diff options
289 files changed, 5754 insertions, 867 deletions
| diff --git a/.gitignore b/.gitignore index 98eb29d657..4d9cbbe4a0 100644 --- a/.gitignore +++ b/.gitignore @@ -133,6 +133,7 @@  /systemd-vconsole-setup  /tags  /test-acd +/test-acl-util  /test-af-list  /test-architecture  /test-arphrd-list @@ -181,6 +182,7 @@  /test-dhcp-server  /test-dhcp6-client  /test-dns-domain +/test-dnssec  /test-efi-disk.img  /test-ellipsize  /test-engine @@ -244,9 +246,11 @@  /test-pty  /test-qcow2  /test-ratelimit +/test-rbtree  /test-replace-var  /test-resolve  /test-ring +/test-rlimit-util  /test-sched-prio  /test-set  /test-sigbus diff --git a/Makefile.am b/Makefile.am index 7880fe57ce..e99c937e61 100644 --- a/Makefile.am +++ b/Makefile.am @@ -147,6 +147,7 @@ tests=  manual_tests =  TEST_EXTENSIONS = .py  PY_LOG_COMPILER = $(PYTHON) +DISABLE_HARD_ERRORS = yes  if ENABLE_TESTS  noinst_PROGRAMS = $(manual_tests) $(tests)  TESTS = $(tests) @@ -744,8 +745,6 @@ CLEANFILES += \  	man/systemd.index.xml \  	man/systemd.directives.xml -EXTRA_DIST += \ -	tools/make-man-rules.py  endif @@ -754,6 +753,7 @@ endif  EXTRA_DIST += \  	$(filter-out man/systemd.directives.xml man/systemd.index.xml,$(XML_FILES)) \  	tools/make-man-index.py \ +	tools/make-man-rules.py \  	tools/make-directive-index.py \  	tools/xml_helper.py \  	man/glib-event-glue.c @@ -766,6 +766,8 @@ libbasic_la_SOURCES = \  	src/basic/missing.h \  	src/basic/capability-util.c \  	src/basic/capability-util.h \ +	src/basic/c-rbtree.c \ +	src/basic/c-rbtree.h \  	src/basic/conf-files.c \  	src/basic/conf-files.h \  	src/basic/stdio-util.h \ @@ -1493,11 +1495,18 @@ tests += \  	test-copy \  	test-cap-list \  	test-sigbus \ +	test-rbtree \  	test-verbs \  	test-af-list \  	test-arphrd-list \  	test-dns-domain \ -	test-install-root +	test-install-root \ +	test-rlimit-util + +if HAVE_ACL +tests += \ +	test-acl-util +endif  EXTRA_DIST += \  	test/a.service \ @@ -1723,6 +1732,12 @@ test_sigbus_SOURCES = \  test_sigbus_LDADD = \  	libshared.la +test_rbtree_SOURCES = \ +	src/test/test-rbtree.c + +test_rbtree_LDADD = \ +	libshared.la +  test_condition_SOURCES = \  	src/test/test-condition.c @@ -1846,9 +1861,21 @@ test_install_root_SOURCES = \  test_install_root_LDADD = \  	libshared.la +test_acl_util_SOURCES = \ +	src/test/test-acl-util.c + +test_acl_util_LDADD = \ +	libshared.la +  test_namespace_LDADD = \  	libcore.la +test_rlimit_util_SOURCES = \ +	src/test/test-rlimit-util.c + +test_rlimit_util_LDADD = \ +	libshared.la +  BUILT_SOURCES += \  	src/test/test-hashmap-ordered.c @@ -4805,9 +4832,6 @@ systemd_timesyncd_SOURCES = \  nodist_systemd_timesyncd_SOURCES = \  	src/timesync/timesyncd-gperf.c -gperf_gperf_sources += \ -	src/timesync/timesyncd-gperf.gperf -  systemd_timesyncd_LDADD = \  	libsystemd-network.la \  	libshared.la @@ -4821,15 +4845,18 @@ nodist_systemunit_DATA += \  GENERAL_ALIASES += \  	$(systemunitdir)/systemd-timesyncd.service $(pkgsysconfdir)/system/sysinit.target.wants/systemd-timesyncd.service -EXTRA_DIST += \ -	units/systemd-timesyncd.service.in  nodist_pkgsysconf_DATA += \  	src/timesync/timesyncd.conf +endif + +gperf_gperf_sources += \ +	src/timesync/timesyncd-gperf.gperf +  EXTRA_DIST += \ +	units/systemd-timesyncd.service.in \  	src/timesync/timesyncd.conf.in -endif  # ------------------------------------------------------------------------------  if HAVE_MYHOSTNAME @@ -5125,12 +5152,13 @@ polkitpolicy_in_files += \  	src/import/org.freedesktop.import1.policy.in  EXTRA_DIST += \ -	units/systemd-importd.service.in \ -	src/resolve/resolved.conf.in +	units/systemd-importd.service.in  # ------------------------------------------------------------------------------  if ENABLE_RESOLVED +if HAVE_GCRYPT +  systemd_resolved_SOURCES = \  	src/resolve/resolved.c \  	src/resolve/resolved-manager.c \ @@ -5145,6 +5173,8 @@ systemd_resolved_SOURCES = \  	src/resolve/resolved-link.c \  	src/resolve/resolved-llmnr.h \  	src/resolve/resolved-llmnr.c \ +	src/resolve/resolved-mdns.h \ +	src/resolve/resolved-mdns.c \  	src/resolve/resolved-def.h \  	src/resolve/resolved-dns-rr.h \  	src/resolve/resolved-dns-rr.c \ @@ -5170,6 +5200,10 @@ systemd_resolved_SOURCES = \  	src/resolve/resolved-dns-zone.c \  	src/resolve/resolved-dns-stream.h \  	src/resolve/resolved-dns-stream.c \ +	src/resolve/resolved-dns-dnssec.h \ +	src/resolve/resolved-dns-dnssec.c \ +	src/resolve/resolved-dns-trust-anchor.h \ +	src/resolve/resolved-dns-trust-anchor.c \  	src/resolve/dns-type.c \  	src/resolve/dns-type.h @@ -5178,12 +5212,6 @@ nodist_systemd_resolved_SOURCES = \  	src/resolve/dns_type-to-name.h \  	src/resolve/resolved-gperf.c -gperf_gperf_sources += \ -	src/resolve/resolved-gperf.gperf - -gperf_txt_sources += \ -	src/resolve/dns_type-list.txt -  systemd_resolved_LDADD = \  	libsystemd-network.la \  	libshared.la @@ -5215,9 +5243,6 @@ GENERAL_ALIASES += \  nodist_pkgsysconf_DATA += \  	src/resolve/resolved.conf -tests += \ -	test-dns-domain -  libnss_resolve_la_SOURCES = \  	src/nss-resolve/nss-resolve.sym \  	src/nss-resolve/nss-resolve.c @@ -5261,10 +5286,40 @@ systemd_resolve_host_LDADD = \  rootlibexec_PROGRAMS += \  	systemd-resolve-host +tests += \ +	test-dns-domain \ +	test-dnssec + +test_dnssec_SOURCES = \ +	src/resolve/test-dnssec.c \ +	src/resolve/resolved-dns-packet.c \ +	src/resolve/resolved-dns-packet.h \ +	src/resolve/resolved-dns-rr.c \ +	src/resolve/resolved-dns-rr.h \ +	src/resolve/resolved-dns-answer.c \ +	src/resolve/resolved-dns-answer.h \ +	src/resolve/resolved-dns-question.c \ +	src/resolve/resolved-dns-question.h \ +	src/resolve/resolved-dns-dnssec.c \ +	src/resolve/resolved-dns-dnssec.h \ +	src/resolve/dns-type.c \ +	src/resolve/dns-type.h + +test_dnssec_LDADD = \ +	libshared.la + +endif  endif +gperf_txt_sources += \ +	src/resolve/dns_type-list.txt + +gperf_gperf_sources += \ +	src/resolve/resolved-gperf.gperf +  EXTRA_DIST += \ -	units/systemd-resolved.service.m4.in +	units/systemd-resolved.service.m4.in \ +	src/resolve/resolved.conf.in  # ------------------------------------------------------------------------------  if ENABLE_NETWORKD @@ -5432,14 +5487,16 @@ SYSTEM_UNIT_ALIASES += \  BUSNAMES_TARGET_WANTS += \  	org.freedesktop.network1.busname +endif +  gperf_gperf_sources += \  	src/network/networkd-network-gperf.gperf \  	src/network/networkd-netdev-gperf.gperf -endif  EXTRA_DIST += \  	units/systemd-networkd.service.m4.in \ -	units/systemd-networkd-wait-online.service.in +	units/systemd-networkd-wait-online.service.in \ +	test/networkd-test.py  # ------------------------------------------------------------------------------  if ENABLE_LOGIND @@ -6173,21 +6230,7 @@ DISTCHECK_CONFIGURE_FLAGS += \  	--disable-split-usr  endif -# -# Require python when making dist -# -.PHONY: dist-check-python dist-check-compat-libs dist-check-help -dist-check-python: -if !HAVE_PYTHON -	@echo "*** python and python-lxml module must be installed and enabled in order to make dist" -	@false -endif - -dist-check-compat-libs: -if !ENABLE_COMPAT_LIBS -	@echo "*** compat-libs must be enabled in order to make dist" -	@false -endif +.PHONY: dist-check-help  dist-check-help: $(rootbin_PROGRAMS) $(bin_PROGRAMS)  	for i in $(abspath $^); do                                             \ @@ -6197,8 +6240,6 @@ dist-check-help: $(rootbin_PROGRAMS) $(bin_PROGRAMS)  	        exit 1;                                                        \              fi; done -dist: dist-check-python dist-check-compat-libs -  .PHONY: hwdb-update  hwdb-update:  	( cd $(top_srcdir)/hwdb && \ diff --git a/src/basic/af-list.c b/src/basic/af-list.c index 07dfff6ad4..606bb49a59 100644 --- a/src/basic/af-list.c +++ b/src/basic/af-list.c @@ -23,7 +23,7 @@  #include <sys/socket.h>  #include "af-list.h" -#include "util.h" +#include "macro.h"  static const struct af_name* lookup_af(register const char *str, register unsigned int len); diff --git a/src/basic/alloc-util.c b/src/basic/alloc-util.c index 48183e381f..0c6a15c958 100644 --- a/src/basic/alloc-util.c +++ b/src/basic/alloc-util.c @@ -19,7 +19,11 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdint.h> +#include <string.h> +  #include "alloc-util.h" +#include "macro.h"  #include "util.h"  void* memdup(const void *p, size_t l) { diff --git a/src/basic/alloc-util.h b/src/basic/alloc-util.h index 12b602e185..f5097ea117 100644 --- a/src/basic/alloc-util.h +++ b/src/basic/alloc-util.h @@ -22,6 +22,7 @@  ***/  #include <alloca.h> +#include <stddef.h>  #include <stdlib.h>  #include <string.h> diff --git a/src/basic/arphrd-list.c b/src/basic/arphrd-list.c index 03d8ad7403..c1fdbbd905 100644 --- a/src/basic/arphrd-list.c +++ b/src/basic/arphrd-list.c @@ -23,7 +23,7 @@  #include <string.h>  #include "arphrd-list.h" -#include "util.h" +#include "macro.h"  static const struct arphrd_name* lookup_arphrd(register const char *str, register unsigned int len); diff --git a/src/basic/async.c b/src/basic/async.c index cfc5d224e1..42c66a762e 100644 --- a/src/basic/async.c +++ b/src/basic/async.c @@ -19,12 +19,15 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <pthread.h> +#include <stddef.h>  #include <unistd.h>  #include "async.h"  #include "fd-util.h"  #include "log.h" +#include "macro.h"  #include "util.h"  int asynchronous_job(void* (*func)(void *p), void *arg) { diff --git a/src/basic/audit-util.c b/src/basic/audit-util.c index 4612297334..e52ee24c05 100644 --- a/src/basic/audit-util.c +++ b/src/basic/audit-util.c @@ -20,7 +20,9 @@  ***/  #include <errno.h> +#include <linux/netlink.h>  #include <stdio.h> +#include <sys/socket.h>  #include "alloc-util.h"  #include "audit-util.h" @@ -30,7 +32,6 @@  #include "parse-util.h"  #include "process-util.h"  #include "user-util.h" -#include "util.h"  int audit_session_from_pid(pid_t pid, uint32_t *id) {          _cleanup_free_ char *s = NULL; diff --git a/src/basic/barrier.c b/src/basic/barrier.c index 2d55bab4ab..9a78a80eb2 100644 --- a/src/basic/barrier.c +++ b/src/basic/barrier.c @@ -32,7 +32,6 @@  #include "barrier.h"  #include "fd-util.h"  #include "macro.h" -#include "util.h"  /**   * Barriers diff --git a/src/basic/barrier.h b/src/basic/barrier.h index b8954694d3..722effe834 100644 --- a/src/basic/barrier.h +++ b/src/basic/barrier.h @@ -21,6 +21,8 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> +#include <stdint.h>  #include <sys/types.h>  #include "macro.h" diff --git a/src/basic/bitmap.c b/src/basic/bitmap.c index 1449e2ea85..95f59e400a 100644 --- a/src/basic/bitmap.c +++ b/src/basic/bitmap.c @@ -19,9 +19,16 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +  #include "alloc-util.h"  #include "bitmap.h" -#include "util.h" +#include "hashmap.h" +#include "macro.h"  struct Bitmap {          uint64_t *bitmaps; diff --git a/src/basic/bitmap.h b/src/basic/bitmap.h index 9ce7b42d00..d2726630f1 100644 --- a/src/basic/bitmap.h +++ b/src/basic/bitmap.h @@ -21,6 +21,8 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> +  #include "hashmap.h"  #include "macro.h" diff --git a/src/basic/btrfs-util.c b/src/basic/btrfs-util.c index be40dc5702..acd48f6954 100644 --- a/src/basic/btrfs-util.c +++ b/src/basic/btrfs-util.c @@ -19,9 +19,20 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <linux/loop.h> +#include <stddef.h> +#include <stdio.h>  #include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h>  #include <sys/stat.h> -#include <sys/vfs.h> +#include <sys/statfs.h> +#include <sys/sysmacros.h> +#include <unistd.h> +  #ifdef HAVE_LINUX_BTRFS_H  #include <linux/btrfs.h>  #endif @@ -37,8 +48,10 @@  #include "path-util.h"  #include "selinux-util.h"  #include "smack-util.h" +#include "sparse-endian.h"  #include "stat-util.h"  #include "string-util.h" +#include "time-util.h"  #include "util.h"  /* WARNING: Be careful with file system ioctls! When we get an fd, we diff --git a/src/basic/btrfs-util.h b/src/basic/btrfs-util.h index 8c11ce35d2..31b9c02785 100644 --- a/src/basic/btrfs-util.h +++ b/src/basic/btrfs-util.h @@ -22,8 +22,11 @@  #pragma once  #include <stdbool.h> +#include <stdint.h>  #include <sys/types.h> +#include "sd-id128.h" +  #include "time-util.h"  typedef struct BtrfsSubvolInfo { diff --git a/src/basic/bus-label.c b/src/basic/bus-label.c index c1534657ac..d8d5863b03 100644 --- a/src/basic/bus-label.c +++ b/src/basic/bus-label.c @@ -25,7 +25,6 @@  #include "bus-label.h"  #include "hexdecoct.h"  #include "macro.h" -#include "util.h"  char *bus_label_escape(const char *s) {          char *r, *t; diff --git a/src/basic/bus-label.h b/src/basic/bus-label.h index ed1dc4e0a7..f51153ce6d 100644 --- a/src/basic/bus-label.h +++ b/src/basic/bus-label.h @@ -21,6 +21,7 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stddef.h>  #include <stdlib.h>  #include <string.h> diff --git a/src/basic/c-rbtree.c b/src/basic/c-rbtree.c new file mode 100644 index 0000000000..914d7e5229 --- /dev/null +++ b/src/basic/c-rbtree.c @@ -0,0 +1,679 @@ +/*** +  This file is part of systemd. See COPYING for details. + +  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/>. +***/ + +/* + * RB-Tree Implementation + * This implements the insertion/removal of elements in RB-Trees. You're highly + * recommended to have an RB-Tree documentation at hand when reading this. Both + * insertion and removal can be split into a handful of situations that can + * occur. Those situations are enumerated as "Case 1" to "Case n" here, and + * follow closely the cases described in most RB-Tree documentations. This file + * does not explain why it is enough to handle just those cases, nor does it + * provide a proof of correctness. Dig out your algorithm 101 handbook if + * you're interested. + * + * This implementation is *not* straightforward. Usually, a handful of + * rotation, reparent, swap and link helpers can be used to implement the + * rebalance operations. However, those often perform unnecessary writes. + * Therefore, this implementation hard-codes all the operations. You're highly + * recommended to look at the two basic helpers before reading the code: + *     c_rbtree_swap_child() + *     c_rbtree_set_parent_and_color() + * Those are the only helpers used, hence, you should really know what they do + * before digging into the code. + * + * For a highlevel documentation of the API, see the header file and docbook + * comments. + */ + +#include <assert.h> +#include <stddef.h> +#include "c-rbtree.h" + +enum { +        C_RBNODE_RED   = 0, +        C_RBNODE_BLACK = 1, +}; + +static inline unsigned long c_rbnode_color(CRBNode *n) { +        return (unsigned long)n->__parent_and_color & 1UL; +} + +static inline _Bool c_rbnode_is_red(CRBNode *n) { +        return c_rbnode_color(n) == C_RBNODE_RED; +} + +static inline _Bool c_rbnode_is_black(CRBNode *n) { +        return c_rbnode_color(n) == C_RBNODE_BLACK; +} + +/** + * c_rbnode_leftmost() - return leftmost child + * @n:          current node, or NULL + * + * This returns the leftmost child of @n. If @n is NULL, this will return NULL. + * In all other cases, this function returns a valid pointer. That is, if @n + * does not have any left children, this returns @n. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to leftmost child, or NULL. + */ +CRBNode *c_rbnode_leftmost(CRBNode *n) { +        if (n) +                while (n->left) +                        n = n->left; +        return n; +} + +/** + * c_rbnode_rightmost() - return rightmost child + * @n:          current node, or NULL + * + * This returns the rightmost child of @n. If @n is NULL, this will return + * NULL. In all other cases, this function returns a valid pointer. That is, if + * @n does not have any right children, this returns @n. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to rightmost child, or NULL. + */ +CRBNode *c_rbnode_rightmost(CRBNode *n) { +        if (n) +                while (n->right) +                        n = n->right; +        return n; +} + +/** + * c_rbnode_next() - return next node + * @n:          current node, or NULL + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically next node to @n. If @n is NULL, the last node or + * unlinked, this returns NULL. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to next node, or NULL. + */ +CRBNode *c_rbnode_next(CRBNode *n) { +        CRBNode *p; + +        if (!c_rbnode_is_linked(n)) +                return NULL; +        if (n->right) +                return c_rbnode_leftmost(n->right); + +        while ((p = c_rbnode_parent(n)) && n == p->right) +                n = p; + +        return p; +} + +/** + * c_rbnode_prev() - return previous node + * @n:          current node, or NULL + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically previous node to @n. If @n is NULL, the first node or + * unlinked, this returns NULL. + * + * Worst case runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to previous node, or NULL. + */ +CRBNode *c_rbnode_prev(CRBNode *n) { +        CRBNode *p; + +        if (!c_rbnode_is_linked(n)) +                return NULL; +        if (n->left) +                return c_rbnode_rightmost(n->left); + +        while ((p = c_rbnode_parent(n)) && n == p->left) +                n = p; + +        return p; +} + +/** + * c_rbtree_first() - return first node + * @t:          tree to operate on + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically first node in @t. If @t is empty, NULL is returned. + * + * Fixed runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to first node, or NULL. + */ +CRBNode *c_rbtree_first(CRBTree *t) { +        assert(t); +        return c_rbnode_leftmost(t->root); +} + +/** + * c_rbtree_last() - return last node + * @t:          tree to operate on + * + * An RB-Tree always defines a linear order of its elements. This function + * returns the logically last node in @t. If @t is empty, NULL is returned. + * + * Fixed runtime (n: number of elements in tree): O(log(n)) + * + * Return: Pointer to last node, or NULL. + */ +CRBNode *c_rbtree_last(CRBTree *t) { +        assert(t); +        return c_rbnode_rightmost(t->root); +} + +/* + * Set the color and parent of a node. This should be treated as a simple + * assignment of the 'color' and 'parent' fields of the node. No other magic is + * applied. But since both fields share its backing memory, this helper + * function is provided. + */ +static inline void c_rbnode_set_parent_and_color(CRBNode *n, CRBNode *p, unsigned long c) { +        assert(!((unsigned long)p & 1)); +        assert(c < 2); +        n->__parent_and_color = (CRBNode*)((unsigned long)p | c); +} + +/* same as c_rbnode_set_parent_and_color(), but keeps the current parent */ +static inline void c_rbnode_set_color(CRBNode *n, unsigned long c) { +        c_rbnode_set_parent_and_color(n, c_rbnode_parent(n), c); +} + +/* same as c_rbnode_set_parent_and_color(), but keeps the current color */ +static inline void c_rbnode_set_parent(CRBNode *n, CRBNode *p) { +        c_rbnode_set_parent_and_color(n, p, c_rbnode_color(n)); +} + +/* + * This function partially replaces an existing child pointer to a new one. The + * existing child must be given as @old, the new child as @new. @p must be the + * parent of @old (or NULL if it has no parent). + * This function ensures that the parent of @old now points to @new. However, + * it does *NOT* change the parent pointer of @new. The caller must ensure + * this. + * If @p is NULL, this function ensures that the root-pointer is adjusted + * instead (given as @t). + */ +static inline void c_rbtree_swap_child(CRBTree *t, CRBNode *p, CRBNode *old, CRBNode *new) { +        if (p) { +                if (p->left == old) +                        p->left = new; +                else +                        p->right = new; +        } else { +                t->root = new; +        } +} + +static inline CRBNode *c_rbtree_paint_one(CRBTree *t, CRBNode *n) { +        CRBNode *p, *g, *gg, *u, *x; + +        /* +         * Paint a single node according to RB-Tree rules. The node must +         * already be linked into the tree and painted red. +         * We repaint the node or rotate the tree, if required. In case a +         * recursive repaint is required, the next node to be re-painted +         * is returned. +         *      p: parent +         *      g: grandparent +         *      gg: grandgrandparent +         *      u: uncle +         *      x: temporary +         */ + +        /* node is red, so we can access the parent directly */ +        p = n->__parent_and_color; + +        if (!p) { +                /* Case 1: +                 * We reached the root. Mark it black and be done. As all +                 * leaf-paths share the root, the ratio of black nodes on each +                 * path stays the same. */ +                c_rbnode_set_parent_and_color(n, p, C_RBNODE_BLACK); +                n = NULL; +        } else if (c_rbnode_is_black(p)) { +                /* Case 2: +                 * The parent is already black. As our node is red, we did not +                 * change the number of black nodes on any path, nor do we have +                 * multiple consecutive red nodes. */ +                n = NULL; +        } else if (p == p->__parent_and_color->left) { /* parent is red, so grandparent exists */ +                g = p->__parent_and_color; +                gg = c_rbnode_parent(g); +                u = g->right; + +                if (u && c_rbnode_is_red(u)) { +                        /* Case 3: +                         * Parent and uncle are both red. We know the +                         * grandparent must be black then. Repaint parent and +                         * uncle black, the grandparent red and recurse into +                         * the grandparent. */ +                        c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED); +                        n = g; +                } else { +                        /* parent is red, uncle is black */ + +                        if (n == p->right) { +                                /* Case 4: +                                 * We're the right child. Rotate on parent to +                                 * become left child, so we can handle it the +                                 * same as case 5. */ +                                x = n->left; +                                p->right = n->left; +                                n->left = p; +                                if (x) +                                        c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); +                                c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED); +                                p = n; +                        } + +                        /* 'n' is invalid from here on! */ +                        n = NULL; + +                        /* Case 5: +                         * We're the red left child or a red parent, black +                         * grandparent and uncle. Rotate on grandparent and +                         * switch color with parent. Number of black nodes on +                         * each path stays the same, but we got rid of the +                         * double red path. As the grandparent is still black, +                         * we're done. */ +                        x = p->right; +                        g->left = x; +                        p->right = g; +                        if (x) +                                c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED); +                        c_rbtree_swap_child(t, gg, g, p); +                } +        } else /* if (p == p->__parent_and_color->left) */ { /* same as above, but mirrored */ +                g = p->__parent_and_color; +                gg = c_rbnode_parent(g); +                u = g->left; + +                if (u && c_rbnode_is_red(u)) { +                        c_rbnode_set_parent_and_color(p, g, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(u, g, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(g, gg, C_RBNODE_RED); +                        n = g; +                } else { +                        if (n == p->left) { +                                x = n->right; +                                p->left = n->right; +                                n->right = p; +                                if (x) +                                        c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); +                                c_rbnode_set_parent_and_color(p, n, C_RBNODE_RED); +                                p = n; +                        } + +                        n = NULL; + +                        x = p->left; +                        g->right = x; +                        p->left = g; +                        if (x) +                                c_rbnode_set_parent_and_color(x, g, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(p, gg, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(g, p, C_RBNODE_RED); +                        c_rbtree_swap_child(t, gg, g, p); +                } +        } + +        return n; +} + +static inline void c_rbtree_paint(CRBTree *t, CRBNode *n) { +        assert(t); +        assert(n); + +        while (n) +                n = c_rbtree_paint_one(t, n); +} + +/** + * c_rbtree_add() - add node to tree + * @t:          tree to operate one + * @p:          parent node to link under, or NULL + * @l:          left/right slot of @p (or root) to link at + * @n:          node to add + * + * This links @n into the tree given as @t. The caller must provide the exact + * spot where to link the node. That is, the caller must traverse the tree + * based on their search order. Once they hit a leaf where to insert the node, + * call this function to link it and rebalance the tree. + * + * A typical insertion would look like this (@t is your tree, @n is your node): + * + *        CRBNode **i, *p; + * + *        i = &t->root; + *        p = NULL; + *        while (*i) { + *                p = *i; + *                if (compare(n, *i) < 0) + *                        i = &(*i)->left; + *                else + *                        i = &(*i)->right; + *        } + * + *        c_rbtree_add(t, p, i, n); + * + * Once the node is linked into the tree, a simple lookup on the same tree can + * be coded like this: + * + *        CRBNode *i; + * + *        i = t->root; + *        while (i) { + *                int v = compare(n, i); + *                if (v < 0) + *                        i = (*i)->left; + *                else if (v > 0) + *                        i = (*i)->right; + *                else + *                        break; + *        } + * + * When you add nodes to a tree, the memory contents of the node do not matter. + * That is, there is no need to initialize the node via c_rbnode_init(). + * However, if you relink nodes multiple times during their lifetime, it is + * usually very convenient to use c_rbnode_init() and c_rbtree_remove_init(). + * In those cases, you should validate that a node is unlinked before you call + * c_rbtree_add(). + */ +void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n) { +        assert(t); +        assert(l); +        assert(n); +        assert(!p || l == &p->left || l == &p->right); +        assert(p || l == &t->root); + +        c_rbnode_set_parent_and_color(n, p, C_RBNODE_RED); +        n->left = n->right = NULL; +        *l = n; + +        c_rbtree_paint(t, n); +} + +static inline CRBNode *c_rbtree_rebalance_one(CRBTree *t, CRBNode *p, CRBNode *n) { +        CRBNode *s, *x, *y, *g; + +        /* +         * Rebalance tree after a node was removed. This happens only if you +         * remove a black node and one path is now left with an unbalanced +         * number or black nodes. +         * This function assumes all paths through p and n have one black node +         * less than all other paths. If recursive fixup is required, the +         * current node is returned. +         */ + +        if (n == p->left) { +                s = p->right; +                if (c_rbnode_is_red(s)) { +                        /* Case 3: +                         * We have a red node as sibling. Rotate it onto our +                         * side so we can later on turn it black. This way, we +                         * gain the additional black node in our path. */ +                        g = c_rbnode_parent(p); +                        x = s->left; +                        p->right = x; +                        s->left = p; +                        c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); +                        c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED); +                        c_rbtree_swap_child(t, g, p, s); +                        s = x; +                } + +                x = s->right; +                if (!x || c_rbnode_is_black(x)) { +                        y = s->left; +                        if (!y || c_rbnode_is_black(y)) { +                                /* Case 4: +                                 * Our sibling is black and has only black +                                 * children. Flip it red and turn parent black. +                                 * This way we gained a black node in our path, +                                 * or we fix it recursively one layer up, which +                                 * will rotate the red sibling as parent. */ +                                c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED); +                                if (c_rbnode_is_black(p)) +                                        return p; + +                                c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK); +                                return NULL; +                        } + +                        /* Case 5: +                         * Left child of our sibling is red, right one is black. +                         * Rotate on parent so the right child of our sibling is +                         * now red, and we can fall through to case 6. */ +                        x = y->right; +                        s->left = y->right; +                        y->right = s; +                        p->right = y; +                        if (x) +                                c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); +                        x = s; +                        s = y; +                } + +                /* Case 6: +                 * The right child of our sibling is red. Rotate left and flip +                 * colors, which gains us an additional black node in our path, +                 * that was previously on our sibling. */ +                g = c_rbnode_parent(p); +                y = s->left; +                p->right = y; +                s->left = p; +                c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); +                if (y) +                        c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y)); +                c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); +                c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK); +                c_rbtree_swap_child(t, g, p, s); +        } else /* if (!n || n == p->right) */ { /* same as above, but mirrored */ +                s = p->left; +                if (c_rbnode_is_red(s)) { +                        g = c_rbnode_parent(p); +                        x = s->right; +                        p->left = x; +                        s->right = p; +                        c_rbnode_set_parent_and_color(x, p, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(s, g, C_RBNODE_BLACK); +                        c_rbnode_set_parent_and_color(p, s, C_RBNODE_RED); +                        c_rbtree_swap_child(t, g, p, s); +                        s = x; +                } + +                x = s->left; +                if (!x || c_rbnode_is_black(x)) { +                        y = s->right; +                        if (!y || c_rbnode_is_black(y)) { +                                c_rbnode_set_parent_and_color(s, p, C_RBNODE_RED); +                                if (c_rbnode_is_black(p)) +                                        return p; + +                                c_rbnode_set_parent_and_color(p, c_rbnode_parent(p), C_RBNODE_BLACK); +                                return NULL; +                        } + +                        x = y->left; +                        s->right = y->left; +                        y->left = s; +                        p->left = y; +                        if (x) +                                c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); +                        x = s; +                        s = y; +                } + +                g = c_rbnode_parent(p); +                y = s->right; +                p->left = y; +                s->right = p; +                c_rbnode_set_parent_and_color(x, s, C_RBNODE_BLACK); +                if (y) +                        c_rbnode_set_parent_and_color(y, p, c_rbnode_color(y)); +                c_rbnode_set_parent_and_color(s, g, c_rbnode_color(p)); +                c_rbnode_set_parent_and_color(p, s, C_RBNODE_BLACK); +                c_rbtree_swap_child(t, g, p, s); +        } + +        return NULL; +} + +static inline void c_rbtree_rebalance(CRBTree *t, CRBNode *p) { +        CRBNode *n = NULL; + +        assert(t); +        assert(p); + +        do { +                n = c_rbtree_rebalance_one(t, p, n); +                p = n ? c_rbnode_parent(n) : NULL; +        } while (p); +} + +/** + * c_rbtree_remove() - remove node from tree + * @t:          tree to operate one + * @n:          node to remove + * + * This removes the given node from its tree. Once unlinked, the tree is + * rebalanced. + * The caller *must* ensure that the given tree is actually the tree it is + * linked on. Otherwise, behavior is undefined. + * + * This does *NOT* reset @n to being unlinked (for performance reason, this + * function *never* modifies @n at all). If you need this, use + * c_rbtree_remove_init(). + */ +void c_rbtree_remove(CRBTree *t, CRBNode *n) { +        CRBNode *p, *s, *gc, *x, *next = NULL; +        unsigned long c; + +        assert(t); +        assert(n); +        assert(c_rbnode_is_linked(n)); + +        /* +         * There are three distinct cases during node removal of a tree: +         *  * The node has no children, in which case it can simply be removed. +         *  * The node has exactly one child, in which case the child displaces +         *    its parent. +         *  * The node has two children, in which case there is guaranteed to +         *    be a successor to the node (successor being the node ordered +         *    directly after it). This successor cannot have two children by +         *    itself (two interior nodes can never be successive). Therefore, +         *    we can simply swap the node with its successor (including color) +         *    and have reduced this case to either of the first two. +         * +         * Whenever the node we removed was black, we have to rebalance the +         * tree. Note that this affects the actual node we _remove_, not @n (in +         * case we swap it). +         * +         *      p: parent +         *      s: successor +         *      gc: grand-...-child +         *      x: temporary +         *      next: next node to rebalance on +         */ + +        if (!n->left) { +                /* +                 * Case 1: +                 * The node has no left child. If it neither has a right child, +                 * it is a leaf-node and we can simply unlink it. If it also +                 * was black, we have to rebalance, as always if we remove a +                 * black node. +                 * But if the node has a right child, the child *must* be red +                 * (otherwise, the right path has more black nodes as the +                 * non-existing left path), and the node to be removed must +                 * hence be black. We simply replace the node with its child, +                 * turning the red child black, and thus no rebalancing is +                 * required. +                 */ +                p = c_rbnode_parent(n); +                c = c_rbnode_color(n); +                c_rbtree_swap_child(t, p, n, n->right); +                if (n->right) +                        c_rbnode_set_parent_and_color(n->right, p, c); +                else +                        next = (c == C_RBNODE_BLACK) ? p : NULL; +        } else if (!n->right) { +                /* +                 * Case 1.1: +                 * The node has exactly one child, and it is on the left. Treat +                 * it as mirrored case of Case 1 (i.e., replace the node by its +                 * child). +                 */ +                p = c_rbnode_parent(n); +                c = c_rbnode_color(n); +                c_rbtree_swap_child(t, p, n, n->left); +                c_rbnode_set_parent_and_color(n->left, p, c); +        } else { +                /* +                 * Case 2: +                 * We are dealing with a full interior node with a child not on +                 * both sides. Find its successor and swap it. Then remove the +                 * node similar to Case 1. For performance reasons we don't +                 * perform the full swap, but skip links that are about to be +                 * removed, anyway. +                 */ +                s = n->right; +                if (!s->left) { +                        /* right child is next, no need to touch grandchild */ +                        p = s; +                        gc = s->right; +                } else { +                        /* find successor and swap partially */ +                        s = c_rbnode_leftmost(s); +                        p = c_rbnode_parent(s); + +                        gc = s->right; +                        p->left = s->right; +                        s->right = n->right; +                        c_rbnode_set_parent(n->right, s); +                } + +                /* node is partially swapped, now remove as in Case 1 */ +                s->left = n->left; +                c_rbnode_set_parent(n->left, s); + +                x = c_rbnode_parent(n); +                c = c_rbnode_color(n); +                c_rbtree_swap_child(t, x, n, s); +                if (gc) +                        c_rbnode_set_parent_and_color(gc, p, C_RBNODE_BLACK); +                else +                        next = c_rbnode_is_black(s) ? p : NULL; +                c_rbnode_set_parent_and_color(s, x, c); +        } + +        if (next) +                c_rbtree_rebalance(t, next); +} diff --git a/src/basic/c-rbtree.h b/src/basic/c-rbtree.h new file mode 100644 index 0000000000..20c5515ca1 --- /dev/null +++ b/src/basic/c-rbtree.h @@ -0,0 +1,297 @@ +#pragma once + +/*** +  This file is part of systemd. See COPYING for details. + +  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/>. +***/ + +/* + * Standalone Red-Black-Tree Implementation in Standard ISO-C11 + * + * This header provides an RB-Tree API, that is fully implemented in ISO-C11 + * and has no external dependencies. Furthermore, tree traversal, memory + * allocations, and key comparisons a fully in control of the API user. The + * implementation only provides the RB-Tree specific rebalancing and coloring. + * + * A tree is represented by the "CRBTree" structure. It contains a *singly* + * field, which is a pointer to the root node. If NULL, the tree is empty. If + * non-NULL, there is at least a single element in the tree. + * + * Each node of the tree is represented by the "CRBNode" structure. It has + * three fields. The @left and @right members can be accessed by the API user + * directly to traverse the tree. The third member is an implementation detail + * and encodes the parent pointer and color of the node. + * API users are required to embed the CRBNode object into their own objects + * and then use offsetof() (i.e., container_of() and friends) to turn CRBNode + * pointers into pointers to their own structure. + */ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct CRBNode CRBNode; +typedef struct CRBTree CRBTree; + +/** + * struct CRBNode - Node of a Red-Black Tree + * @__parent_and_color:         internal state + * @left:                       left child, or NULL + * @right:                      right child, or NULL + * + * Each node in an RB-Tree must embed an CRBNode object. This object contains + * pointers to its left and right child, which can be freely accessed by the + * API user at any time. They are NULL, if the node does not have a left/right + * child. + * + * The @__parent_and_color field must never be accessed directly. It encodes + * the pointer to the parent node, and the color of the node. Use the accessor + * functions instead. + * + * There is no reason to initialize a CRBNode object before linking it. + * However, if you need a boolean state that tells you whether the node is + * linked or not, you should initialize the node via c_rbnode_init() or + * C_RBNODE_INIT. + */ +struct CRBNode { +        CRBNode *__parent_and_color; +        CRBNode *left; +        CRBNode *right; +}; + +#define C_RBNODE_INIT(_var) { .__parent_and_color = &(_var) } + +CRBNode *c_rbnode_leftmost(CRBNode *n); +CRBNode *c_rbnode_rightmost(CRBNode *n); +CRBNode *c_rbnode_next(CRBNode *n); +CRBNode *c_rbnode_prev(CRBNode *n); + +/** + * struct CRBTree - Red-Black Tree + * @root:       pointer to the root node, or NULL + * + * Each Red-Black Tree is rooted in an CRBTree object. This object contains a + * pointer to the root node of the tree. The API user is free to access the + * @root member at any time, and use it to traverse the tree. + * + * To initialize an RB-Tree, set it to NULL / all zero. + */ +struct CRBTree { +        CRBNode *root; +}; + +CRBNode *c_rbtree_first(CRBTree *t); +CRBNode *c_rbtree_last(CRBTree *t); + +void c_rbtree_add(CRBTree *t, CRBNode *p, CRBNode **l, CRBNode *n); +void c_rbtree_remove(CRBTree *t, CRBNode *n); + +/** + * c_rbnode_init() - mark a node as unlinked + * @n:          node to operate on + * + * This marks the node @n as unlinked. The node will be set to a valid state + * that can never happen if the node is linked in a tree. Furthermore, this + * state is fully known to the implementation, and as such handled gracefully + * in all cases. + * + * You are *NOT* required to call this on your node. c_rbtree_add() can handle + * uninitialized nodes just fine. However, calling this allows to use + * c_rbnode_is_linked() to check for the state of a node. Furthermore, + * iterators and accessors can be called on initialized (yet unlinked) nodes. + * + * Use the C_RBNODE_INIT macro if you want to initialize static variables. + */ +static inline void c_rbnode_init(CRBNode *n) { +        *n = (CRBNode)C_RBNODE_INIT(*n); +} + +/** + * c_rbnode_is_linked() - check whether a node is linked + * @n:          node to check, or NULL + * + * This checks whether the passed node is linked. If you pass NULL, or if the + * node is not linked into a tree, this will return false. Otherwise, this + * returns true. + * + * Note that you must have either linked the node or initialized it, before + * calling this function. Never call this function on uninitialized nodes. + * Furthermore, removing a node via c_rbtree_remove() does *NOT* mark the node + * as unlinked. You have to call c_rbnode_init() yourself after removal, or use + * the c_rbtree_remove_init() helper. + * + * Return: true if the node is linked, false if not. + */ +static inline _Bool c_rbnode_is_linked(CRBNode *n) { +        return n && n->__parent_and_color != n; +} + +/** + * c_rbnode_parent() - return parent pointer + * @n           node to access + * + * This returns a pointer to the parent of the given node @n. If @n does not + * have a parent, NULL is returned. If @n is not linked, @n itself is returned. + * + * You should not call this on unlinked or uninitialized nodes! If you do, you + * better know how its semantics. + * + * Return: Pointer to parent. + */ +static inline CRBNode *c_rbnode_parent(CRBNode *n) { +        return (CRBNode*)((unsigned long)n->__parent_and_color & ~1UL); +} + +/** + * c_rbtree_remove_init() - safely remove node from tree and reinitialize it + * @t:          tree to operate on + * @n:          node to remove, or NULL + * + * This is almost the same as c_rbtree_remove(), but extends it slightly, to be + * more convenient to use in many cases: + *  - if @n is unlinked or NULL, this is a no-op + *  - @n is reinitialized after being removed + */ +static inline void c_rbtree_remove_init(CRBTree *t, CRBNode *n) { +        if (c_rbnode_is_linked(n)) { +                c_rbtree_remove(t, n); +                c_rbnode_init(n); +        } +} + +/** + * CRBCompareFunc - compare a node to a key + * @t:          tree where the node is linked to + * @k:          key to compare + * @n:          node to compare + * + * If you use the tree-traversal helpers (which are optional), you need to + * provide this callback so they can compare nodes in a tree to the key you + * look for. + * + * The tree @t is provided as optional context to this callback. The key you + * look for is provided as @k, the current node that should be compared to is + * provided as @n. This function should work like strcmp(), that is, return -1 + * if @key orders before @n, 0 if both compare equal, and 1 if it orders after + * @n. + */ +typedef int (*CRBCompareFunc) (CRBTree *t, void *k, CRBNode *n); + +/** + * c_rbtree_find_node() - find node + * @t:          tree to search through + * @f:          comparison function + * @k:          key to search for + * + * This searches through @t for a node that compares equal to @k. The function + * @f must be provided by the caller, which is used to compare nodes to @k. See + * the documentation of CRBCompareFunc for details. + * + * If there are multiple entries that compare equal to @k, this will return a + * pseudo-randomly picked node. If you need stable lookup functions for trees + * where duplicate entries are allowed, you better code your own lookup. + * + * Return: Pointer to matching node, or NULL. + */ +static inline CRBNode *c_rbtree_find_node(CRBTree *t, CRBCompareFunc f, const void *k) { +        CRBNode *i; + +        assert(t); +        assert(f); + +        i = t->root; +        while (i) { +                int v = f(t, (void *)k, i); +                if (v < 0) +                        i = i->left; +                else if (v > 0) +                        i = i->right; +                else +                        return i; +        } + +        return NULL; +} + +/** + * c_rbtree_find_entry() - find entry + * @_t:         tree to search through + * @_f:         comparison function + * @_k:         key to search for + * @_t:         type of the structure that embeds the nodes + * @_o:         name of the node-member in type @_t + * + * This is very similar to c_rbtree_find_node(), but instead of returning a + * pointer to the CRBNode, it returns a pointer to the surrounding object. This + * object must embed the CRBNode object. The type of the surrounding object + * must be given as @_t, and the name of the embedded CRBNode member as @_o. + * + * See c_rbtree_find_node() for more details. + * + * Return: Pointer to found entry, NULL if not found. + */ +#define c_rbtree_find_entry(_m, _f, _k, _t, _o) \ +        ((_t *)(((char *)c_rbtree_find_node((_m), (_f), (_k)) ?: \ +                (char *)NULL + offsetof(_t, _o)) - offsetof(_t, _o))) + +/** + * c_rbtree_find_slot() - find slot to insert new node + * @t:          tree to search through + * @f:          comparison function + * @k:          key to search for + * @p:          output storage for parent pointer + * + * This searches through @t just like c_rbtree_find_node() does. However, + * instead of returning a pointer to a node that compares equal to @k, this + * searches for a slot to insert a node with key @k. A pointer to the slot is + * returned, and a pointer to the parent of the slot is stored in @p. Both + * can be passed directly to c_rbtree_add(), together with your node to insert. + * + * If there already is a node in the tree, that compares equal to @k, this will + * return NULL and store the conflicting node in @p. In all other cases, + * this will return a pointer (non-NULL) to the empty slot to insert the node + * at. @p will point to the parent node of that slot. + * + * If you want trees that allow duplicate nodes, you better code your own + * insertion function. + * + * Return: Pointer to slot to insert node, or NULL on conflicts. + */ +static inline CRBNode **c_rbtree_find_slot(CRBTree *t, CRBCompareFunc f, const void *k, CRBNode **p) { +        CRBNode **i; + +        assert(t); +        assert(f); +        assert(p); + +        i = &t->root; +        *p = NULL; +        while (*i) { +                int v = f(t, (void *)k, *i); +                *p = *i; +                if (v < 0) +                        i = &(*i)->left; +                else if (v > 0) +                        i = &(*i)->right; +                else +                        return NULL; +        } + +        return i; +} + +#ifdef __cplusplus +} +#endif diff --git a/src/basic/calendarspec.c b/src/basic/calendarspec.c index 8f60561ede..8f83d9c142 100644 --- a/src/basic/calendarspec.c +++ b/src/basic/calendarspec.c @@ -19,12 +19,18 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <alloca.h> +#include <errno.h> +#include <stddef.h> +#include <stdio.h>  #include <stdlib.h>  #include <string.h> +#include <time.h>  #include "alloc-util.h"  #include "calendarspec.h"  #include "fileio.h" +#include "macro.h"  #include "parse-util.h"  #include "string-util.h" diff --git a/src/basic/calendarspec.h b/src/basic/calendarspec.h index 75b699682a..4e3aa9e1d8 100644 --- a/src/basic/calendarspec.h +++ b/src/basic/calendarspec.h @@ -26,6 +26,7 @@  #include <stdbool.h> +#include "time-util.h"  #include "util.h"  typedef struct CalendarComponent { diff --git a/src/basic/cap-list.c b/src/basic/cap-list.c index f0974900cd..0e5cc452b9 100644 --- a/src/basic/cap-list.c +++ b/src/basic/cap-list.c @@ -19,9 +19,11 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <string.h>  #include "cap-list.h" +#include "macro.h"  #include "missing.h"  #include "parse-util.h"  #include "util.h" diff --git a/src/basic/capability-util.c b/src/basic/capability-util.c index 0eb5c03d65..fef722b6f2 100644 --- a/src/basic/capability-util.c +++ b/src/basic/capability-util.c @@ -22,6 +22,7 @@  #include <errno.h>  #include <grp.h>  #include <stdio.h> +#include <stdlib.h>  #include <sys/capability.h>  #include <sys/prctl.h>  #include <unistd.h> diff --git a/src/basic/capability-util.h b/src/basic/capability-util.h index 4eb5c2a835..6bbf7318fd 100644 --- a/src/basic/capability-util.h +++ b/src/basic/capability-util.h @@ -22,8 +22,11 @@  ***/  #include <stdbool.h> +#include <stdint.h>  #include <sys/capability.h> +#include <sys/types.h> +#include "macro.h"  #include "util.h"  unsigned long cap_last_cap(void); diff --git a/src/basic/cgroup-util.c b/src/basic/cgroup-util.c index f7fc2c2c97..639f9f3db1 100644 --- a/src/basic/cgroup-util.c +++ b/src/basic/cgroup-util.c @@ -22,23 +22,29 @@  #include <dirent.h>  #include <errno.h>  #include <ftw.h> +#include <limits.h>  #include <signal.h> +#include <stddef.h>  #include <stdlib.h>  #include <string.h>  #include <sys/stat.h> +#include <sys/statfs.h>  #include <sys/types.h>  #include <unistd.h>  #include "alloc-util.h"  #include "cgroup-util.h" +#include "def.h"  #include "dirent-util.h"  #include "extract-word.h"  #include "fd-util.h"  #include "fileio.h"  #include "formats-util.h"  #include "fs-util.h" +#include "log.h"  #include "login-util.h"  #include "macro.h" +#include "missing.h"  #include "mkdir.h"  #include "parse-util.h"  #include "path-util.h" @@ -51,7 +57,6 @@  #include "string-util.h"  #include "unit-name.h"  #include "user-util.h" -#include "util.h"  int cg_enumerate_processes(const char *controller, const char *path, FILE **_f) {          _cleanup_free_ char *fs = NULL; @@ -2130,7 +2135,7 @@ int cg_unified(void) {          else if (F_TYPE_EQUAL(fs.f_type, TMPFS_MAGIC))                  unified_cache = false;          else -                return -ENOEXEC; +                return -ENOMEDIUM;          return unified_cache;  } diff --git a/src/basic/cgroup-util.h b/src/basic/cgroup-util.h index a80ee60bd3..661785784a 100644 --- a/src/basic/cgroup-util.h +++ b/src/basic/cgroup-util.h @@ -22,10 +22,14 @@  ***/  #include <dirent.h> +#include <stdbool.h> +#include <stdint.h>  #include <stdio.h>  #include <sys/types.h>  #include "def.h" +#include "hashmap.h" +#include "macro.h"  #include "set.h"  /* An enum of well known cgroup controllers */ diff --git a/src/basic/chattr-util.c b/src/basic/chattr-util.c index d49ca0537a..438fc63c5c 100644 --- a/src/basic/chattr-util.c +++ b/src/basic/chattr-util.c @@ -19,13 +19,15 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <fcntl.h>  #include <sys/ioctl.h>  #include <sys/stat.h>  #include <linux/fs.h>  #include "chattr-util.h"  #include "fd-util.h" -#include "util.h" +#include "macro.h"  int chattr_fd(int fd, unsigned value, unsigned mask) {          unsigned old_attr, new_attr; diff --git a/src/basic/clock-util.c b/src/basic/clock-util.c index 00ee4c2796..00f549c023 100644 --- a/src/basic/clock-util.c +++ b/src/basic/clock-util.c @@ -21,6 +21,9 @@  #include <errno.h>  #include <fcntl.h> +#include <limits.h> +#include <stdbool.h> +#include <time.h>  #include <linux/rtc.h>  #include <stdio.h>  #include <sys/ioctl.h> @@ -30,7 +33,6 @@  #include "fd-util.h"  #include "macro.h"  #include "string-util.h" -#include "util.h"  int clock_get_hwclock(struct tm *tm) {          _cleanup_close_ int fd = -1; diff --git a/src/basic/conf-files.c b/src/basic/conf-files.c index be9972ffff..75dad228e3 100644 --- a/src/basic/conf-files.c +++ b/src/basic/conf-files.c @@ -21,6 +21,7 @@  #include <dirent.h>  #include <errno.h> +#include <stdarg.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> diff --git a/src/basic/copy.c b/src/basic/copy.c index a187ae08fe..024712d290 100644 --- a/src/basic/copy.c +++ b/src/basic/copy.c @@ -19,8 +19,18 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h>  #include <sys/sendfile.h> +#include <sys/stat.h>  #include <sys/xattr.h> +#include <time.h> +#include <unistd.h>  #include "alloc-util.h"  #include "btrfs-util.h" @@ -31,10 +41,11 @@  #include "fileio.h"  #include "fs-util.h"  #include "io-util.h" +#include "macro.h"  #include "string-util.h"  #include "strv.h" +#include "time-util.h"  #include "umask-util.h" -#include "util.h"  #include "xattr-util.h"  #define COPY_BUFFER_SIZE (16*1024) diff --git a/src/basic/copy.h b/src/basic/copy.h index ba0890b442..b3fc2bb709 100644 --- a/src/basic/copy.h +++ b/src/basic/copy.h @@ -23,6 +23,7 @@  #include <inttypes.h>  #include <stdbool.h> +#include <stdint.h>  #include <sys/types.h>  int copy_file_fd(const char *from, int to, bool try_reflink); diff --git a/src/basic/cpu-set-util.c b/src/basic/cpu-set-util.c index e2ec4ca83f..85b7519953 100644 --- a/src/basic/cpu-set-util.c +++ b/src/basic/cpu-set-util.c @@ -20,12 +20,17 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stddef.h> +#include <syslog.h> +  #include "alloc-util.h"  #include "cpu-set-util.h"  #include "extract-word.h" +#include "log.h" +#include "macro.h"  #include "parse-util.h"  #include "string-util.h" -#include "util.h"  cpu_set_t* cpu_set_malloc(unsigned *ncpus) {          cpu_set_t *c; diff --git a/src/basic/device-nodes.c b/src/basic/device-nodes.c index 9d5af72d27..ec58cfdd4c 100644 --- a/src/basic/device-nodes.c +++ b/src/basic/device-nodes.c @@ -19,7 +19,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <stdio.h> +#include <string.h>  #include "device-nodes.h"  #include "utf8.h" diff --git a/src/basic/device-nodes.h b/src/basic/device-nodes.h index 7db81f3d52..9669c86970 100644 --- a/src/basic/device-nodes.h +++ b/src/basic/device-nodes.h @@ -21,6 +21,7 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stddef.h>  #include <sys/types.h>  int encode_devnode_name(const char *str, char *str_enc, size_t len); diff --git a/src/basic/dirent-util.c b/src/basic/dirent-util.c index c433d5844a..4ef5aba5a8 100644 --- a/src/basic/dirent-util.c +++ b/src/basic/dirent-util.c @@ -21,10 +21,9 @@  #include <fcntl.h>  #include <sys/stat.h> -#include <sys/types.h> -#include <unistd.h>  #include "dirent-util.h" +#include "path-util.h"  #include "string-util.h"  int dirent_ensure_type(DIR *d, struct dirent *de) { diff --git a/src/basic/dirent-util.h b/src/basic/dirent-util.h index 5866a755f4..1ad5e4715a 100644 --- a/src/basic/dirent-util.h +++ b/src/basic/dirent-util.h @@ -22,7 +22,10 @@  ***/  #include <dirent.h> +#include <errno.h> +#include <stdbool.h> +#include "macro.h"  #include "path-util.h"  int dirent_ensure_type(DIR *d, struct dirent *de); diff --git a/src/basic/env-util.c b/src/basic/env-util.c index 441169db31..dd56545f12 100644 --- a/src/basic/env-util.c +++ b/src/basic/env-util.c @@ -19,17 +19,21 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <limits.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h>  #include <unistd.h>  #include "alloc-util.h" -#include "def.h"  #include "env-util.h" +#include "extract-word.h" +#include "macro.h"  #include "parse-util.h"  #include "string-util.h"  #include "strv.h"  #include "utf8.h" -#include "util.h"  #define VALID_CHARS_ENV_NAME                    \          DIGITS LETTERS                          \ diff --git a/src/basic/env-util.h b/src/basic/env-util.h index 5efffa3dc7..3b83a63a78 100644 --- a/src/basic/env-util.h +++ b/src/basic/env-util.h @@ -22,6 +22,7 @@  ***/  #include <stdbool.h> +#include <stddef.h>  #include "macro.h" diff --git a/src/basic/errno-list.c b/src/basic/errno-list.c index 22869e4136..0a66902ac9 100644 --- a/src/basic/errno-list.c +++ b/src/basic/errno-list.c @@ -22,7 +22,7 @@  #include <string.h>  #include "errno-list.h" -#include "util.h" +#include "macro.h"  static const struct errno_name* lookup_errno(register const char *str,                                                   register unsigned int len); diff --git a/src/basic/escape.c b/src/basic/escape.c index 42a84c9317..ab282efa3c 100644 --- a/src/basic/escape.c +++ b/src/basic/escape.c @@ -19,12 +19,15 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stdlib.h> +#include <string.h> +  #include "alloc-util.h"  #include "escape.h"  #include "hexdecoct.h" -#include "string-util.h" +#include "macro.h"  #include "utf8.h" -#include "util.h"  size_t cescape_char(char c, char *buf) {          char * buf_old = buf; diff --git a/src/basic/escape.h b/src/basic/escape.h index 52ebf11c4a..c710f01743 100644 --- a/src/basic/escape.h +++ b/src/basic/escape.h @@ -22,8 +22,12 @@  ***/  #include <inttypes.h> +#include <stddef.h> +#include <stdint.h>  #include <sys/types.h> +#include "string-util.h" +  /* What characters are special in the shell? */  /* must be escaped outside and inside double-quotes */  #define SHELL_NEED_ESCAPE "\"\\`$" diff --git a/src/basic/ether-addr-util.c b/src/basic/ether-addr-util.c index 2bf3bfec1d..bc54f8f5f4 100644 --- a/src/basic/ether-addr-util.c +++ b/src/basic/ether-addr-util.c @@ -19,7 +19,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <net/ethernet.h>  #include <stdio.h> +#include <sys/types.h>  #include "ether-addr-util.h"  #include "macro.h" diff --git a/src/basic/exit-status.h b/src/basic/exit-status.h index 7259cd1d18..664222c1d6 100644 --- a/src/basic/exit-status.h +++ b/src/basic/exit-status.h @@ -23,6 +23,8 @@  #include <stdbool.h> +#include "hashmap.h" +#include "macro.h"  #include "set.h"  typedef enum ExitStatus { diff --git a/src/basic/extract-word.c b/src/basic/extract-word.c index fd495692fa..7cc2a1de13 100644 --- a/src/basic/extract-word.c +++ b/src/basic/extract-word.c @@ -19,12 +19,22 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stdarg.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +  #include "alloc-util.h"  #include "escape.h"  #include "extract-word.h" +#include "log.h" +#include "macro.h"  #include "string-util.h"  #include "utf8.h" -#include "util.h"  int extract_first_word(const char **p, char **ret, const char *separators, ExtractFlags flags) {          _cleanup_free_ char *s = NULL; diff --git a/src/basic/fd-util.c b/src/basic/fd-util.c index d1b1db3a4d..9759cac23c 100644 --- a/src/basic/fd-util.c +++ b/src/basic/fd-util.c @@ -19,9 +19,18 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -#include "dirent-util.h" +#include <errno.h> +#include <fcntl.h> +#include <sys/resource.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <unistd.h> +  #include "fd-util.h" +#include "macro.h" +#include "missing.h"  #include "parse-util.h" +#include "path-util.h"  #include "socket-util.h"  #include "util.h" diff --git a/src/basic/fdset.c b/src/basic/fdset.c index e5452f3bb0..de9b723ab8 100644 --- a/src/basic/fdset.c +++ b/src/basic/fdset.c @@ -19,19 +19,21 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <alloca.h>  #include <dirent.h>  #include <errno.h>  #include <fcntl.h> +#include <stddef.h>  #include "sd-daemon.h" -#include "dirent-util.h"  #include "fd-util.h"  #include "fdset.h" +#include "log.h"  #include "macro.h"  #include "parse-util.h" +#include "path-util.h"  #include "set.h" -#include "util.h"  #define MAKE_SET(s) ((Set*) s)  #define MAKE_FDSET(s) ((FDSet*) s) diff --git a/src/basic/fdset.h b/src/basic/fdset.h index 70d8acbcff..615ba05661 100644 --- a/src/basic/fdset.h +++ b/src/basic/fdset.h @@ -21,6 +21,10 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> + +#include "hashmap.h" +#include "macro.h"  #include "set.h"  typedef struct FDSet FDSet; diff --git a/src/basic/fileio-label.c b/src/basic/fileio-label.c index 0405822ce0..1cee87c9cd 100644 --- a/src/basic/fileio-label.c +++ b/src/basic/fileio-label.c @@ -20,9 +20,11 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <sys/stat.h> +  #include "fileio-label.h" +#include "fileio.h"  #include "selinux-util.h" -#include "util.h"  int write_string_file_atomic_label(const char *fn, const char *line) {          int r; diff --git a/src/basic/fileio.c b/src/basic/fileio.c index 10aacdc56d..3a237252b5 100644 --- a/src/basic/fileio.c +++ b/src/basic/fileio.c @@ -19,6 +19,15 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/types.h>  #include <unistd.h>  #include "alloc-util.h" @@ -28,15 +37,17 @@  #include "fileio.h"  #include "fs-util.h"  #include "hexdecoct.h" +#include "log.h" +#include "macro.h"  #include "parse-util.h"  #include "path-util.h"  #include "random-util.h"  #include "stdio-util.h"  #include "string-util.h"  #include "strv.h" +#include "time-util.h"  #include "umask-util.h"  #include "utf8.h" -#include "util.h"  int write_string_stream(FILE *f, const char *line, bool enforce_newline) { diff --git a/src/basic/fs-util.c b/src/basic/fs-util.c index 2b6189ad90..fb760abe18 100644 --- a/src/basic/fs-util.c +++ b/src/basic/fs-util.c @@ -19,16 +19,30 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <dirent.h> +#include <errno.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <time.h> +#include <unistd.h> +  #include "alloc-util.h"  #include "dirent-util.h"  #include "fd-util.h"  #include "fileio.h"  #include "fs-util.h" +#include "log.h" +#include "macro.h" +#include "missing.h"  #include "mkdir.h"  #include "parse-util.h"  #include "path-util.h"  #include "string-util.h"  #include "strv.h" +#include "time-util.h"  #include "user-util.h"  #include "util.h" diff --git a/src/basic/fs-util.h b/src/basic/fs-util.h index 5fbb7bc4c3..67ed214b51 100644 --- a/src/basic/fs-util.h +++ b/src/basic/fs-util.h @@ -23,6 +23,8 @@  #include <fcntl.h>  #include <limits.h> +#include <stdbool.h> +#include <stdint.h>  #include <sys/inotify.h>  #include <sys/types.h>  #include <unistd.h> diff --git a/src/basic/glob-util.c b/src/basic/glob-util.c index 0bfbcb1d37..a0be0efd40 100644 --- a/src/basic/glob-util.c +++ b/src/basic/glob-util.c @@ -19,12 +19,12 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <glob.h>  #include "glob-util.h" -#include "string-util.h" +#include "macro.h"  #include "strv.h" -#include "util.h"  int glob_exists(const char *path) {          _cleanup_globfree_ glob_t g = {}; diff --git a/src/basic/glob-util.h b/src/basic/glob-util.h index 793adf4a6c..a0a5efe5b6 100644 --- a/src/basic/glob-util.h +++ b/src/basic/glob-util.h @@ -21,6 +21,7 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h>  #include <string.h>  #include "macro.h" diff --git a/src/basic/gunicode.c b/src/basic/gunicode.c index d89a2f3ed9..542110503f 100644 --- a/src/basic/gunicode.c +++ b/src/basic/gunicode.c @@ -4,6 +4,8 @@   *  Copyright 2000, 2005 Red Hat, Inc.   */ +#include <stdlib.h> +  #include "gunicode.h"  #define unichar uint32_t diff --git a/src/basic/hashmap.c b/src/basic/hashmap.c index 6e501ef6ff..b3954e3223 100644 --- a/src/basic/hashmap.c +++ b/src/basic/hashmap.c @@ -21,8 +21,9 @@  ***/  #include <errno.h> -#include <pthread.h> +#include <stdint.h>  #include <stdlib.h> +#include <string.h>  #include "alloc-util.h"  #include "hashmap.h" diff --git a/src/basic/hashmap.h b/src/basic/hashmap.h index ed6a092d82..708811124b 100644 --- a/src/basic/hashmap.h +++ b/src/basic/hashmap.h @@ -22,7 +22,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <limits.h>  #include <stdbool.h> +#include <stddef.h>  #include "macro.h"  #include "siphash24.h" diff --git a/src/basic/hexdecoct.c b/src/basic/hexdecoct.c index 4eb566b15a..1e907de228 100644 --- a/src/basic/hexdecoct.c +++ b/src/basic/hexdecoct.c @@ -20,11 +20,13 @@  ***/  #include <ctype.h> -#include <inttypes.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h>  #include "alloc-util.h"  #include "hexdecoct.h" -#include "util.h" +#include "macro.h"  char octchar(int x) {          return '0' + (x & 7); diff --git a/src/basic/hexdecoct.h b/src/basic/hexdecoct.h index 4aeb4c3bdc..d9eb54a8a1 100644 --- a/src/basic/hexdecoct.h +++ b/src/basic/hexdecoct.h @@ -22,6 +22,7 @@  ***/  #include <stdbool.h> +#include <stddef.h>  #include <stdio.h>  #include <sys/types.h> diff --git a/src/basic/hostname-util.c b/src/basic/hostname-util.c index c57a3cbd60..795afb6d00 100644 --- a/src/basic/hostname-util.c +++ b/src/basic/hostname-util.c @@ -19,14 +19,19 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -#include <ctype.h> +#include <bits/local_lim.h> +#include <errno.h> +#include <limits.h> +#include <stdio.h> +#include <string.h>  #include <sys/utsname.h> +#include <unistd.h>  #include "fd-util.h"  #include "fileio.h"  #include "hostname-util.h" +#include "macro.h"  #include "string-util.h" -#include "util.h"  bool hostname_is_set(void) {          struct utsname u; diff --git a/src/basic/in-addr-util.c b/src/basic/in-addr-util.c index b75c39aac7..5143dddf8f 100644 --- a/src/basic/in-addr-util.c +++ b/src/basic/in-addr-util.c @@ -20,9 +20,15 @@  ***/  #include <arpa/inet.h> +#include <endian.h> +#include <errno.h> +#include <stdint.h> +#include <stdlib.h>  #include "alloc-util.h"  #include "in-addr-util.h" +#include "macro.h" +#include "util.h"  int in_addr_is_null(int family, const union in_addr_union *u) {          assert(u); diff --git a/src/basic/in-addr-util.h b/src/basic/in-addr-util.h index 58f55b3418..bcc116c783 100644 --- a/src/basic/in-addr-util.h +++ b/src/basic/in-addr-util.h @@ -22,6 +22,8 @@  ***/  #include <netinet/in.h> +#include <stddef.h> +#include <sys/socket.h>  #include "macro.h"  #include "util.h" diff --git a/src/basic/io-util.c b/src/basic/io-util.c index ac8f93ff57..e83e7cec72 100644 --- a/src/basic/io-util.c +++ b/src/basic/io-util.c @@ -19,10 +19,15 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <limits.h>  #include <poll.h> +#include <stdio.h> +#include <time.h>  #include <unistd.h>  #include "io-util.h" +#include "time-util.h"  int flush_fd(int fd) {          struct pollfd pollfd = { diff --git a/src/basic/io-util.h b/src/basic/io-util.h index cd2aa75ad2..5f77a556c0 100644 --- a/src/basic/io-util.h +++ b/src/basic/io-util.h @@ -22,9 +22,12 @@  ***/  #include <stdbool.h> +#include <stddef.h> +#include <stdint.h>  #include <sys/types.h>  #include <sys/uio.h> +#include "macro.h"  #include "time-util.h"  int flush_fd(int fd); diff --git a/src/basic/json.c b/src/basic/json.c index 9d5dedb934..1523e9fb09 100644 --- a/src/basic/json.c +++ b/src/basic/json.c @@ -19,7 +19,10 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <math.h> +#include <stdlib.h> +#include <string.h>  #include <sys/types.h>  #include "alloc-util.h" diff --git a/src/basic/json.h b/src/basic/json.h index 8a7d79cb17..df3f62f206 100644 --- a/src/basic/json.h +++ b/src/basic/json.h @@ -22,7 +22,10 @@  ***/  #include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include "macro.h"  #include "util.h"  enum { diff --git a/src/basic/label.c b/src/basic/label.c index f33502f90f..f72a985967 100644 --- a/src/basic/label.c +++ b/src/basic/label.c @@ -19,10 +19,14 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <sys/stat.h> +#include <unistd.h> +  #include "label.h" +#include "macro.h"  #include "selinux-util.h"  #include "smack-util.h" -#include "util.h"  int label_fix(const char *path, bool ignore_enoent, bool ignore_erofs) {          int r, q; diff --git a/src/basic/locale-util.c b/src/basic/locale-util.c index b87fd7670b..7784d02168 100644 --- a/src/basic/locale-util.c +++ b/src/basic/locale-util.c @@ -19,12 +19,22 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <dirent.h> +#include <errno.h> +#include <fcntl.h>  #include <langinfo.h> +#include <libintl.h>  #include <locale.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h>  #include <sys/mman.h> +#include <sys/stat.h>  #include "dirent-util.h"  #include "fd-util.h" +#include "hashmap.h"  #include "locale-util.h"  #include "path-util.h"  #include "set.h" @@ -32,7 +42,6 @@  #include "string-util.h"  #include "strv.h"  #include "utf8.h" -#include "util.h"  static int add_locales_from_archive(Set *locales) {          /* Stolen from glibc... */ diff --git a/src/basic/lockfile-util.c b/src/basic/lockfile-util.c index 0bdbae480b..6ecfc2ec46 100644 --- a/src/basic/lockfile-util.c +++ b/src/basic/lockfile-util.c @@ -20,20 +20,18 @@  ***/  #include <errno.h> -#include <limits.h> -#include <stdbool.h> +#include <fcntl.h>  #include <stdio.h> -#include <stdlib.h>  #include <string.h>  #include <sys/file.h> +#include <sys/stat.h>  #include "alloc-util.h"  #include "fd-util.h" -#include "fileio.h"  #include "fs-util.h"  #include "lockfile-util.h" +#include "macro.h"  #include "path-util.h" -#include "util.h"  int make_lock_file(const char *p, int operation, LockFile *ret) {          _cleanup_close_ int fd = -1; diff --git a/src/basic/lockfile-util.h b/src/basic/lockfile-util.h index 38d47094bd..3c514c9e62 100644 --- a/src/basic/lockfile-util.h +++ b/src/basic/lockfile-util.h @@ -21,6 +21,8 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stddef.h> +  #include "macro.h"  #include "missing.h" diff --git a/src/basic/log.c b/src/basic/log.c index fe29cacd9e..1a9e6bdb91 100644 --- a/src/basic/log.c +++ b/src/basic/log.c @@ -21,12 +21,18 @@  #include <errno.h>  #include <fcntl.h> -#include <printf.h> +#include <inttypes.h> +#include <limits.h>  #include <stdarg.h>  #include <stddef.h>  #include <stdio.h> +#include <string.h> +#include <sys/signalfd.h>  #include <sys/socket.h> +#include <sys/time.h> +#include <sys/uio.h>  #include <sys/un.h> +#include <time.h>  #include <unistd.h>  #include "sd-messages.h" @@ -48,6 +54,7 @@  #include "string-util.h"  #include "syslog-util.h"  #include "terminal-util.h" +#include "time-util.h"  #include "util.h"  #define SNDBUF_SIZE (8*1024*1024) diff --git a/src/basic/login-util.c b/src/basic/login-util.c index 41cef14e73..4e08fe3895 100644 --- a/src/basic/login-util.c +++ b/src/basic/login-util.c @@ -19,7 +19,8 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -#include "def.h" +#include <string.h> +  #include "login-util.h"  #include "string-util.h" diff --git a/src/basic/memfd-util.c b/src/basic/memfd-util.c index 92630f6b25..789638f013 100644 --- a/src/basic/memfd-util.c +++ b/src/basic/memfd-util.c @@ -19,7 +19,10 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h>  #ifdef HAVE_LINUX_MEMFD_H  #include <linux/memfd.h>  #endif @@ -29,11 +32,11 @@  #include "alloc-util.h"  #include "fd-util.h" +#include "macro.h"  #include "memfd-util.h"  #include "missing.h"  #include "string-util.h"  #include "utf8.h" -#include "util.h"  int memfd_new(const char *name) {          _cleanup_free_ char *g = NULL; diff --git a/src/basic/memfd-util.h b/src/basic/memfd-util.h index 3e4de008a4..2a89361c4c 100644 --- a/src/basic/memfd-util.h +++ b/src/basic/memfd-util.h @@ -22,6 +22,8 @@  ***/  #include <inttypes.h> +#include <stddef.h> +#include <stdint.h>  #include <sys/types.h>  int memfd_new(const char *name); diff --git a/src/basic/mempool.c b/src/basic/mempool.c index 9ee6e6a76d..1822d3956f 100644 --- a/src/basic/mempool.c +++ b/src/basic/mempool.c @@ -20,6 +20,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdint.h> +#include <stdlib.h> +  #include "macro.h"  #include "mempool.h"  #include "util.h" diff --git a/src/basic/mkdir-label.c b/src/basic/mkdir-label.c index c241ef6064..c9e17f7680 100644 --- a/src/basic/mkdir-label.c +++ b/src/basic/mkdir-label.c @@ -21,6 +21,7 @@  ***/  #include <stdio.h> +#include <sys/types.h>  #include <unistd.h>  #include "label.h" diff --git a/src/basic/mkdir.c b/src/basic/mkdir.c index 5d7fb9a12d..9f9d52b5df 100644 --- a/src/basic/mkdir.c +++ b/src/basic/mkdir.c @@ -20,14 +20,16 @@  ***/  #include <errno.h> +#include <stdbool.h>  #include <string.h> +#include <sys/stat.h>  #include "fs-util.h" +#include "macro.h"  #include "mkdir.h"  #include "path-util.h"  #include "stat-util.h"  #include "user-util.h" -#include "util.h"  int mkdir_safe_internal(const char *path, mode_t mode, uid_t uid, gid_t gid, mkdir_func_t _mkdir) {          struct stat st; diff --git a/src/basic/mount-util.c b/src/basic/mount-util.c index 29997b1ce7..10a6536cfc 100644 --- a/src/basic/mount-util.c +++ b/src/basic/mount-util.c @@ -19,21 +19,25 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stdlib.h>  #include <string.h>  #include <sys/mount.h> +#include <sys/stat.h>  #include <sys/statvfs.h> +#include <unistd.h>  #include "alloc-util.h"  #include "escape.h"  #include "fd-util.h"  #include "fileio.h" +#include "hashmap.h"  #include "mount-util.h"  #include "parse-util.h"  #include "path-util.h"  #include "set.h"  #include "stdio-util.h"  #include "string-util.h" -#include "util.h"  static int fd_fdinfo_mnt_id(int fd, const char *filename, int flags, int *mnt_id) {          char path[strlen("/proc/self/fdinfo/") + DECIMAL_STR_MAX(int)]; diff --git a/src/basic/mount-util.h b/src/basic/mount-util.h index 48954c2d67..b37250f08e 100644 --- a/src/basic/mount-util.h +++ b/src/basic/mount-util.h @@ -24,9 +24,11 @@  #include <fcntl.h>  #include <mntent.h>  #include <stdbool.h> +#include <stdio.h>  #include <sys/stat.h>  #include <sys/types.h> +#include "macro.h"  #include "missing.h"  int fd_is_mount_point(int fd, const char *filename, int flags); diff --git a/src/basic/parse-util.c b/src/basic/parse-util.c index 3ae99d9334..618ef5d564 100644 --- a/src/basic/parse-util.c +++ b/src/basic/parse-util.c @@ -19,11 +19,19 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <inttypes.h> +#include <locale.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <xlocale.h> +  #include "alloc-util.h"  #include "extract-word.h" +#include "macro.h"  #include "parse-util.h"  #include "string-util.h" -#include "util.h"  int parse_boolean(const char *v) {          assert(v); diff --git a/src/basic/parse-util.h b/src/basic/parse-util.h index 125de53d7a..af439cfaa7 100644 --- a/src/basic/parse-util.h +++ b/src/basic/parse-util.h @@ -22,6 +22,9 @@  ***/  #include <inttypes.h> +#include <limits.h> +#include <stddef.h> +#include <stdint.h>  #include <sys/types.h>  #include "macro.h" diff --git a/src/basic/path-util.c b/src/basic/path-util.c index ec90c432a4..61fab0e087 100644 --- a/src/basic/path-util.c +++ b/src/basic/path-util.c @@ -20,11 +20,11 @@  ***/  #include <errno.h> -#include <fcntl.h> +#include <limits.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> -#include <sys/statvfs.h> +#include <sys/stat.h>  #include <unistd.h>  /* When we include libgen.h because we need dirname() we immediately @@ -34,18 +34,16 @@  #undef basename  #include "alloc-util.h" -#include "fd-util.h" -#include "fileio.h" +#include "extract-word.h"  #include "fs-util.h"  #include "log.h"  #include "macro.h"  #include "missing.h" -#include "parse-util.h"  #include "path-util.h"  #include "stat-util.h"  #include "string-util.h"  #include "strv.h" -#include "util.h" +#include "time-util.h"  bool path_is_absolute(const char *p) {          return p[0] == '/'; diff --git a/src/basic/path-util.h b/src/basic/path-util.h index 989e0f9004..84472d38c7 100644 --- a/src/basic/path-util.h +++ b/src/basic/path-util.h @@ -21,7 +21,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <alloca.h>  #include <stdbool.h> +#include <stddef.h>  #include "macro.h"  #include "time-util.h" diff --git a/src/basic/prioq.c b/src/basic/prioq.c index 7590698911..86c5c0e9b4 100644 --- a/src/basic/prioq.c +++ b/src/basic/prioq.c @@ -29,9 +29,12 @@   * The underlying algorithm used in this implementation is a Heap.   */ +#include <errno.h> +#include <stdlib.h> +  #include "alloc-util.h" +#include "hashmap.h"  #include "prioq.h" -#include "util.h"  struct prioq_item {          void *data; diff --git a/src/basic/prioq.h b/src/basic/prioq.h index 1c044b135c..6a2451387c 100644 --- a/src/basic/prioq.h +++ b/src/basic/prioq.h @@ -21,7 +21,10 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> +  #include "hashmap.h" +#include "macro.h"  typedef struct Prioq Prioq; diff --git a/src/basic/proc-cmdline.c b/src/basic/proc-cmdline.c index 4464573c5b..4e8eba10ab 100644 --- a/src/basic/proc-cmdline.c +++ b/src/basic/proc-cmdline.c @@ -19,6 +19,10 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> +#include <stddef.h> +#include <string.h> +  #include "alloc-util.h"  #include "extract-word.h"  #include "fileio.h" diff --git a/src/basic/process-util.c b/src/basic/process-util.c index 7631928d5f..4cc54a51fb 100644 --- a/src/basic/process-util.c +++ b/src/basic/process-util.c @@ -17,18 +17,21 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -#include <assert.h>  #include <ctype.h>  #include <errno.h> +#include <limits.h> +#include <linux/oom.h>  #include <sched.h>  #include <signal.h>  #include <stdbool.h>  #include <stdio.h> +#include <stdlib.h>  #include <string.h>  #include <sys/personality.h>  #include <sys/prctl.h>  #include <sys/types.h>  #include <sys/wait.h> +#include <syslog.h>  #include <unistd.h>  #include "alloc-util.h" @@ -38,6 +41,8 @@  #include "fs-util.h"  #include "ioprio.h"  #include "log.h" +#include "macro.h" +#include "missing.h"  #include "process-util.h"  #include "signal-util.h"  #include "string-table.h" diff --git a/src/basic/process-util.h b/src/basic/process-util.h index fdc7e1bdef..f4c4437624 100644 --- a/src/basic/process-util.h +++ b/src/basic/process-util.h @@ -22,6 +22,7 @@  #include <alloca.h>  #include <signal.h>  #include <stdbool.h> +#include <stddef.h>  #include <stdio.h>  #include <string.h>  #include <sys/types.h> diff --git a/src/basic/random-util.c b/src/basic/random-util.c index 2f5c16e2af..e1543da5a3 100644 --- a/src/basic/random-util.c +++ b/src/basic/random-util.c @@ -17,23 +17,24 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <elf.h>  #include <errno.h>  #include <fcntl.h> +#include <stdbool.h> +#include <stdlib.h> +#include <sys/time.h>  #include <linux/random.h>  #include <stdint.h> +  #ifdef HAVE_SYS_AUXV_H  #include <sys/auxv.h>  #endif -#include <sys/stat.h> -#include <sys/types.h> -#include <time.h>  #include "fd-util.h"  #include "io-util.h"  #include "missing.h"  #include "random-util.h"  #include "time-util.h" -#include "util.h"  int dev_urandom(void *p, size_t n) {          static int have_syscall = -1; diff --git a/src/basic/random-util.h b/src/basic/random-util.h index f7862c8c8b..3cee4c5014 100644 --- a/src/basic/random-util.h +++ b/src/basic/random-util.h @@ -19,6 +19,7 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stddef.h>  #include <stdint.h>  int dev_urandom(void *p, size_t n); diff --git a/src/basic/ratelimit.c b/src/basic/ratelimit.c index 81fc9c19ff..b62f3da76b 100644 --- a/src/basic/ratelimit.c +++ b/src/basic/ratelimit.c @@ -20,6 +20,9 @@  ***/ +#include <sys/time.h> + +#include "macro.h"  #include "ratelimit.h"  /* Modelled after Linux' lib/ratelimit.c by Dave Young diff --git a/src/basic/ratelimit.h b/src/basic/ratelimit.h index 58efca7df1..98c81f6b9e 100644 --- a/src/basic/ratelimit.h +++ b/src/basic/ratelimit.h @@ -21,6 +21,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> + +#include "time-util.h"  #include "util.h"  typedef struct RateLimit { diff --git a/src/basic/replace-var.c b/src/basic/replace-var.c index bf757cbc48..8c3279b376 100644 --- a/src/basic/replace-var.c +++ b/src/basic/replace-var.c @@ -19,13 +19,15 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stddef.h> +#include <stdlib.h>  #include <string.h>  #include "alloc-util.h"  #include "macro.h"  #include "replace-var.h"  #include "string-util.h" -#include "util.h"  /*   * Generic infrastructure for replacing @FOO@ style variables in diff --git a/src/basic/rlimit-util.c b/src/basic/rlimit-util.c index 2627c813fc..44f885db16 100644 --- a/src/basic/rlimit-util.c +++ b/src/basic/rlimit-util.c @@ -19,10 +19,13 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <sys/resource.h> + +#include "macro.h"  #include "missing.h"  #include "rlimit-util.h"  #include "string-table.h" -#include "util.h"  int setrlimit_closest(int resource, const struct rlimit *rlim) {          struct rlimit highest, fixed; diff --git a/src/basic/rm-rf.c b/src/basic/rm-rf.c index 8ec7dd75ee..14f8474da0 100644 --- a/src/basic/rm-rf.c +++ b/src/basic/rm-rf.c @@ -19,14 +19,24 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <stdbool.h> +#include <stddef.h> +#include <sys/stat.h> +#include <sys/statfs.h> +#include <unistd.h> +  #include "btrfs-util.h"  #include "fd-util.h" +#include "log.h" +#include "macro.h"  #include "mount-util.h"  #include "path-util.h"  #include "rm-rf.h"  #include "stat-util.h"  #include "string-util.h" -#include "util.h"  int rm_rf_children(int fd, RemoveFlags flags, struct stat *root_dev) {          _cleanup_closedir_ DIR *d = NULL; diff --git a/src/basic/selinux-util.c b/src/basic/selinux-util.c index e8ce5cfd96..5956c4fe43 100644 --- a/src/basic/selinux-util.c +++ b/src/basic/selinux-util.c @@ -21,7 +21,12 @@  #include <errno.h>  #include <malloc.h> +#include <stddef.h> +#include <string.h> +#include <sys/stat.h> +#include <sys/time.h>  #include <sys/un.h> +#include <syslog.h>  #ifdef HAVE_SELINUX  #include <selinux/context.h> @@ -30,9 +35,12 @@  #endif  #include "alloc-util.h" +#include "log.h" +#include "macro.h"  #include "path-util.h"  #include "selinux-util.h" -#include "strv.h" +#include "time-util.h" +#include "util.h"  #ifdef HAVE_SELINUX  DEFINE_TRIVIAL_CLEANUP_FUNC(security_context_t, freecon); @@ -47,7 +55,7 @@ static struct selabel_handle *label_hnd = NULL;  #define log_enforcing(...) log_full(security_getenforce() == 1 ? LOG_ERR : LOG_DEBUG, __VA_ARGS__)  #endif -bool mac_selinux_use(void) { +bool mac_selinux_have(void) {  #ifdef HAVE_SELINUX          if (cached_use < 0)                  cached_use = is_selinux_enabled() > 0; @@ -58,6 +66,16 @@ bool mac_selinux_use(void) {  #endif  } +bool mac_selinux_use(void) { +        if (!mac_selinux_have()) +                return false; + +        /* Never try to configure SELinux features if we aren't +         * root */ + +        return getuid() == 0; +} +  void mac_selinux_retest(void) {  #ifdef HAVE_SELINUX          cached_use = -1; @@ -197,7 +215,7 @@ int mac_selinux_get_create_label_from_exe(const char *exe, char **label) {          assert(exe);          assert(label); -        if (!mac_selinux_use()) +        if (!mac_selinux_have())                  return -EOPNOTSUPP;          r = getcon_raw(&mycon); @@ -223,7 +241,7 @@ int mac_selinux_get_our_label(char **label) {          assert(label);  #ifdef HAVE_SELINUX -        if (!mac_selinux_use()) +        if (!mac_selinux_have())                  return -EOPNOTSUPP;          r = getcon_raw(label); @@ -247,7 +265,7 @@ int mac_selinux_get_child_mls_label(int socket_fd, const char *exe, const char *          assert(exe);          assert(label); -        if (!mac_selinux_use()) +        if (!mac_selinux_have())                  return -EOPNOTSUPP;          r = getcon_raw(&mycon); @@ -302,7 +320,7 @@ char* mac_selinux_free(char *label) {          if (!label)                  return NULL; -        if (!mac_selinux_use()) +        if (!mac_selinux_have())                  return NULL; diff --git a/src/basic/selinux-util.h b/src/basic/selinux-util.h index d19984c5fe..0111f4c858 100644 --- a/src/basic/selinux-util.h +++ b/src/basic/selinux-util.h @@ -23,10 +23,12 @@  #include <stdbool.h>  #include <sys/socket.h> +#include <sys/types.h>  #include "macro.h"  bool mac_selinux_use(void); +bool mac_selinux_have(void);  void mac_selinux_retest(void);  int mac_selinux_init(const char *prefix); diff --git a/src/basic/sigbus.c b/src/basic/sigbus.c index c535c89d52..fe2e2d1a28 100644 --- a/src/basic/sigbus.c +++ b/src/basic/sigbus.c @@ -19,7 +19,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <signal.h> +#include <stddef.h>  #include <sys/mman.h>  #include "macro.h" diff --git a/src/basic/signal-util.c b/src/basic/signal-util.c index 8038bc891d..7637fccb2f 100644 --- a/src/basic/signal-util.c +++ b/src/basic/signal-util.c @@ -19,11 +19,15 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> + +#include "macro.h"  #include "parse-util.h"  #include "signal-util.h"  #include "string-table.h"  #include "string-util.h" -#include "util.h"  int reset_all_signal_handlers(void) {          static const struct sigaction sa = { diff --git a/src/basic/siphash24.c b/src/basic/siphash24.c index 10fc56da69..060e8ba387 100644 --- a/src/basic/siphash24.c +++ b/src/basic/siphash24.c @@ -17,10 +17,9 @@      coding style)  */ +#include "macro.h"  #include "siphash24.h" -#include "sparse-endian.h"  #include "unaligned.h" -#include "util.h"  static inline uint64_t rotate_left(uint64_t x, uint8_t b) {          assert(b < 64); diff --git a/src/basic/siphash24.h b/src/basic/siphash24.h index ba4f7d01b6..3f7e20362b 100644 --- a/src/basic/siphash24.h +++ b/src/basic/siphash24.h @@ -1,6 +1,8 @@  #pragma once  #include <inttypes.h> +#include <stddef.h> +#include <stdint.h>  #include <sys/types.h>  struct siphash { diff --git a/src/basic/smack-util.c b/src/basic/smack-util.c index fcc046098d..b9e4ff87d8 100644 --- a/src/basic/smack-util.c +++ b/src/basic/smack-util.c @@ -21,15 +21,20 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <string.h> +#include <sys/stat.h>  #include <sys/xattr.h> +#include <unistd.h>  #include "alloc-util.h"  #include "fileio.h" +#include "log.h" +#include "macro.h"  #include "path-util.h"  #include "process-util.h"  #include "smack-util.h"  #include "string-table.h" -#include "util.h"  #include "xattr-util.h"  #ifdef HAVE_SMACK diff --git a/src/basic/smack-util.h b/src/basic/smack-util.h index e756dc8c28..1d85b52a33 100644 --- a/src/basic/smack-util.h +++ b/src/basic/smack-util.h @@ -24,6 +24,7 @@  ***/  #include <stdbool.h> +#include <sys/types.h>  #include "macro.h" diff --git a/src/basic/socket-label.c b/src/basic/socket-label.c index e5d4efc719..e169439e04 100644 --- a/src/basic/socket-label.c +++ b/src/basic/socket-label.c @@ -20,19 +20,23 @@  ***/  #include <errno.h> +#include <netinet/in.h> +#include <stdbool.h>  #include <stddef.h>  #include <string.h> +#include <sys/socket.h>  #include <sys/stat.h> +#include <sys/un.h>  #include <unistd.h>  #include "alloc-util.h"  #include "fd-util.h" +#include "log.h"  #include "macro.h"  #include "missing.h"  #include "mkdir.h"  #include "selinux-util.h"  #include "socket-util.h" -#include "util.h"  int socket_address_listen(                  const SocketAddress *a, diff --git a/src/basic/socket-util.c b/src/basic/socket-util.c index 1acab1ef95..79901a6a06 100644 --- a/src/basic/socket-util.c +++ b/src/basic/socket-util.c @@ -21,19 +21,22 @@  #include <arpa/inet.h>  #include <errno.h> +#include <limits.h>  #include <net/if.h>  #include <netdb.h>  #include <netinet/ip.h>  #include <stddef.h> +#include <stdint.h>  #include <stdio.h> +#include <stdlib.h>  #include <string.h> -#include <sys/types.h>  #include <unistd.h>  #include "alloc-util.h"  #include "fd-util.h"  #include "fileio.h"  #include "formats-util.h" +#include "log.h"  #include "macro.h"  #include "missing.h"  #include "parse-util.h" @@ -867,16 +870,24 @@ int getpeersec(int fd, char **ret) {          return 0;  } -int send_one_fd(int transport_fd, int fd, int flags) { +int send_one_fd_sa( +                int transport_fd, +                int fd, +                const struct sockaddr *sa, socklen_t len, +                int flags) { +          union {                  struct cmsghdr cmsghdr;                  uint8_t buf[CMSG_SPACE(sizeof(int))];          } control = {}; +        struct cmsghdr *cmsg; +          struct msghdr mh = { +                .msg_name = (struct sockaddr*) sa, +                .msg_namelen = len,                  .msg_control = &control,                  .msg_controllen = sizeof(control),          }; -        struct cmsghdr *cmsg;          assert(transport_fd >= 0);          assert(fd >= 0); diff --git a/src/basic/socket-util.h b/src/basic/socket-util.h index 129ffa811c..6da1df68d8 100644 --- a/src/basic/socket-util.h +++ b/src/basic/socket-util.h @@ -23,7 +23,10 @@  #include <netinet/ether.h>  #include <netinet/in.h> +#include <stdbool.h> +#include <stddef.h>  #include <sys/socket.h> +#include <sys/types.h>  #include <sys/un.h>  #include <linux/netlink.h>  #include <linux/if_packet.h> @@ -125,7 +128,11 @@ int ip_tos_from_string(const char *s);  int getpeercred(int fd, struct ucred *ucred);  int getpeersec(int fd, char **ret); -int send_one_fd(int transport_fd, int fd, int flags); +int send_one_fd_sa(int transport_fd, +                   int fd, +                   const struct sockaddr *sa, socklen_t len, +                   int flags); +#define send_one_fd(transport_fd, fd, flags) send_one_fd_sa(transport_fd, fd, NULL, 0, flags)  int receive_one_fd(int transport_fd, int flags);  #define CMSG_FOREACH(cmsg, mh)                                          \ diff --git a/src/basic/stat-util.c b/src/basic/stat-util.c index 3bc66b3be7..21a8fb77a1 100644 --- a/src/basic/stat-util.c +++ b/src/basic/stat-util.c @@ -19,7 +19,11 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <dirent.h> +#include <errno.h>  #include <fcntl.h> +#include <sys/stat.h> +#include <sys/types.h>  #include <linux/magic.h>  #include <sys/statvfs.h>  #include <unistd.h> diff --git a/src/basic/stat-util.h b/src/basic/stat-util.h index fb92464274..8e031e6155 100644 --- a/src/basic/stat-util.h +++ b/src/basic/stat-util.h @@ -22,7 +22,9 @@  ***/  #include <stdbool.h> +#include <stddef.h>  #include <sys/stat.h> +#include <sys/statfs.h>  #include <sys/types.h>  #include <sys/vfs.h> diff --git a/src/basic/strbuf.c b/src/basic/strbuf.c index f4f702a05a..c9984bef08 100644 --- a/src/basic/strbuf.c +++ b/src/basic/strbuf.c @@ -19,12 +19,12 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <stdlib.h>  #include <string.h>  #include "alloc-util.h"  #include "strbuf.h" -#include "util.h"  /*   * Strbuf stores given strings in a single continuous allocated memory diff --git a/src/basic/strbuf.h b/src/basic/strbuf.h index fbc4e5f2a1..69565f7e2c 100644 --- a/src/basic/strbuf.h +++ b/src/basic/strbuf.h @@ -21,7 +21,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stddef.h>  #include <stdint.h> +#include <sys/types.h>  struct strbuf {          char *buf; diff --git a/src/basic/string-table.c b/src/basic/string-table.c index a860324fc9..4633a57f44 100644 --- a/src/basic/string-table.c +++ b/src/basic/string-table.c @@ -20,6 +20,7 @@  ***/  #include "string-table.h" +#include "string-util.h"  ssize_t string_table_lookup(const char * const *table, size_t len, const char *key) {          size_t i; diff --git a/src/basic/string-table.h b/src/basic/string-table.h index 51b6007214..2181a3a767 100644 --- a/src/basic/string-table.h +++ b/src/basic/string-table.h @@ -22,6 +22,7 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <stddef.h>  #include <stdio.h>  #include <string.h> diff --git a/src/basic/string-util.c b/src/basic/string-util.c index 6006767daa..8178c7093f 100644 --- a/src/basic/string-util.c +++ b/src/basic/string-util.c @@ -19,8 +19,15 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +  #include "alloc-util.h"  #include "gunicode.h" +#include "macro.h"  #include "string-util.h"  #include "utf8.h"  #include "util.h" diff --git a/src/basic/string-util.h b/src/basic/string-util.h index 54f9d3058c..b59b9b5a71 100644 --- a/src/basic/string-util.h +++ b/src/basic/string-util.h @@ -21,7 +21,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <alloca.h>  #include <stdbool.h> +#include <stddef.h>  #include <string.h>  #include "macro.h" diff --git a/src/basic/strv.c b/src/basic/strv.c index 771781f9fc..0a3d15706f 100644 --- a/src/basic/strv.c +++ b/src/basic/strv.c @@ -20,12 +20,15 @@  ***/  #include <errno.h> +#include <fnmatch.h>  #include <stdarg.h> +#include <stdio.h>  #include <stdlib.h>  #include <string.h>  #include "alloc-util.h"  #include "escape.h" +#include "extract-word.h"  #include "string-util.h"  #include "strv.h"  #include "util.h" diff --git a/src/basic/strv.h b/src/basic/strv.h index e66794fc34..bb61db2638 100644 --- a/src/basic/strv.h +++ b/src/basic/strv.h @@ -24,8 +24,11 @@  #include <fnmatch.h>  #include <stdarg.h>  #include <stdbool.h> +#include <stddef.h> +#include "alloc-util.h"  #include "extract-word.h" +#include "macro.h"  #include "util.h"  char *strv_find(char **l, const char *name) _pure_; diff --git a/src/basic/strxcpyx.c b/src/basic/strxcpyx.c index 088ba53c29..c454171de1 100644 --- a/src/basic/strxcpyx.c +++ b/src/basic/strxcpyx.c @@ -25,6 +25,7 @@   * Returns the * remaining size, and 0 if the string was truncated.   */ +#include <stdarg.h>  #include <stdio.h>  #include <string.h> diff --git a/src/basic/strxcpyx.h b/src/basic/strxcpyx.h index ccc7e52f37..02e22e6294 100644 --- a/src/basic/strxcpyx.h +++ b/src/basic/strxcpyx.h @@ -22,6 +22,8 @@  ***/ +#include <stddef.h> +  #include "macro.h"  size_t strpcpy(char **dest, size_t size, const char *src); diff --git a/src/basic/syslog-util.c b/src/basic/syslog-util.c index 01577941a0..7dc2761b6f 100644 --- a/src/basic/syslog-util.c +++ b/src/basic/syslog-util.c @@ -19,10 +19,11 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <string.h>  #include <syslog.h> -#include "assert.h"  #include "hexdecoct.h" +#include "macro.h"  #include "string-table.h"  #include "syslog-util.h" diff --git a/src/basic/terminal-util.c b/src/basic/terminal-util.c index 3931b03bc2..a39764472b 100644 --- a/src/basic/terminal-util.c +++ b/src/basic/terminal-util.c @@ -17,18 +17,25 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -#include <assert.h> +#include <errno.h>  #include <fcntl.h> +#include <limits.h> +#include <stdarg.h> +#include <stddef.h> +#include <stdlib.h> +#include <string.h> +#include <sys/inotify.h> +#include <sys/socket.h> +#include <sys/sysmacros.h> +#include <sys/time.h>  #include <linux/kd.h>  #include <linux/tiocl.h>  #include <linux/vt.h>  #include <poll.h>  #include <signal.h>  #include <sys/ioctl.h> -#include <sys/stat.h>  #include <sys/types.h>  #include <termios.h> -#include <time.h>  #include <unistd.h>  #include "alloc-util.h" @@ -36,8 +43,9 @@  #include "fileio.h"  #include "fs-util.h"  #include "io-util.h" +#include "log.h" +#include "macro.h"  #include "parse-util.h" -#include "path-util.h"  #include "process-util.h"  #include "socket-util.h"  #include "stat-util.h" diff --git a/src/basic/terminal-util.h b/src/basic/terminal-util.h index b2c7a297ae..597a0060ad 100644 --- a/src/basic/terminal-util.h +++ b/src/basic/terminal-util.h @@ -22,6 +22,7 @@  #include <stdarg.h>  #include <stdbool.h>  #include <stdio.h> +#include <sys/types.h>  #include "macro.h"  #include "time-util.h" diff --git a/src/basic/time-util.c b/src/basic/time-util.c index b9da6991da..bfc7cf870c 100644 --- a/src/basic/time-util.c +++ b/src/basic/time-util.c @@ -19,20 +19,28 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <limits.h> +#include <stdlib.h>  #include <string.h> +#include <sys/stat.h> +#include <sys/time.h>  #include <sys/timerfd.h>  #include <sys/timex.h> +#include <sys/types.h> +#include <unistd.h>  #include "alloc-util.h"  #include "fd-util.h"  #include "fileio.h"  #include "fs-util.h" +#include "log.h" +#include "macro.h"  #include "parse-util.h"  #include "path-util.h"  #include "string-util.h"  #include "strv.h"  #include "time-util.h" -#include "util.h"  usec_t now(clockid_t clock_id) {          struct timespec ts; diff --git a/src/basic/time-util.h b/src/basic/time-util.h index 0417c29cdd..7321e3c670 100644 --- a/src/basic/time-util.h +++ b/src/basic/time-util.h @@ -22,6 +22,9 @@  ***/  #include <inttypes.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h>  #include <stdio.h>  #include <time.h> diff --git a/src/basic/unit-name.c b/src/basic/unit-name.c index 9a55eacbfb..5fc3b9d6fd 100644 --- a/src/basic/unit-name.c +++ b/src/basic/unit-name.c @@ -20,18 +20,20 @@  ***/  #include <errno.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h>  #include <string.h>  #include "alloc-util.h"  #include "bus-label.h" -#include "def.h"  #include "hexdecoct.h" +#include "macro.h"  #include "path-util.h"  #include "string-table.h"  #include "string-util.h"  #include "strv.h"  #include "unit-name.h" -#include "util.h"  #define VALID_CHARS                             \          DIGITS LETTERS                          \ diff --git a/src/basic/user-util.c b/src/basic/user-util.c index 397880b0b1..56e1a3be48 100644 --- a/src/basic/user-util.c +++ b/src/basic/user-util.c @@ -19,17 +19,27 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <alloca.h> +#include <errno.h> +#include <fcntl.h>  #include <grp.h>  #include <pwd.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h>  #include "alloc-util.h"  #include "fd-util.h" +#include "formats-util.h"  #include "macro.h"  #include "parse-util.h"  #include "path-util.h"  #include "string-util.h"  #include "user-util.h" -#include "util.h"  bool uid_is_valid(uid_t uid) { diff --git a/src/basic/utf8.c b/src/basic/utf8.c index b4063a4cec..124effd6df 100644 --- a/src/basic/utf8.c +++ b/src/basic/utf8.c @@ -44,15 +44,14 @@   */  #include <errno.h> -#include <inttypes.h>  #include <stdbool.h>  #include <stdlib.h>  #include <string.h>  #include "alloc-util.h"  #include "hexdecoct.h" +#include "macro.h"  #include "utf8.h" -#include "util.h"  bool unichar_is_valid(uint32_t ch) { diff --git a/src/basic/utf8.h b/src/basic/utf8.h index e745649f06..16c4b5b55d 100644 --- a/src/basic/utf8.h +++ b/src/basic/utf8.h @@ -22,6 +22,8 @@  ***/  #include <stdbool.h> +#include <stddef.h> +#include <stdint.h>  #include "macro.h" diff --git a/src/basic/util.c b/src/basic/util.c index 58617b354a..9e0b576283 100644 --- a/src/basic/util.c +++ b/src/basic/util.c @@ -19,91 +19,46 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -#include <ctype.h> +#include <alloca.h>  #include <dirent.h>  #include <errno.h>  #include <fcntl.h> -#include <grp.h> -#include <langinfo.h> -#include <libintl.h> -#include <limits.h> -#include <linux/magic.h> -#include <linux/oom.h> -#include <linux/sched.h> -#include <locale.h> -#include <poll.h> -#include <pwd.h>  #include <sched.h>  #include <signal.h>  #include <stdarg.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> -#include <sys/file.h> -#include <sys/ioctl.h>  #include <sys/mman.h> -#include <sys/mount.h> -#include <sys/personality.h>  #include <sys/prctl.h> -#include <sys/stat.h> -#include <sys/statvfs.h> -#include <sys/time.h> +#include <sys/statfs.h> +#include <sys/sysmacros.h>  #include <sys/types.h> -#include <sys/utsname.h> -#include <sys/vfs.h> -#include <sys/wait.h> -#include <syslog.h>  #include <unistd.h> -/* When we include libgen.h because we need dirname() we immediately - * undefine basename() since libgen.h defines it as a macro to the - * POSIX version which is really broken. We prefer GNU basename(). */ -#include <libgen.h> -#undef basename - -#ifdef HAVE_SYS_AUXV_H -#include <sys/auxv.h> -#endif - -/* We include linux/fs.h as last of the system headers, as it - * otherwise conflicts with sys/mount.h. Yay, Linux is great! */ -#include <linux/fs.h> -  #include "alloc-util.h"  #include "build.h"  #include "def.h" -#include "device-nodes.h"  #include "dirent-util.h" -#include "env-util.h" -#include "escape.h" -#include "exit-status.h"  #include "fd-util.h"  #include "fileio.h"  #include "formats-util.h" -#include "gunicode.h"  #include "hashmap.h" -#include "hexdecoct.h"  #include "hostname-util.h" -#include "ioprio.h"  #include "log.h"  #include "macro.h"  #include "missing.h" -#include "mkdir.h"  #include "parse-util.h"  #include "path-util.h"  #include "process-util.h" -#include "random-util.h" +#include "set.h"  #include "signal-util.h" -#include "sparse-endian.h"  #include "stat-util.h" -#include "string-table.h"  #include "string-util.h"  #include "strv.h" -#include "terminal-util.h" +#include "time-util.h"  #include "user-util.h" -#include "utf8.h"  #include "util.h" -#include "virt.h"  /* Put this test here for a lack of better place */  assert_cc(EAGAIN == EWOULDBLOCK); diff --git a/src/basic/util.h b/src/basic/util.h index d9d2f72b75..76a06822b7 100644 --- a/src/basic/util.h +++ b/src/basic/util.h @@ -22,6 +22,7 @@  ***/  #include <alloca.h> +#include <errno.h>  #include <fcntl.h>  #include <inttypes.h>  #include <limits.h> @@ -29,8 +30,10 @@  #include <stdarg.h>  #include <stdbool.h>  #include <stddef.h> +#include <stdint.h>  #include <stdio.h>  #include <stdlib.h> +#include <string.h>  #include <sys/inotify.h>  #include <sys/socket.h>  #include <sys/stat.h> diff --git a/src/basic/verbs.c b/src/basic/verbs.c index d63062d39e..7feb47c48e 100644 --- a/src/basic/verbs.c +++ b/src/basic/verbs.c @@ -19,8 +19,14 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <getopt.h> +#include <stdbool.h> +#include <stddef.h> + +#include "log.h" +#include "macro.h"  #include "string-util.h" -#include "util.h"  #include "verbs.h"  int dispatch_verb(int argc, char *argv[], const Verb verbs[], void *userdata) { diff --git a/src/basic/virt.c b/src/basic/virt.c index b82680a54b..0ffc2769d2 100644 --- a/src/basic/virt.c +++ b/src/basic/virt.c @@ -20,6 +20,8 @@  ***/  #include <errno.h> +#include <stdint.h> +#include <stdlib.h>  #include <string.h>  #include <unistd.h> @@ -27,11 +29,11 @@  #include "dirent-util.h"  #include "fd-util.h"  #include "fileio.h" +#include "macro.h"  #include "process-util.h"  #include "stat-util.h"  #include "string-table.h"  #include "string-util.h" -#include "util.h"  #include "virt.h"  static int detect_vm_cpuid(void) { diff --git a/src/basic/xattr-util.c b/src/basic/xattr-util.c index 6abdaedc3e..960209282f 100644 --- a/src/basic/xattr-util.c +++ b/src/basic/xattr-util.c @@ -19,13 +19,20 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <fcntl.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> +#include <sys/time.h>  #include <sys/xattr.h>  #include "alloc-util.h"  #include "fd-util.h" +#include "macro.h"  #include "sparse-endian.h"  #include "stdio-util.h" -#include "util.h" +#include "time-util.h"  #include "xattr-util.h"  int getxattr_malloc(const char *path, const char *name, char **value, bool allow_symlink) { diff --git a/src/basic/xattr-util.h b/src/basic/xattr-util.h index cf4cb12a25..a5134cba89 100644 --- a/src/basic/xattr-util.h +++ b/src/basic/xattr-util.h @@ -22,6 +22,7 @@  ***/  #include <stdbool.h> +#include <stddef.h>  #include <sys/types.h>  #include "time-util.h" diff --git a/src/basic/xml.c b/src/basic/xml.c index 8126bce212..b9976cf5f1 100644 --- a/src/basic/xml.c +++ b/src/basic/xml.c @@ -19,10 +19,12 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stddef.h>  #include <string.h> +#include "macro.h"  #include "string-util.h" -#include "util.h"  #include "xml.h"  enum { diff --git a/src/cgls/cgls.c b/src/cgls/cgls.c index 01140c73d8..12537ae85b 100644 --- a/src/cgls/cgls.c +++ b/src/cgls/cgls.c @@ -131,7 +131,9 @@ static int get_cgroup_root(char **ret) {          if (!arg_machine) {                  r = cg_get_root_path(ret); -                if (r < 0) +                if (r == -ENOMEDIUM) +                        return log_error_errno(r, "Failed to get root control group path: No cgroup filesystem mounted on /sys/fs/cgroup"); +                else if (r < 0)                          return log_error_errno(r, "Failed to get root control group path: %m");                  return 0; diff --git a/src/core/selinux-access.c b/src/core/selinux-access.c index 05655fc99a..3f3c5bf9fc 100644 --- a/src/core/selinux-access.c +++ b/src/core/selinux-access.c @@ -134,52 +134,45 @@ _printf_(2, 3) static int log_callback(int type, const char *fmt, ...) {  #endif          va_start(ap, fmt); -        log_internalv(LOG_AUTH | callback_type_to_priority(type), -                      0, __FILE__, __LINE__, __FUNCTION__, fmt, ap); +        log_internalv(LOG_AUTH | callback_type_to_priority(type), 0, __FILE__, __LINE__, __FUNCTION__, fmt, ap);          va_end(ap);          return 0;  } -/* -   Function must be called once to initialize the SELinux AVC environment. -   Sets up callbacks. -   If you want to cleanup memory you should need to call selinux_access_finish. -*/ -static int access_init(void) { -        int r = 0; +static int access_init(sd_bus_error *error) { -        if (avc_open(NULL, 0)) -                return log_error_errno(errno, "avc_open() failed: %m"); - -        selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback); -        selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback); +        if (!mac_selinux_use()) +                return 0; -        if (security_getenforce() < 0){ -                r = -errno; -                avc_destroy(); -        } +        if (initialized) +                return 1; -        return r; -} +        if (avc_open(NULL, 0) != 0) { +                int enforce, saved_errno = errno; -static int mac_selinux_access_init(sd_bus_error *error) { -        int r; +                enforce = security_getenforce(); +                log_full_errno(enforce != 0 ? LOG_ERR : LOG_WARNING, saved_errno, "Failed to open the SELinux AVC: %m"); -        if (initialized) -                return 0; +                /* If enforcement isn't on, then let's suppress this +                 * error, and just don't do any AVC checks. The +                 * warning we printed is hence all the admin will +                 * see. */ +                if (enforce == 0) +                        return 0; -        if (!mac_selinux_use()) -                return 0; +                /* Return an access denied error, if we couldn't load +                 * the AVC but enforcing mode was on, or we couldn't +                 * determine whether it is one. */ +                return sd_bus_error_setf(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to open the SELinux AVC: %s", strerror(saved_errno)); +        } -        r = access_init(); -        if (r < 0) -                return sd_bus_error_set(error, SD_BUS_ERROR_ACCESS_DENIED, "Failed to initialize SELinux."); +        selinux_set_callback(SELINUX_CB_AUDIT, (union selinux_callback) audit_callback); +        selinux_set_callback(SELINUX_CB_LOG, (union selinux_callback) log_callback);          initialized = true; -        return 0; +        return 1;  } -#endif  /*     This function communicates with the kernel to check whether or not it should @@ -193,7 +186,6 @@ int mac_selinux_generic_access_check(                  const char *permission,                  sd_bus_error *error) { -#ifdef HAVE_SELINUX          _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;          const char *tclass = NULL, *scon = NULL;          struct audit_info audit_info = {}; @@ -206,11 +198,8 @@ int mac_selinux_generic_access_check(          assert(permission);          assert(error); -        if (!mac_selinux_use()) -                return 0; - -        r = mac_selinux_access_init(error); -        if (r < 0) +        r = access_init(error); +        if (r <= 0)                  return r;          r = sd_bus_query_sender_creds( @@ -277,7 +266,17 @@ finish:          }          return r; +} +  #else + +int mac_selinux_generic_access_check( +                sd_bus_message *message, +                const char *path, +                const char *permission, +                sd_bus_error *error) { +          return 0; -#endif  } + +#endif diff --git a/src/hostname/hostnamed.c b/src/hostname/hostnamed.c index e1fbacd11b..d383041d39 100644 --- a/src/hostname/hostnamed.c +++ b/src/hostname/hostnamed.c @@ -212,10 +212,10 @@ try_dmi:             unreliable enough, so let's not do any additional guesswork             on top of that. -           See the SMBIOS Specification 2.7.1 section 7.4.1 for +           See the SMBIOS Specification 4.0 section 7.4.1 for             details about the values listed here: -           http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.1.pdf +           https://www.dmtf.org/sites/default/files/standards/documents/DSP0134_3.0.0.pdf           */          switch (t) { @@ -237,7 +237,11 @@ try_dmi:          case 0x11:          case 0x1C: +        case 0x1D:                  return "server"; + +        case 0x1E: +                return "tablet";          }          return NULL; diff --git a/src/journal/compress.c b/src/journal/compress.c index e1ca0a8818..1a3d2cdd80 100644 --- a/src/journal/compress.c +++ b/src/journal/compress.c @@ -201,7 +201,7 @@ int decompress_blob_lz4(const void *src, uint64_t src_size,                  return -EBADMSG;          size = le64toh( *(le64_t*)src ); -        if (size < 0 || (le64_t) size != *(le64_t*)src) +        if (size < 0 || (unsigned) size != le64toh(*(le64_t*)src))                  return -EFBIG;          if ((size_t) size > *dst_alloc_size) {                  out = realloc(*dst, size); diff --git a/src/journal/journal-send.c b/src/journal/journal-send.c index fa5dee73c3..44fa11a00e 100644 --- a/src/journal/journal-send.c +++ b/src/journal/journal-send.c @@ -225,8 +225,8 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {          assert_return(iov, -EINVAL);          assert_return(n > 0, -EINVAL); -        w = alloca(sizeof(struct iovec) * n * 5 + 3); -        l = alloca(sizeof(uint64_t) * n); +        w = newa(struct iovec, n * 5 + 3); +        l = newa(uint64_t, n);          for (i = 0; i < n; i++) {                  char *c, *nl; @@ -337,7 +337,11 @@ _public_ int sd_journal_sendv(const struct iovec *iov, int n) {                          return r;          } -        return send_one_fd(fd, buffer_fd, 0); +        r = send_one_fd_sa(fd, buffer_fd, mh.msg_name, mh.msg_namelen, 0); +        if (r == -ENOENT) +                /* Fail silently if the journal is not available */ +                return 0; +        return r;  }  static int fill_iovec_perror_and_send(const char *message, int skip, struct iovec iov[]) { diff --git a/src/journal/journald-native.c b/src/journal/journald-native.c index 69a685c06f..371df5b37f 100644 --- a/src/journal/journald-native.c +++ b/src/journal/journald-native.c @@ -480,7 +480,7 @@ int server_open_native_socket(Server*s) {                  return log_error_errno(errno, "SO_PASSCRED failed: %m");  #ifdef HAVE_SELINUX -        if (mac_selinux_use()) { +        if (mac_selinux_have()) {                  r = setsockopt(s->native_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));                  if (r < 0)                          log_warning_errno(errno, "SO_PASSSEC failed: %m"); diff --git a/src/journal/journald-server.c b/src/journal/journald-server.c index 7d11a568aa..a8a9b72080 100644 --- a/src/journal/journald-server.c +++ b/src/journal/journald-server.c @@ -204,58 +204,19 @@ static int determine_space(Server *s, bool verbose, bool patch_min_use, uint64_t          return determine_space_for(s, metrics, path, name, verbose, patch_min_use, available, limit);  } -void server_fix_perms(Server *s, JournalFile *f, uid_t uid) { -        int r; +static void server_add_acls(JournalFile *f, uid_t uid) {  #ifdef HAVE_ACL -        _cleanup_(acl_freep) acl_t acl = NULL; -        acl_entry_t entry; -        acl_permset_t permset; +        int r;  #endif -          assert(f); -        r = fchmod(f->fd, 0640); -        if (r < 0) -                log_warning_errno(errno, "Failed to fix access mode on %s, ignoring: %m", f->path); -  #ifdef HAVE_ACL          if (uid <= SYSTEM_UID_MAX)                  return; -        acl = acl_get_fd(f->fd); -        if (!acl) { -                log_warning_errno(errno, "Failed to read ACL on %s, ignoring: %m", f->path); -                return; -        } - -        r = acl_find_uid(acl, uid, &entry); -        if (r <= 0) { - -                if (acl_create_entry(&acl, &entry) < 0 || -                    acl_set_tag_type(entry, ACL_USER) < 0 || -                    acl_set_qualifier(entry, &uid) < 0) { -                        log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path); -                        return; -                } -        } - -        /* We do not recalculate the mask unconditionally here, -         * so that the fchmod() mask above stays intact. */ -        if (acl_get_permset(entry, &permset) < 0 || -            acl_add_perm(permset, ACL_READ) < 0) { -                log_warning_errno(errno, "Failed to patch ACL on %s, ignoring: %m", f->path); -                return; -        } - -        r = calc_acl_mask_if_needed(&acl); -        if (r < 0) { -                log_warning_errno(r, "Failed to patch ACL on %s, ignoring: %m", f->path); -                return; -        } - -        if (acl_set_fd(f->fd, acl) < 0) -                log_warning_errno(errno, "Failed to set ACL on %s, ignoring: %m", f->path); - +        r = add_acls_for_user(f->fd, uid); +        if (r < 0) +                log_warning_errno(r, "Failed to set ACL on %s, ignoring: %m", f->path);  #endif  } @@ -301,7 +262,7 @@ static JournalFile* find_journal(Server *s, uid_t uid) {          if (r < 0)                  return s->system_journal; -        server_fix_perms(s, f, uid); +        server_add_acls(f, uid);          r = ordered_hashmap_put(s->user_journals, UID_TO_PTR(uid), f);          if (r < 0) { @@ -332,7 +293,7 @@ static int do_rotate(                  else                          log_error_errno(r, "Failed to create new %s journal: %m", name);          else -                server_fix_perms(s, *f, uid); +                server_add_acls(*f, uid);          return r;  } @@ -707,7 +668,7 @@ static void dispatch_message_real(                  }  #ifdef HAVE_SELINUX -                if (mac_selinux_use()) { +                if (mac_selinux_have()) {                          if (label) {                                  x = alloca(strlen("_SELINUX_CONTEXT=") + label_len + 1); @@ -971,7 +932,7 @@ static int system_journal_open(Server *s, bool flush_requested) {                  fn = strjoina(fn, "/system.journal");                  r = journal_file_open_reliably(fn, O_RDWR|O_CREAT, 0640, s->compress, s->seal, &s->system_metrics, s->mmap, NULL, &s->system_journal);                  if (r >= 0) { -                        server_fix_perms(s, s->system_journal, 0); +                        server_add_acls(s->system_journal, 0);                          (void) determine_space_for(s, &s->system_metrics, "/var/log/journal/", "System journal", true, true, NULL, NULL);                  } else if (r < 0) {                          if (r != -ENOENT && r != -EROFS) @@ -1015,7 +976,7 @@ static int system_journal_open(Server *s, bool flush_requested) {                  }                  if (s->runtime_journal) { -                        server_fix_perms(s, s->runtime_journal, 0); +                        server_add_acls(s->runtime_journal, 0);                          (void) determine_space_for(s, &s->runtime_metrics, "/run/log/journal/", "Runtime journal", true, true, NULL, NULL);                  }          } diff --git a/src/journal/journald-server.h b/src/journal/journald-server.h index dcc21bb7c3..1822765228 100644 --- a/src/journal/journald-server.h +++ b/src/journal/journald-server.h @@ -174,7 +174,6 @@ int config_parse_split_mode(const char *unit, const char *filename, unsigned lin  const char *split_mode_to_string(SplitMode s) _const_;  SplitMode split_mode_from_string(const char *s) _pure_; -void server_fix_perms(Server *s, JournalFile *f, uid_t uid);  int server_init(Server *s);  void server_done(Server *s);  void server_sync(Server *s); diff --git a/src/journal/journald-stream.c b/src/journal/journald-stream.c index 07a0f1bf41..131fcdac42 100644 --- a/src/journal/journald-stream.c +++ b/src/journal/journald-stream.c @@ -493,7 +493,7 @@ static int stdout_stream_install(Server *s, int fd, StdoutStream **ret) {          if (r < 0)                  return log_error_errno(r, "Failed to determine peer credentials: %m"); -        if (mac_selinux_use()) { +        if (mac_selinux_have()) {                  r = getpeersec(fd, &stream->label);                  if (r < 0 && r != -EOPNOTSUPP)                          (void) log_warning_errno(r, "Failed to determine peer security context: %m"); diff --git a/src/journal/journald-syslog.c b/src/journal/journald-syslog.c index f3ac1a7ae0..cfc50d889b 100644 --- a/src/journal/journald-syslog.c +++ b/src/journal/journald-syslog.c @@ -415,7 +415,7 @@ int server_open_syslog_socket(Server *s) {                  return log_error_errno(errno, "SO_PASSCRED failed: %m");  #ifdef HAVE_SELINUX -        if (mac_selinux_use()) { +        if (mac_selinux_have()) {                  r = setsockopt(s->syslog_fd, SOL_SOCKET, SO_PASSSEC, &one, sizeof(one));                  if (r < 0)                          log_warning_errno(errno, "SO_PASSSEC failed: %m"); diff --git a/src/journal/test-journal-send.c b/src/journal/test-journal-send.c index 694376670d..e537c1fe5f 100644 --- a/src/journal/test-journal-send.c +++ b/src/journal/test-journal-send.c @@ -19,59 +19,84 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <stdlib.h>  #include <unistd.h>  #include "sd-journal.h" -#include "log.h" +#include "macro.h"  int main(int argc, char *argv[]) {          char huge[4096*1024]; -        log_set_max_level(LOG_DEBUG); - -        sd_journal_print(LOG_INFO, "piepapo"); - -        sd_journal_send("MESSAGE=foobar", -                        "VALUE=%i", 7, -                        NULL); +        /* utf-8 and non-utf-8, message-less and message-ful iovecs */ +        struct iovec graph1[] = { +                {(char*) "GRAPH=graph", strlen("GRAPH=graph")} +        }; +        struct iovec graph2[] = { +                {(char*) "GRAPH=graph\n", strlen("GRAPH=graph\n")} +        }; +        struct iovec message1[] = { +                {(char*) "MESSAGE=graph", strlen("MESSAGE=graph")} +        }; +        struct iovec message2[] = { +                {(char*) "MESSAGE=graph\n", strlen("MESSAGE=graph\n")} +        }; + +        assert_se(sd_journal_print(LOG_INFO, "piepapo") == 0); + +        assert_se(sd_journal_send("MESSAGE=foobar", +                                  "VALUE=%i", 7, +                                  NULL) == 0);          errno = ENOENT; -        sd_journal_perror("Foobar"); +        assert_se(sd_journal_perror("Foobar") == 0); -        sd_journal_perror(""); +        assert_se(sd_journal_perror("") == 0);          memset(huge, 'x', sizeof(huge));          memcpy(huge, "HUGE=", 5);          char_array_0(huge); -        sd_journal_send("MESSAGE=Huge field attached", -                        huge, -                        NULL); +        assert_se(sd_journal_send("MESSAGE=Huge field attached", +                                  huge, +                                  NULL) == 0); -        sd_journal_send("MESSAGE=uiui", -                        "VALUE=A", -                        "VALUE=B", -                        "VALUE=C", -                        "SINGLETON=1", -                        "OTHERVALUE=X", -                        "OTHERVALUE=Y", -                        "WITH_BINARY=this is a binary value \a", -                        NULL); +        assert_se(sd_journal_send("MESSAGE=uiui", +                                  "VALUE=A", +                                  "VALUE=B", +                                  "VALUE=C", +                                  "SINGLETON=1", +                                  "OTHERVALUE=X", +                                  "OTHERVALUE=Y", +                                  "WITH_BINARY=this is a binary value \a", +                                  NULL) == 0);          syslog(LOG_NOTICE, "Hello World!"); -        sd_journal_print(LOG_NOTICE, "Hello World"); - -        sd_journal_send("MESSAGE=Hello World!", -                        "MESSAGE_ID=52fb62f99e2c49d89cfbf9d6de5e3555", -                        "PRIORITY=5", -                        "HOME=%s", getenv("HOME"), -                        "TERM=%s", getenv("TERM"), -                        "PAGE_SIZE=%li", sysconf(_SC_PAGESIZE), -                        "N_CPUS=%li", sysconf(_SC_NPROCESSORS_ONLN), -                        NULL); +        assert_se(sd_journal_print(LOG_NOTICE, "Hello World") == 0); + +        assert_se(sd_journal_send("MESSAGE=Hello World!", +                                  "MESSAGE_ID=52fb62f99e2c49d89cfbf9d6de5e3555", +                                  "PRIORITY=5", +                                  "HOME=%s", getenv("HOME"), +                                  "TERM=%s", getenv("TERM"), +                                  "PAGE_SIZE=%li", sysconf(_SC_PAGESIZE), +                                  "N_CPUS=%li", sysconf(_SC_NPROCESSORS_ONLN), +                                  NULL) == 0); + +        assert_se(sd_journal_sendv(graph1, 1) == 0); +        assert_se(sd_journal_sendv(graph2, 1) == 0); +        assert_se(sd_journal_sendv(message1, 1) == 0); +        assert_se(sd_journal_sendv(message2, 1) == 0); + +        /* test without location fields */ +#undef sd_journal_sendv +        assert_se(sd_journal_sendv(graph1, 1) == 0); +        assert_se(sd_journal_sendv(graph2, 1) == 0); +        assert_se(sd_journal_sendv(message1, 1) == 0); +        assert_se(sd_journal_sendv(message2, 1) == 0);          sleep(1); diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index a03c8460a8..4521f8f0b1 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -554,7 +554,7 @@ static int client_append_fqdn_option(DHCPMessage *message, size_t optlen, size_t          buffer[1] = 0;                 /* RCODE1 (deprecated) */          buffer[2] = 0;                 /* RCODE2 (deprecated) */ -        r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3); +        r = dns_name_to_wire_format(fqdn, buffer + 3, sizeof(buffer) - 3, false);          if (r > 0)                  r = dhcp_option_append(message, optlen, optoffset, 0,                                         DHCP_OPTION_FQDN, 3 + r, buffer); diff --git a/src/libsystemd/sd-bus/bus-socket.c b/src/libsystemd/sd-bus/bus-socket.c index 25873dea1e..1df571ac92 100644 --- a/src/libsystemd/sd-bus/bus-socket.c +++ b/src/libsystemd/sd-bus/bus-socket.c @@ -609,7 +609,7 @@ static void bus_get_peercred(sd_bus *b) {          b->ucred_valid = getpeercred(b->input_fd, &b->ucred) >= 0;          /* Get the SELinux context of the peer */ -        if (mac_selinux_use()) { +        if (mac_selinux_have()) {                  r = getpeersec(b->input_fd, &b->label);                  if (r < 0 && r != -EOPNOTSUPP)                          log_debug_errno(r, "Failed to determine peer security context: %m"); diff --git a/src/libsystemd/sd-bus/test-bus-creds.c b/src/libsystemd/sd-bus/test-bus-creds.c index 500fffc5ce..8003501059 100644 --- a/src/libsystemd/sd-bus/test-bus-creds.c +++ b/src/libsystemd/sd-bus/test-bus-creds.c @@ -29,7 +29,7 @@ int main(int argc, char *argv[]) {          _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;          int r; -        if (cg_unified() == -ENOEXEC) { +        if (cg_unified() == -ENOMEDIUM) {                  puts("Skipping test: /sys/fs/cgroup/ not available");                  return EXIT_TEST_SKIP;          } diff --git a/src/libudev/libudev-device-private.c b/src/libudev/libudev-device-private.c index 2d3e62410c..2aae0726c1 100644 --- a/src/libudev/libudev-device-private.c +++ b/src/libudev/libudev-device-private.c @@ -137,14 +137,10 @@ gid_t udev_device_get_devnode_gid(struct udev_device *udev_device) {  }  void udev_device_ensure_usec_initialized(struct udev_device *udev_device, struct udev_device *udev_device_old) { -        sd_device *device_old = NULL; -          assert(udev_device); -        if (udev_device_old) -                device_old = udev_device_old->device; - -        device_ensure_usec_initialized(udev_device->device, device_old); +        device_ensure_usec_initialized(udev_device->device, +                                       udev_device_old ? udev_device_old->device : NULL);  }  char **udev_device_get_properties_envp(struct udev_device *udev_device) { diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index d0875cf930..c1643cf41a 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -1820,7 +1820,7 @@ static int nologin_timeout_handler(          log_info("Creating /run/nologin, blocking further logins..."); -        r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); +        r = write_string_file_atomic_label("/run/nologin", "System is going down.");          if (r < 0)                  log_error_errno(r, "Failed to create /run/nologin: %m");          else diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 49e574b6ca..c6b5b1ec44 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -1325,6 +1325,10 @@ int manager_start_scope(          if (r < 0)                  return r; +        r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", 8192); +        if (r < 0) +                return bus_log_create_error(r); +          if (more_properties) {                  r = sd_bus_message_copy(m, more_properties, true);                  if (r < 0) diff --git a/src/nspawn/nspawn-register.c b/src/nspawn/nspawn-register.c index d6c0200c0c..65ca9c762b 100644 --- a/src/nspawn/nspawn-register.c +++ b/src/nspawn/nspawn-register.c @@ -105,10 +105,6 @@ int register_machine(                                  return bus_log_create_error(r);                  } -                r = sd_bus_message_append(m, "(sv)", "TasksMax", "t", 8192); -                if (r < 0) -                        return bus_log_create_error(r); -                  r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "strict");                  if (r < 0)                          return bus_log_create_error(r); diff --git a/src/resolve-host/resolve-host.c b/src/resolve-host/resolve-host.c index 36dfc70e00..0f154d9798 100644 --- a/src/resolve-host/resolve-host.c +++ b/src/resolve-host/resolve-host.c @@ -67,6 +67,8 @@ static void print_source(uint64_t flags, usec_t rtt) {          fputc('.', stdout);          fputc('\n', stdout); + +        printf("-- Data is authenticated: %s\n", yes_no(flags & SD_RESOLVED_AUTHENTICATED));  }  static int resolve_host(sd_bus *bus, const char *name) { diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index f86c4ceb05..0ceca56371 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -197,7 +197,7 @@ static void bus_method_resolve_hostname_complete(DnsQuery *q) {          r = sd_bus_message_append(                          reply, "st",                          DNS_RESOURCE_KEY_NAME(canonical->key), -                        SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); +                        SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));          if (r < 0)                  goto finish; @@ -344,7 +344,7 @@ static void bus_method_resolve_address_complete(DnsQuery *q) {          if (r < 0)                  goto finish; -        r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); +        r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));          if (r < 0)                  goto finish; @@ -425,8 +425,6 @@ fail:  }  static int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int ifindex) { -        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; -        size_t start;          int r;          assert(m); @@ -443,17 +441,11 @@ static int bus_message_append_rr(sd_bus_message *m, DnsResourceRecord *rr, int i          if (r < 0)                  return r; -        r = dns_packet_new(&p, DNS_PROTOCOL_DNS, 0); +        r = dns_resource_record_to_wire_format(rr, false);          if (r < 0)                  return r; -        p->refuse_compression = true; - -        r = dns_packet_append_rr(p, rr, &start); -        if (r < 0) -                return r; - -        r = sd_bus_message_append_array(m, 'y', DNS_PACKET_DATA(p) + start, p->size - start); +        r = sd_bus_message_append_array(m, 'y', rr->wire_format, rr->wire_format_size);          if (r < 0)                  return r; @@ -518,7 +510,7 @@ static void bus_method_resolve_record_complete(DnsQuery *q) {          if (r < 0)                  goto finish; -        r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); +        r = sd_bus_message_append(reply, "t", SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));          if (r < 0)                  goto finish; @@ -867,7 +859,7 @@ static void resolve_service_all_complete(DnsQuery *q) {                          reply,                          "ssst",                          name, type, domain, -                        SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family)); +                        SD_RESOLVED_FLAGS_MAKE(q->answer_protocol, q->answer_family, q->answer_authenticated));          if (r < 0)                  goto finish; diff --git a/src/resolve/resolved-conf.c b/src/resolve/resolved-conf.c index 3fc7d9ae3d..1b2f3e336e 100644 --- a/src/resolve/resolved-conf.c +++ b/src/resolve/resolved-conf.c @@ -234,6 +234,41 @@ int config_parse_support(          return 0;  } +int config_parse_dnssec( +                const char *unit, +                const char *filename, +                unsigned line, +                const char *section, +                unsigned section_line, +                const char *lvalue, +                int ltype, +                const char *rvalue, +                void *data, +                void *userdata) { + +        Manager *m = data; +        DnssecMode mode; +        int r; + +        assert(filename); +        assert(lvalue); +        assert(rvalue); + +        mode = dnssec_mode_from_string(rvalue); +        if (mode < 0) { +                r = parse_boolean(rvalue); +                if (r < 0) { +                        log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse DNSSEC mode '%s'. Ignoring.", rvalue); +                        return 0; +                } + +                mode = r ? DNSSEC_YES : DNSSEC_NO; +        } + +        m->unicast_scope->dnssec_mode = mode; +        return 0; +} +  int manager_parse_config_file(Manager *m) {          int r; diff --git a/src/resolve/resolved-conf.h b/src/resolve/resolved-conf.h index 28d2549d35..668ea02bba 100644 --- a/src/resolve/resolved-conf.h +++ b/src/resolve/resolved-conf.h @@ -36,3 +36,4 @@ const struct ConfigPerfItem* resolved_gperf_lookup(const char *key, unsigned len  int config_parse_dns_servers(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);  int config_parse_search_domains(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata);  int config_parse_support(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); +int config_parse_dnssec(const char *unit, const char *filename, unsigned line, const char *section, unsigned section_line, const char *lvalue, int ltype, const char *rvalue, void *data, void *userdata); diff --git a/src/resolve/resolved-def.h b/src/resolve/resolved-def.h index be29f51663..6014d345f3 100644 --- a/src/resolve/resolved-def.h +++ b/src/resolve/resolved-def.h @@ -24,10 +24,15 @@  #define SD_RESOLVED_DNS           (UINT64_C(1) << 0)  #define SD_RESOLVED_LLMNR_IPV4    (UINT64_C(1) << 1)  #define SD_RESOLVED_LLMNR_IPV6    (UINT64_C(1) << 2) +#define SD_RESOLVED_MDNS_IPV4     (UINT64_C(1) << 3) +#define SD_RESOLVED_MDNS_IPV6     (UINT64_C(1) << 4)  #define SD_RESOLVED_NO_CNAME      (UINT64_C(1) << 5)  #define SD_RESOLVED_NO_TXT        (UINT64_C(1) << 6)  #define SD_RESOLVED_NO_ADDRESS    (UINT64_C(1) << 7)  #define SD_RESOLVED_NO_SEARCH     (UINT64_C(1) << 8) +#define SD_RESOLVED_AUTHENTICATED (UINT64_C(1) << 9)  #define SD_RESOLVED_LLMNR         (SD_RESOLVED_LLMNR_IPV4|SD_RESOLVED_LLMNR_IPV6) -#define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_LLMNR|SD_RESOLVED_DNS) +#define SD_RESOLVED_MDNS          (SD_RESOLVED_MDNS_IPV4|SD_RESOLVED_MDNS_IPV6) + +#define SD_RESOLVED_PROTOCOLS_ALL (SD_RESOLVED_MDNS|SD_RESOLVED_LLMNR|SD_RESOLVED_DNS) diff --git a/src/resolve/resolved-dns-answer.h b/src/resolve/resolved-dns-answer.h index 8814919deb..89c254b02e 100644 --- a/src/resolve/resolved-dns-answer.h +++ b/src/resolve/resolved-dns-answer.h @@ -24,6 +24,7 @@  typedef struct DnsAnswer DnsAnswer;  typedef struct DnsAnswerItem DnsAnswerItem; +#include "macro.h"  #include "resolved-dns-rr.h"  /* A simple array of resource records. We keep track of the @@ -59,19 +60,23 @@ int dns_answer_reserve(DnsAnswer **a, unsigned n_free);  DEFINE_TRIVIAL_CLEANUP_FUNC(DnsAnswer*, dns_answer_unref); -#define DNS_ANSWER_FOREACH(kk, a)                                       \ -        for (unsigned _i = ({                                           \ +#define _DNS_ANSWER_FOREACH(q, kk, a)                                   \ +        for (unsigned UNIQ_T(i, q) = ({                                 \                                  (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \                                  0;                                      \ -                           });                                          \ -             (a) && ((_i) < (a)->n_rrs);                                \ -             _i++, (kk) = (_i < (a)->n_rrs ? (a)->items[_i].rr : NULL)) +                        });                                             \ +             (a) && (UNIQ_T(i, q) < (a)->n_rrs);                        \ +             UNIQ_T(i, q)++, (kk) = (UNIQ_T(i, q) < (a)->n_rrs ? (a)->items[UNIQ_T(i, q)].rr : NULL)) -#define DNS_ANSWER_FOREACH_IFINDEX(kk, ifindex, a)                      \ -        for (unsigned _i = ({                                           \ +#define DNS_ANSWER_FOREACH(kk, a) _DNS_ANSWER_FOREACH(UNIQ, kk, a) + +#define _DNS_ANSWER_FOREACH_IFINDEX(q, kk, ifindex, a)                  \ +        for (unsigned UNIQ_T(i, q) = ({                                 \                                  (kk) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].rr : NULL; \                                  (ifindex) = ((a) && (a)->n_rrs > 0) ? (a)->items[0].ifindex : 0; \                                  0;                                      \ -                           });                                          \ -             (a) && ((_i) < (a)->n_rrs);                                \ -             _i++, (kk) = ((_i < (a)->n_rrs) ? (a)->items[_i].rr : NULL), (ifindex) = ((_i < (a)->n_rrs) ? (a)->items[_i].ifindex : 0)) +                        });                                             \ +             (a) && (UNIQ_T(i, q) < (a)->n_rrs);                        \ +             UNIQ_T(i, q)++, (kk) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].rr : NULL), (ifindex) = ((UNIQ_T(i, q) < (a)->n_rrs) ? (a)->items[UNIQ_T(i, q)].ifindex : 0)) + +#define DNS_ANSWER_FOREACH_IFINDEX(kk, ifindex, a) _DNS_ANSWER_FOREACH_IFINDEX(UNIQ, kk, ifindex, a) diff --git a/src/resolve/resolved-dns-cache.c b/src/resolve/resolved-dns-cache.c index d963ce6e00..1774ae6cb8 100644 --- a/src/resolve/resolved-dns-cache.c +++ b/src/resolve/resolved-dns-cache.c @@ -46,6 +46,7 @@ struct DnsCacheItem {          usec_t until;          DnsCacheItemType type;          unsigned prioq_idx; +        bool authenticated;          int owner_family;          union in_addr_union owner_address;          LIST_FIELDS(DnsCacheItem, by_key); @@ -237,7 +238,7 @@ static DnsCacheItem* dns_cache_get(DnsCache *c, DnsResourceRecord *rr) {          return NULL;  } -static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsResourceRecord *rr, usec_t timestamp) { +static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsResourceRecord *rr, bool authenticated, usec_t timestamp) {          assert(c);          assert(i);          assert(rr); @@ -257,6 +258,7 @@ static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsReso          dns_resource_key_unref(i->key);          i->key = dns_resource_key_ref(rr->key); +        i->authenticated = authenticated;          i->until = timestamp + MIN(rr->ttl * USEC_PER_SEC, CACHE_TTL_MAX_USEC);          prioq_reshuffle(c->by_expiry, i, &i->prioq_idx); @@ -265,6 +267,7 @@ static void dns_cache_item_update_positive(DnsCache *c, DnsCacheItem *i, DnsReso  static int dns_cache_put_positive(                  DnsCache *c,                  DnsResourceRecord *rr, +                bool authenticated,                  usec_t timestamp,                  int owner_family,                  const union in_addr_union *owner_address) { @@ -300,7 +303,7 @@ static int dns_cache_put_positive(          /* Entry exists already? Update TTL and timestamp */          existing = dns_cache_get(c, rr);          if (existing) { -                dns_cache_item_update_positive(c, existing, rr, timestamp); +                dns_cache_item_update_positive(c, existing, rr, authenticated, timestamp);                  return 0;          } @@ -322,6 +325,7 @@ static int dns_cache_put_positive(          i->prioq_idx = PRIOQ_IDX_NULL;          i->owner_family = owner_family;          i->owner_address = *owner_address; +        i->authenticated = authenticated;          r = dns_cache_link_item(c, i);          if (r < 0) @@ -341,6 +345,7 @@ static int dns_cache_put_negative(                  DnsCache *c,                  DnsResourceKey *key,                  int rcode, +                bool authenticated,                  usec_t timestamp,                  uint32_t soa_ttl,                  int owner_family, @@ -389,6 +394,7 @@ static int dns_cache_put_negative(          i->prioq_idx = PRIOQ_IDX_NULL;          i->owner_family = owner_family;          i->owner_address = *owner_address; +        i->authenticated = authenticated;          r = dns_cache_link_item(c, i);          if (r < 0) @@ -410,6 +416,7 @@ int dns_cache_put(                  int rcode,                  DnsAnswer *answer,                  unsigned max_rrs, +                bool authenticated,                  usec_t timestamp,                  int owner_family,                  const union in_addr_union *owner_address) { @@ -452,7 +459,12 @@ int dns_cache_put(          /* Second, add in positive entries for all contained RRs */          for (i = 0; i < MIN(max_rrs, answer->n_rrs); i++) { -                r = dns_cache_put_positive(c, answer->items[i].rr, timestamp, owner_family, owner_address); +                DnsResourceRecord *rr = answer->items[i].rr; + +                if (rr->key->cache_flush) +                        dns_cache_remove(c, rr->key); + +                r = dns_cache_put_positive(c, rr, authenticated, timestamp, owner_family, owner_address);                  if (r < 0)                          goto fail;          } @@ -496,13 +508,13 @@ int dns_cache_put(                          if (!dns_answer_match_soa(canonical_key, soa->key))                                  continue; -                        r = dns_cache_put_negative(c, canonical_key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address); +                        r = dns_cache_put_negative(c, canonical_key, rcode, authenticated, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address);                          if (r < 0)                                  goto fail;                  }          } -        r = dns_cache_put_negative(c, key, rcode, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address); +        r = dns_cache_put_negative(c, key, rcode, authenticated, timestamp, MIN(soa->soa.minimum, soa->ttl), owner_family, owner_address);          if (r < 0)                  goto fail; @@ -521,8 +533,7 @@ fail:          return r;  } -static DnsCacheItem *dns_cache_get_by_key_follow_cname(DnsCache *c, DnsResourceKey *k) { -        _cleanup_(dns_resource_key_unrefp) DnsResourceKey *cname_key = NULL; +static DnsCacheItem *dns_cache_get_by_key_follow_cname_dname_nsec(DnsCache *c, DnsResourceKey *k) {          DnsCacheItem *i;          const char *n;          int r; @@ -534,32 +545,29 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname(DnsCache *c, DnsResourceK           * much, after all this is just a cache */          i = hashmap_get(c->by_key, k); -        if (i || k->type == DNS_TYPE_CNAME || k->type == DNS_TYPE_DNAME) +        if (i || IN_SET(k->type, DNS_TYPE_CNAME, DNS_TYPE_DNAME, DNS_TYPE_NSEC))                  return i; -        /* Check if we have a CNAME record instead */ -        cname_key = dns_resource_key_new_cname(k); -        if (!cname_key) -                return NULL; +        n = DNS_RESOURCE_KEY_NAME(k); -        i = hashmap_get(c->by_key, cname_key); +        /* Check if we have an NSEC record instead for the name. */ +        i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_NSEC, n)); +        if (i) +                return i; + +        /* Check if we have a CNAME record instead */ +        i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_CNAME, n));          if (i)                  return i;          /* OK, let's look for cached DNAME records. */ -        n = DNS_RESOURCE_KEY_NAME(k);          for (;;) { -                _cleanup_(dns_resource_key_unrefp) DnsResourceKey *dname_key = NULL;                  char label[DNS_LABEL_MAX];                  if (isempty(n))                          return NULL; -                dname_key = dns_resource_key_new(k->class, DNS_TYPE_DNAME, n); -                if (!dname_key) -                        return NULL; - -                i = hashmap_get(c->by_key, dname_key); +                i = hashmap_get(c->by_key, &DNS_RESOURCE_KEY_CONST(k->class, DNS_TYPE_DNAME, n));                  if (i)                          return i; @@ -572,23 +580,26 @@ static DnsCacheItem *dns_cache_get_by_key_follow_cname(DnsCache *c, DnsResourceK          return NULL;  } -int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret) { +int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **ret, bool *authenticated) {          _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL;          unsigned n = 0;          int r;          bool nxdomain = false;          _cleanup_free_ char *key_str = NULL; -        DnsCacheItem *j, *first; +        DnsCacheItem *j, *first, *nsec = NULL; +        bool have_authenticated = false, have_non_authenticated = false;          assert(c);          assert(key);          assert(rcode);          assert(ret); +        assert(authenticated);          if (key->type == DNS_TYPE_ANY ||              key->class == DNS_CLASS_ANY) { -                /* If we have ANY lookups we simply refresh */ +                /* If we have ANY lookups we don't use the cache, so +                 * that the caller refreshes via the network. */                  r = dns_resource_key_to_string(key, &key_str);                  if (r < 0) @@ -601,7 +612,7 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r                  return 0;          } -        first = dns_cache_get_by_key_follow_cname(c, key); +        first = dns_cache_get_by_key_follow_cname_dname_nsec(c, key);          if (!first) {                  /* If one question cannot be answered we need to refresh */ @@ -617,24 +628,49 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r          }          LIST_FOREACH(by_key, j, first) { -                if (j->rr) +                if (j->rr) { +                        if (j->rr->key->type == DNS_TYPE_NSEC) +                                nsec = j; +                          n++; -                else if (j->type == DNS_CACHE_NXDOMAIN) +                } else if (j->type == DNS_CACHE_NXDOMAIN)                          nxdomain = true; + +                if (j->authenticated) +                        have_authenticated = true; +                else +                        have_non_authenticated = true;          }          r = dns_resource_key_to_string(key, &key_str);          if (r < 0)                  return r; +        if (nsec && key->type != DNS_TYPE_NSEC) { +                log_debug("NSEC NODATA cache hit for %s", key_str); + +                /* We only found an NSEC record that matches our name. +                 * If it says the type doesn't exit report +                 * NODATA. Otherwise report a cache miss. */ + +                *ret = NULL; +                *rcode = DNS_RCODE_SUCCESS; +                *authenticated = nsec->authenticated; + +                return !bitmap_isset(nsec->rr->nsec.types, key->type) && +                       !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_CNAME) && +                       !bitmap_isset(nsec->rr->nsec.types, DNS_TYPE_DNAME); +        } +          log_debug("%s cache hit for %s", -                  nxdomain ? "NXDOMAIN" : -                     n > 0 ? "Positive" : "NODATA", +                  n > 0    ? "Positive" : +                  nxdomain ? "NXDOMAIN" : "NODATA",                    key_str);          if (n <= 0) {                  *ret = NULL;                  *rcode = nxdomain ? DNS_RCODE_NXDOMAIN : DNS_RCODE_SUCCESS; +                *authenticated = have_authenticated && !have_non_authenticated;                  return 1;          } @@ -653,6 +689,7 @@ int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **r          *ret = answer;          *rcode = DNS_RCODE_SUCCESS; +        *authenticated = have_authenticated && !have_non_authenticated;          answer = NULL;          return n; @@ -694,6 +731,57 @@ int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_          return 1;  } +int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p) { +        unsigned ancount = 0; +        Iterator iterator; +        DnsCacheItem *i; +        int r; + +        assert(cache); +        assert(p); + +        HASHMAP_FOREACH(i, cache->by_key, iterator) { +                DnsCacheItem *j; + +                LIST_FOREACH(by_key, j, i) { +                        _cleanup_free_ char *t = NULL; + +                        if (!j->rr) +                                continue; + +                        if (!dns_key_is_shared(j->rr->key)) +                                continue; + +                        r = dns_packet_append_rr(p, j->rr, NULL, NULL); +                        if (r == -EMSGSIZE && p->protocol == DNS_PROTOCOL_MDNS) { +                                /* For mDNS, if we're unable to stuff all known answers into the given packet, +                                 * allocate a new one, push the RR into that one and link it to the current one. +                                 */ + +                                DNS_PACKET_HEADER(p)->ancount = htobe16(ancount); +                                ancount = 0; + +                                r = dns_packet_new_query(&p->more, p->protocol, 0, true); +                                if (r < 0) +                                        return r; + +                                /* continue with new packet */ +                                p = p->more; +                                r = dns_packet_append_rr(p, j->rr, NULL, NULL); +                        } + +                        if (r < 0) +                                return r; + +                        ancount ++; +                } +        } + +        DNS_PACKET_HEADER(p)->ancount = htobe16(ancount); + +        return 0; +} +  void dns_cache_dump(DnsCache *cache, FILE *f) {          Iterator iterator;          DnsCacheItem *i; diff --git a/src/resolve/resolved-dns-cache.h b/src/resolve/resolved-dns-cache.h index 164435b4fb..0f28bbe543 100644 --- a/src/resolve/resolved-dns-cache.h +++ b/src/resolve/resolved-dns-cache.h @@ -21,7 +21,6 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -  #include "hashmap.h"  #include "list.h"  #include "prioq.h" @@ -33,16 +32,19 @@ typedef struct DnsCache {  } DnsCache;  #include "resolved-dns-answer.h" +#include "resolved-dns-packet.h"  #include "resolved-dns-question.h"  #include "resolved-dns-rr.h"  void dns_cache_flush(DnsCache *c);  void dns_cache_prune(DnsCache *c); -int dns_cache_put(DnsCache *c, DnsResourceKey *key, int rcode, DnsAnswer *answer, unsigned max_rrs, usec_t timestamp, int owner_family, const union in_addr_union *owner_address); -int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **answer); +int dns_cache_put(DnsCache *c, DnsResourceKey *key, int rcode, DnsAnswer *answer, unsigned max_rrs, bool authenticated, usec_t timestamp, int owner_family, const union in_addr_union *owner_address); +int dns_cache_lookup(DnsCache *c, DnsResourceKey *key, int *rcode, DnsAnswer **answer, bool *authenticated);  int dns_cache_check_conflicts(DnsCache *cache, DnsResourceRecord *rr, int owner_family, const union in_addr_union *owner_address);  void dns_cache_dump(DnsCache *cache, FILE *f);  bool dns_cache_is_empty(DnsCache *cache); + +int dns_cache_export_shared_to_packet(DnsCache *cache, DnsPacket *p); diff --git a/src/resolve/resolved-dns-dnssec.c b/src/resolve/resolved-dns-dnssec.c new file mode 100644 index 0000000000..2d06775dca --- /dev/null +++ b/src/resolve/resolved-dns-dnssec.c @@ -0,0 +1,719 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** +  This file is part of systemd. + +  Copyright 2015 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 <gcrypt.h> + +#include "alloc-util.h" +#include "dns-domain.h" +#include "resolved-dns-dnssec.h" +#include "resolved-dns-packet.h" +#include "string-table.h" + +/* Open question: + * + * How does the DNSSEC canonical form of a hostname with a label + * containing a dot look like, the way DNS-SD does it? + * + * TODO: + * + *   - Iterative validation + *   - NSEC proof of non-existance + *   - NSEC3 proof of non-existance + *   - Make trust anchor store read additional DS+DNSKEY data from disk + *   - wildcard zones compatibility + *   - multi-label zone compatibility + *   - DMSSEC cname/dname compatibility + *   - per-interface DNSSEC setting + *   - DSA support + *   - EC support? + * + * */ + +#define VERIFY_RRS_MAX 256 +#define MAX_KEY_SIZE (32*1024) + +/* Permit a maximum clock skew of 1h 10min. This should be enough to deal with DST confusion */ +#define SKEW_MAX (1*USEC_PER_HOUR + 10*USEC_PER_MINUTE) + +/* + * The DNSSEC Chain of trust: + * + *            Normal RRs are protected via RRSIG RRs in combination with DNSKEY RRs, all in the same zone + *            DNSKEY RRs are either protected like normal RRs, or via a DS from a zone "higher" up the tree + *            DS RRs are protected like normal RRs + * + * Example chain: + *            Normal RR → RRSIG/DNSKEY+ → DS → RRSIG/DNSKEY+ → DS → ... → DS → RRSIG/DNSKEY+ → DS + */ + +static bool dnssec_algorithm_supported(int algorithm) { +        return IN_SET(algorithm, +                      DNSSEC_ALGORITHM_RSASHA1, +                      DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1, +                      DNSSEC_ALGORITHM_RSASHA256, +                      DNSSEC_ALGORITHM_RSASHA512); +} + +static bool dnssec_digest_supported(int digest) { +        return IN_SET(digest, +                      DNSSEC_DIGEST_SHA1, +                      DNSSEC_DIGEST_SHA256); +} + +uint16_t dnssec_keytag(DnsResourceRecord *dnskey) { +        const uint8_t *p; +        uint32_t sum; +        size_t i; + +        /* The algorithm from RFC 4034, Appendix B. */ + +        assert(dnskey); +        assert(dnskey->key->type == DNS_TYPE_DNSKEY); + +        sum = (uint32_t) dnskey->dnskey.flags + +                ((((uint32_t) dnskey->dnskey.protocol) << 8) + (uint32_t) dnskey->dnskey.algorithm); + +        p = dnskey->dnskey.key; + +        for (i = 0; i < dnskey->dnskey.key_size; i++) +                sum += (i & 1) == 0 ? (uint32_t) p[i] << 8 : (uint32_t) p[i]; + +        sum += (sum >> 16) & UINT32_C(0xFFFF); + +        return sum & UINT32_C(0xFFFF); +} + +static int rr_compare(const void *a, const void *b) { +        DnsResourceRecord **x = (DnsResourceRecord**) a, **y = (DnsResourceRecord**) b; +        size_t m; +        int r; + +        /* Let's order the RRs according to RFC 4034, Section 6.3 */ + +        assert(x); +        assert(*x); +        assert((*x)->wire_format); +        assert(y); +        assert(*y); +        assert((*y)->wire_format); + +        m = MIN((*x)->wire_format_size, (*y)->wire_format_size); + +        r = memcmp((*x)->wire_format, (*y)->wire_format, m); +        if (r != 0) +                return r; + +        if ((*x)->wire_format_size < (*y)->wire_format_size) +                return -1; +        else if ((*x)->wire_format_size > (*y)->wire_format_size) +                return 1; + +        return 0; +} + +static int dnssec_rsa_verify( +                const char *hash_algorithm, +                const void *signature, size_t signature_size, +                const void *data, size_t data_size, +                const void *exponent, size_t exponent_size, +                const void *modulus, size_t modulus_size) { + +        gcry_sexp_t public_key_sexp = NULL, data_sexp = NULL, signature_sexp = NULL; +        gcry_mpi_t n = NULL, e = NULL, s = NULL; +        gcry_error_t ge; +        int r; + +        assert(hash_algorithm); + +        ge = gcry_mpi_scan(&s, GCRYMPI_FMT_USG, signature, signature_size, NULL); +        if (ge != 0) { +                r = -EIO; +                goto finish; +        } + +        ge = gcry_mpi_scan(&e, GCRYMPI_FMT_USG, exponent, exponent_size, NULL); +        if (ge != 0) { +                r = -EIO; +                goto finish; +        } + +        ge = gcry_mpi_scan(&n, GCRYMPI_FMT_USG, modulus, modulus_size, NULL); +        if (ge != 0) { +                r = -EIO; +                goto finish; +        } + +        ge = gcry_sexp_build(&signature_sexp, +                             NULL, +                             "(sig-val (rsa (s %m)))", +                             s); + +        if (ge != 0) { +                r = -EIO; +                goto finish; +        } + +        ge = gcry_sexp_build(&data_sexp, +                             NULL, +                             "(data (flags pkcs1) (hash %s %b))", +                             hash_algorithm, +                             (int) data_size, +                             data); +        if (ge != 0) { +                r = -EIO; +                goto finish; +        } + +        ge = gcry_sexp_build(&public_key_sexp, +                             NULL, +                             "(public-key (rsa (n %m) (e %m)))", +                             n, +                             e); +        if (ge != 0) { +                r = -EIO; +                goto finish; +        } + +        ge = gcry_pk_verify(signature_sexp, data_sexp, public_key_sexp); +        if (ge == GPG_ERR_BAD_SIGNATURE) +                r = 0; +        else if (ge != 0) +                r = -EIO; +        else +                r = 1; + +finish: +        if (e) +                gcry_mpi_release(e); +        if (n) +                gcry_mpi_release(n); +        if (s) +                gcry_mpi_release(s); + +        if (public_key_sexp) +                gcry_sexp_release(public_key_sexp); +        if (signature_sexp) +                gcry_sexp_release(signature_sexp); +        if (data_sexp) +                gcry_sexp_release(data_sexp); + +        return r; +} + +static void md_add_uint8(gcry_md_hd_t md, uint8_t v) { +        gcry_md_write(md, &v, sizeof(v)); +} + +static void md_add_uint16(gcry_md_hd_t md, uint16_t v) { +        v = htobe16(v); +        gcry_md_write(md, &v, sizeof(v)); +} + +static void md_add_uint32(gcry_md_hd_t md, uint32_t v) { +        v = htobe32(v); +        gcry_md_write(md, &v, sizeof(v)); +} + +static int dnssec_rrsig_expired(DnsResourceRecord *rrsig, usec_t realtime) { +        usec_t expiration, inception, skew; + +        assert(rrsig); +        assert(rrsig->key->type == DNS_TYPE_RRSIG); + +        if (realtime == USEC_INFINITY) +                realtime = now(CLOCK_REALTIME); + +        expiration = rrsig->rrsig.expiration * USEC_PER_SEC; +        inception = rrsig->rrsig.inception * USEC_PER_SEC; + +        if (inception > expiration) +                return -EKEYREJECTED; + +        /* Permit a certain amount of clock skew of 10% of the valid +         * time range. This takes inspiration from unbound's +         * resolver. */ +        skew = (expiration - inception) / 10; +        if (skew > SKEW_MAX) +                skew = SKEW_MAX; + +        if (inception < skew) +                inception = 0; +        else +                inception -= skew; + +        if (expiration + skew < expiration) +                expiration = USEC_INFINITY; +        else +                expiration += skew; + +        return realtime < inception || realtime > expiration; +} + +int dnssec_verify_rrset( +                DnsAnswer *a, +                DnsResourceKey *key, +                DnsResourceRecord *rrsig, +                DnsResourceRecord *dnskey, +                usec_t realtime) { + +        uint8_t wire_format_name[DNS_WIRE_FOMAT_HOSTNAME_MAX]; +        size_t exponent_size, modulus_size, hash_size; +        void *exponent, *modulus, *hash; +        DnsResourceRecord **list, *rr; +        gcry_md_hd_t md = NULL; +        size_t k, n = 0; +        int r; + +        assert(key); +        assert(rrsig); +        assert(dnskey); +        assert(rrsig->key->type == DNS_TYPE_RRSIG); +        assert(dnskey->key->type == DNS_TYPE_DNSKEY); + +        /* Verifies the the RRSet matching the specified "key" in "a", +         * using the signature "rrsig" and the key "dnskey". It's +         * assumed the RRSIG and DNSKEY match. */ + +        if (!dnssec_algorithm_supported(rrsig->rrsig.algorithm)) +                return -EOPNOTSUPP; + +        if (a->n_rrs > VERIFY_RRS_MAX) +                return -E2BIG; + +        r = dnssec_rrsig_expired(rrsig, realtime); +        if (r < 0) +                return r; +        if (r > 0) +                return DNSSEC_SIGNATURE_EXPIRED; + +        /* Collect all relevant RRs in a single array, so that we can look at the RRset */ +        list = newa(DnsResourceRecord *, a->n_rrs); + +        DNS_ANSWER_FOREACH(rr, a) { +                r = dns_resource_key_equal(key, rr->key); +                if (r < 0) +                        return r; +                if (r == 0) +                        continue; + +                /* We need the wire format for ordering, and digest calculation */ +                r = dns_resource_record_to_wire_format(rr, true); +                if (r < 0) +                        return r; + +                list[n++] = rr; +        } + +        if (n <= 0) +                return -ENODATA; + +        /* Bring the RRs into canonical order */ +        qsort_safe(list, n, sizeof(DnsResourceRecord), rr_compare); + +        /* OK, the RRs are now in canonical order. Let's calculate the digest */ +        switch (rrsig->rrsig.algorithm) { + +        case DNSSEC_ALGORITHM_RSASHA1: +        case DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1: +                gcry_md_open(&md, GCRY_MD_SHA1, 0); +                hash_size = 20; +                break; + +        case DNSSEC_ALGORITHM_RSASHA256: +                gcry_md_open(&md, GCRY_MD_SHA256, 0); +                hash_size = 32; +                break; + +        case DNSSEC_ALGORITHM_RSASHA512: +                gcry_md_open(&md, GCRY_MD_SHA512, 0); +                hash_size = 64; +                break; + +        default: +                assert_not_reached("Unknown digest"); +        } + +        if (!md) +                return -EIO; + +        md_add_uint16(md, rrsig->rrsig.type_covered); +        md_add_uint8(md, rrsig->rrsig.algorithm); +        md_add_uint8(md, rrsig->rrsig.labels); +        md_add_uint32(md, rrsig->rrsig.original_ttl); +        md_add_uint32(md, rrsig->rrsig.expiration); +        md_add_uint32(md, rrsig->rrsig.inception); +        md_add_uint16(md, rrsig->rrsig.key_tag); + +        r = dns_name_to_wire_format(rrsig->rrsig.signer, wire_format_name, sizeof(wire_format_name), true); +        if (r < 0) +                goto finish; +        gcry_md_write(md, wire_format_name, r); + +        for (k = 0; k < n; k++) { +                size_t l; +                rr = list[k]; + +                r = dns_name_to_wire_format(DNS_RESOURCE_KEY_NAME(rr->key), wire_format_name, sizeof(wire_format_name), true); +                if (r < 0) +                        goto finish; +                gcry_md_write(md, wire_format_name, r); + +                md_add_uint16(md, rr->key->type); +                md_add_uint16(md, rr->key->class); +                md_add_uint32(md, rrsig->rrsig.original_ttl); + +                assert(rr->wire_format_rdata_offset <= rr->wire_format_size); +                l = rr->wire_format_size - rr->wire_format_rdata_offset; +                assert(l <= 0xFFFF); + +                md_add_uint16(md, (uint16_t) l); +                gcry_md_write(md, (uint8_t*) rr->wire_format + rr->wire_format_rdata_offset, l); +        } + +        hash = gcry_md_read(md, 0); +        if (!hash) { +                r = -EIO; +                goto finish; +        } + +        if (*(uint8_t*) dnskey->dnskey.key == 0) { +                /* exponent is > 255 bytes long */ + +                exponent = (uint8_t*) dnskey->dnskey.key + 3; +                exponent_size = +                        ((size_t) (((uint8_t*) dnskey->dnskey.key)[0]) << 8) | +                        ((size_t) ((uint8_t*) dnskey->dnskey.key)[1]); + +                if (exponent_size < 256) { +                        r = -EINVAL; +                        goto finish; +                } + +                if (3 + exponent_size >= dnskey->dnskey.key_size) { +                        r = -EINVAL; +                        goto finish; +                } + +                modulus = (uint8_t*) dnskey->dnskey.key + 3 + exponent_size; +                modulus_size = dnskey->dnskey.key_size - 3 - exponent_size; + +        } else { +                /* exponent is <= 255 bytes long */ + +                exponent = (uint8_t*) dnskey->dnskey.key + 1; +                exponent_size = (size_t) ((uint8_t*) dnskey->dnskey.key)[0]; + +                if (exponent_size <= 0) { +                        r = -EINVAL; +                        goto finish; +                } + +                if (1 + exponent_size >= dnskey->dnskey.key_size) { +                        r = -EINVAL; +                        goto finish; +                } + +                modulus = (uint8_t*) dnskey->dnskey.key + 1 + exponent_size; +                modulus_size = dnskey->dnskey.key_size - 1 - exponent_size; +        } + +        r = dnssec_rsa_verify( +                        gcry_md_algo_name(gcry_md_get_algo(md)), +                        rrsig->rrsig.signature, rrsig->rrsig.signature_size, +                        hash, hash_size, +                        exponent, exponent_size, +                        modulus, modulus_size); +        if (r < 0) +                goto finish; + +        r = r ? DNSSEC_VERIFIED : DNSSEC_INVALID; + +finish: +        gcry_md_close(md); +        return r; +} + +int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey) { + +        assert(rrsig); +        assert(dnskey); + +        /* Checks if the specified DNSKEY RR matches the key used for +         * the signature in the specified RRSIG RR */ + +        if (rrsig->key->type != DNS_TYPE_RRSIG) +                return -EINVAL; + +        if (dnskey->key->type != DNS_TYPE_DNSKEY) +                return 0; +        if (dnskey->key->class != rrsig->key->class) +                return 0; +        if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0) +                return 0; +        if (dnskey->dnskey.protocol != 3) +                return 0; +        if (dnskey->dnskey.algorithm != rrsig->rrsig.algorithm) +                return 0; + +        if (dnssec_keytag(dnskey) != rrsig->rrsig.key_tag) +                return 0; + +        return dns_name_equal(DNS_RESOURCE_KEY_NAME(dnskey->key), DNS_RESOURCE_KEY_NAME(rrsig->key)); +} + +int dnssec_key_match_rrsig(DnsResourceKey *key, DnsResourceRecord *rrsig) { +        assert(key); +        assert(rrsig); + +        /* Checks if the specified RRSIG RR protects the RRSet of the specified RR key. */ + +        if (rrsig->key->type != DNS_TYPE_RRSIG) +                return 0; +        if (rrsig->key->class != key->class) +                return 0; +        if (rrsig->rrsig.type_covered != key->type) +                return 0; + +        return dns_name_equal(DNS_RESOURCE_KEY_NAME(rrsig->key), DNS_RESOURCE_KEY_NAME(key)); +} + +int dnssec_verify_rrset_search( +                DnsAnswer *a, +                DnsResourceKey *key, +                DnsAnswer *validated_dnskeys, +                usec_t realtime) { + +        bool found_rrsig = false, found_dnskey = false; +        DnsResourceRecord *rrsig; +        int r; + +        assert(key); + +        /* Verifies all RRs from "a" that match the key "key", against DNSKEY RRs in "validated_dnskeys" */ + +        if (!a || a->n_rrs <= 0) +                return -ENODATA; + +        /* Iterate through each RRSIG RR. */ +        DNS_ANSWER_FOREACH(rrsig, a) { +                DnsResourceRecord *dnskey; + +                r = dnssec_key_match_rrsig(key, rrsig); +                if (r < 0) +                        return r; +                if (r == 0) +                        continue; + +                found_rrsig = true; + +                DNS_ANSWER_FOREACH(dnskey, validated_dnskeys) { + +                        r = dnssec_rrsig_match_dnskey(rrsig, dnskey); +                        if (r < 0) +                                return r; +                        if (r == 0) +                                continue; + +                        found_dnskey = true; + +                        /* Take the time here, if it isn't set yet, so +                         * that we do all validations with the same +                         * time. */ +                        if (realtime == USEC_INFINITY) +                                realtime = now(CLOCK_REALTIME); + +                        /* Yay, we found a matching RRSIG with a matching +                         * DNSKEY, awesome. Now let's verify all entries of +                         * the RRSet against the RRSIG and DNSKEY +                         * combination. */ + +                        r = dnssec_verify_rrset(a, key, rrsig, dnskey, realtime); +                        if (r < 0 && r != EOPNOTSUPP) +                                return r; +                        if (r == DNSSEC_VERIFIED) +                                return DNSSEC_VERIFIED; + +                        /* If the signature is invalid, or done using +                           an unsupported algorithm, let's try another +                           key and/or signature. After all they +                           key_tags and stuff are not unique, and +                           might be shared by multiple keys. */ +                } +        } + +        if (found_dnskey) +                return DNSSEC_INVALID; + +        if (found_rrsig) +                return DNSSEC_MISSING_KEY; + +        return DNSSEC_NO_SIGNATURE; +} + +int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max) { +        size_t c = 0; +        int r; + +        /* Converts the specified hostname into DNSSEC canonicalized +         * form. */ + +        if (buffer_max < 2) +                return -ENOBUFS; + +        for (;;) { +                size_t i; + +                r = dns_label_unescape(&n, buffer, buffer_max); +                if (r < 0) +                        return r; +                if (r == 0) +                        break; +                if (r > 0) { +                        int k; + +                        /* DNSSEC validation is always done on the ASCII version of the label */ +                        k = dns_label_apply_idna(buffer, r, buffer, buffer_max); +                        if (k < 0) +                                return k; +                        if (k > 0) +                                r = k; +                } + +                if (buffer_max < (size_t) r + 2) +                        return -ENOBUFS; + +                /* The DNSSEC canonical form is not clear on what to +                 * do with dots appearing in labels, the way DNS-SD +                 * does it. Refuse it for now. */ + +                if (memchr(buffer, '.', r)) +                        return -EINVAL; + +                for (i = 0; i < (size_t) r; i ++) { +                        if (buffer[i] >= 'A' && buffer[i] <= 'Z') +                                buffer[i] = buffer[i] - 'A' + 'a'; +                } + +                buffer[r] = '.'; + +                buffer += r + 1; +                c += r + 1; + +                buffer_max -= r + 1; +        } + +        if (c <= 0) { +                /* Not even a single label: this is the root domain name */ + +                assert(buffer_max > 2); +                buffer[0] = '.'; +                buffer[1] = 0; + +                return 1; +        } + +        return (int) c; +} + +int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds) { +        gcry_md_hd_t md = NULL; +        char owner_name[DNSSEC_CANONICAL_HOSTNAME_MAX]; +        void *result; +        int r; + +        assert(dnskey); +        assert(ds); + +        /* Implements DNSKEY verification by a DS, according to RFC 4035, section 5.2 */ + +        if (dnskey->key->type != DNS_TYPE_DNSKEY) +                return -EINVAL; +        if (ds->key->type != DNS_TYPE_DS) +                return -EINVAL; +        if ((dnskey->dnskey.flags & DNSKEY_FLAG_ZONE_KEY) == 0) +                return -EKEYREJECTED; +        if (dnskey->dnskey.protocol != 3) +                return -EKEYREJECTED; + +        if (!dnssec_algorithm_supported(dnskey->dnskey.algorithm)) +                return -EOPNOTSUPP; +        if (!dnssec_digest_supported(ds->ds.digest_type)) +                return -EOPNOTSUPP; + +        if (dnskey->dnskey.algorithm != ds->ds.algorithm) +                return 0; +        if (dnssec_keytag(dnskey) != ds->ds.key_tag) +                return 0; + +        switch (ds->ds.digest_type) { + +        case DNSSEC_DIGEST_SHA1: + +                if (ds->ds.digest_size != 20) +                        return 0; + +                gcry_md_open(&md, GCRY_MD_SHA1, 0); +                break; + +        case DNSSEC_DIGEST_SHA256: + +                if (ds->ds.digest_size != 32) +                        return 0; + +                gcry_md_open(&md, GCRY_MD_SHA256, 0); +                break; + +        default: +                assert_not_reached("Unknown digest"); +        } + +        if (!md) +                return -EIO; + +        r = dnssec_canonicalize(DNS_RESOURCE_KEY_NAME(dnskey->key), owner_name, sizeof(owner_name)); +        if (r < 0) +                goto finish; + +        gcry_md_write(md, owner_name, r); +        md_add_uint16(md, dnskey->dnskey.flags); +        md_add_uint8(md, dnskey->dnskey.protocol); +        md_add_uint8(md, dnskey->dnskey.algorithm); +        gcry_md_write(md, dnskey->dnskey.key, dnskey->dnskey.key_size); + +        result = gcry_md_read(md, 0); +        if (!result) { +                r = -EIO; +                goto finish; +        } + +        r = memcmp(result, ds->ds.digest, ds->ds.digest_size) != 0; + +finish: +        gcry_md_close(md); +        return r; +} + +static const char* const dnssec_mode_table[_DNSSEC_MODE_MAX] = { +        [DNSSEC_NO] = "no", +        [DNSSEC_TRUST] = "trust", +        [DNSSEC_YES] = "yes", +}; +DEFINE_STRING_TABLE_LOOKUP(dnssec_mode, DnssecMode); diff --git a/src/resolve/resolved-dns-dnssec.h b/src/resolve/resolved-dns-dnssec.h new file mode 100644 index 0000000000..f4cb58988a --- /dev/null +++ b/src/resolve/resolved-dns-dnssec.h @@ -0,0 +1,67 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** +  This file is part of systemd. + +  Copyright 2015 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/>. +***/ + +typedef enum DnssecMode DnssecMode; + +#include "dns-domain.h" +#include "resolved-dns-answer.h" +#include "resolved-dns-rr.h" + +enum DnssecMode { +        /* No DNSSEC validation is done */ +        DNSSEC_NO, + +        /* Trust the AD bit sent by the server. UNSAFE! */ +        DNSSEC_TRUST, + +        /* Validate locally, if the server knows DO, but if not, don't. Don't trust the AD bit */ +        DNSSEC_YES, + +        _DNSSEC_MODE_MAX, +        _DNSSEC_MODE_INVALID = -1 +}; + +enum { +        DNSSEC_VERIFIED, +        DNSSEC_INVALID, +        DNSSEC_NO_SIGNATURE, +        DNSSEC_MISSING_KEY, +        DNSSEC_SIGNATURE_EXPIRED, +}; + +#define DNSSEC_CANONICAL_HOSTNAME_MAX (DNS_HOSTNAME_MAX + 2) + +int dnssec_rrsig_match_dnskey(DnsResourceRecord *rrsig, DnsResourceRecord *dnskey); +int dnssec_key_match_rrsig(DnsResourceKey *key, DnsResourceRecord *rrsig); + +int dnssec_verify_rrset(DnsAnswer *answer, DnsResourceKey *key, DnsResourceRecord *rrsig, DnsResourceRecord *dnskey, usec_t realtime); +int dnssec_verify_rrset_search(DnsAnswer *a, DnsResourceKey *key, DnsAnswer *validated_dnskeys, usec_t realtime); + +int dnssec_verify_dnskey(DnsResourceRecord *dnskey, DnsResourceRecord *ds); + +uint16_t dnssec_keytag(DnsResourceRecord *dnskey); + +int dnssec_canonicalize(const char *n, char *buffer, size_t buffer_max); + +const char* dnssec_mode_to_string(DnssecMode m) _const_; +DnssecMode dnssec_mode_from_string(const char *s) _pure_; diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 75ca23fd08..f753b3522f 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -65,30 +65,44 @@ int dns_packet_new(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {          return 0;  } -int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) { -        DnsPacket *p; -        DnsPacketHeader *h; -        int r; +void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated) { -        assert(ret); +        DnsPacketHeader *h; -        r = dns_packet_new(&p, protocol, mtu); -        if (r < 0) -                return r; +        assert(p);          h = DNS_PACKET_HEADER(p); -        if (protocol == DNS_PROTOCOL_LLMNR) +        switch(p->protocol) { +        case DNS_PROTOCOL_LLMNR: +                assert(!truncated); +                  h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,                                                           0 /* opcode */,                                                           0 /* c */, -                                                         0 /* tc */, +                                                         0/* tc */,                                                           0 /* t */,                                                           0 /* ra */,                                                           0 /* ad */,                                                           0 /* cd */,                                                           0 /* rcode */)); -        else +                break; + +        case DNS_PROTOCOL_MDNS: +                h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0         /* qr */, +                                                         0         /* opcode */, +                                                         0         /* aa */, +                                                         truncated /* tc */, +                                                         0         /* rd (ask for recursion) */, +                                                         0         /* ra */, +                                                         0         /* ad */, +                                                         0         /* cd */, +                                                         0         /* rcode */)); +                break; + +        default: +                assert(!truncated); +                  h->flags = htobe16(DNS_PACKET_MAKE_FLAGS(0 /* qr */,                                                           0 /* opcode */,                                                           0 /* aa */, @@ -96,8 +110,25 @@ int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu) {                                                           1 /* rd (ask for recursion) */,                                                           0 /* ra */,                                                           0 /* ad */, -                                                         0 /* cd */, +                                                         dnssec_checking_disabled /* cd */,                                                           0 /* rcode */)); +        } +} + +int dns_packet_new_query(DnsPacket **ret, DnsProtocol protocol, size_t mtu, bool dnssec_checking_disabled) { +        DnsPacket *p; +        int r; + +        assert(ret); + +        r = dns_packet_new(&p, protocol, mtu); +        if (r < 0) +                return r; + +        /* Always set the TC bit to 0 initially. +         * If there are multiple packets later, we'll update the bit shortly before sending. +         */ +        dns_packet_set_flags(p, dnssec_checking_disabled, false);          *ret = p;          return 0; @@ -108,6 +139,8 @@ DnsPacket *dns_packet_ref(DnsPacket *p) {          if (!p)                  return NULL; +        assert(!p->on_stack); +          assert(p->n_ref > 0);          p->n_ref++;          return p; @@ -126,7 +159,9 @@ static void dns_packet_free(DnsPacket *p) {          hashmap_free(p->names);          free(p->_data); -        free(p); + +        if (!p->on_stack) +                free(p);  }  DnsPacket *dns_packet_unref(DnsPacket *p) { @@ -135,6 +170,9 @@ DnsPacket *dns_packet_unref(DnsPacket *p) {          assert(p->n_ref > 0); +        if (p->more) +                dns_packet_unref(p->more); +          if (p->n_ref == 1)                  dns_packet_free(p);          else @@ -178,6 +216,13 @@ int dns_packet_validate_reply(DnsPacket *p) {                  break; +        case DNS_PROTOCOL_MDNS: +                /* RFC 6762, Section 18 */ +                if (DNS_PACKET_RCODE(p) != 0) +                        return -EBADMSG; + +                break; +          default:                  break;          } @@ -219,6 +264,18 @@ int dns_packet_validate_query(DnsPacket *p) {                  break; +        case DNS_PROTOCOL_MDNS: +                /* RFC 6762, Section 18 */ +                if (DNS_PACKET_AA(p)    != 0 || +                    DNS_PACKET_RD(p)    != 0 || +                    DNS_PACKET_RA(p)    != 0 || +                    DNS_PACKET_AD(p)    != 0 || +                    DNS_PACKET_CD(p)    != 0 || +                    DNS_PACKET_RCODE(p) != 0) +                        return -EBADMSG; + +                break; +          default:                  break;          } @@ -351,25 +408,10 @@ int dns_packet_append_uint32(DnsPacket *p, uint32_t v, size_t *start) {  }  int dns_packet_append_string(DnsPacket *p, const char *s, size_t *start) { -        void *d; -        size_t l; -        int r; -          assert(p);          assert(s); -        l = strlen(s); -        if (l > 255) -                return -E2BIG; - -        r = dns_packet_extend(p, 1 + l, &d, start); -        if (r < 0) -                return r; - -        ((uint8_t*) d)[0] = (uint8_t) l; -        memcpy(((uint8_t*) d) + 1, s, l); - -        return 0; +        return dns_packet_append_raw_string(p, s, strlen(s), start);  }  int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_t *start) { @@ -395,7 +437,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_  }  int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start) { -        void *w; +        uint8_t *w;          int r;          assert(p); @@ -404,12 +446,29 @@ int dns_packet_append_label(DnsPacket *p, const char *d, size_t l, size_t *start          if (l > DNS_LABEL_MAX)                  return -E2BIG; -        r = dns_packet_extend(p, 1 + l, &w, start); +        r = dns_packet_extend(p, 1 + l, (void**) &w, start);          if (r < 0)                  return r; -        ((uint8_t*) w)[0] = (uint8_t) l; -        memcpy(((uint8_t*) w) + 1, d, l); +        *(w++) = (uint8_t) l; + +        if (p->canonical_form) { +                size_t i; + +                /* Generate in canonical form, as defined by DNSSEC +                 * RFC 4034, Section 6.2, i.e. all lower-case. */ + +                for (i = 0; i < l; i++) { +                        if (d[i] >= 'A' && d[i] <= 'Z') +                                w[i] = (uint8_t) (d[i] - 'A' + 'a'); +                        else +                                w[i] = (uint8_t) d[i]; +                } +        } else +                /* Otherwise, just copy the string unaltered. This is +                 * essential for DNS-SD, where the casing of labels +                 * matters and needs to be retained. */ +                memcpy(w, d, l);          return 0;  } @@ -662,8 +721,8 @@ fail:          return r;  } -int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start) { -        size_t saved_size, rdlength_offset, end, rdlength; +int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start) { +        size_t saved_size, rdlength_offset, end, rdlength, rds;          int r;          assert(p); @@ -684,6 +743,8 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star          if (r < 0)                  goto fail; +        rds = p->size - saved_size; +          switch (rr->unparseable ? _DNS_TYPE_INVALID : rr->key->type) {          case DNS_TYPE_SRV: @@ -841,11 +902,11 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star                  break;          case DNS_TYPE_DNSKEY: -                r = dns_packet_append_uint16(p, dnskey_to_flags(rr), NULL); +                r = dns_packet_append_uint16(p, rr->dnskey.flags, NULL);                  if (r < 0)                          goto fail; -                r = dns_packet_append_uint8(p, 3u, NULL); +                r = dns_packet_append_uint8(p, rr->dnskey.protocol, NULL);                  if (r < 0)                          goto fail; @@ -962,6 +1023,9 @@ int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *star          if (start)                  *start = saved_size; +        if (rdata_start) +                *rdata_start = rds; +          return 0;  fail: @@ -1381,6 +1445,7 @@ fail:  int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {          _cleanup_free_ char *name = NULL; +        bool cache_flush = false;          uint16_t class, type;          DnsResourceKey *key;          size_t saved_rindex; @@ -1403,12 +1468,23 @@ int dns_packet_read_key(DnsPacket *p, DnsResourceKey **ret, size_t *start) {          if (r < 0)                  goto fail; +        if (p->protocol == DNS_PROTOCOL_MDNS) { +                /* See RFC6762, Section 10.2 */ + +                if (class & MDNS_RR_CACHE_FLUSH) { +                        class &= ~MDNS_RR_CACHE_FLUSH; +                        cache_flush = true; +                } +        } +          key = dns_resource_key_new_consume(class, type, name);          if (!key) {                  r = -ENOMEM;                  goto fail;          } +        key->cache_flush = cache_flush; +          name = NULL;          *ret = key; @@ -1427,17 +1503,6 @@ static bool loc_size_ok(uint8_t size) {          return m <= 9 && e <= 9 && (m > 0 || e == 0);  } -static int dnskey_parse_flags(DnsResourceRecord *rr, uint16_t flags) { -        assert(rr); - -        if (flags & ~(DNSKEY_FLAG_SEP | DNSKEY_FLAG_ZONE_KEY)) -                return -EBADMSG; - -        rr->dnskey.zone_key_flag = flags & DNSKEY_FLAG_ZONE_KEY; -        rr->dnskey.sep_flag = flags & DNSKEY_FLAG_SEP; -        return 0; -} -  int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {          _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL;          _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; @@ -1706,28 +1771,15 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {                  break; -        case DNS_TYPE_DNSKEY: { -                uint16_t flags; -                uint8_t proto; - -                r = dns_packet_read_uint16(p, &flags, NULL); -                if (r < 0) -                        goto fail; - -                r = dnskey_parse_flags(rr, flags); +        case DNS_TYPE_DNSKEY: +                r = dns_packet_read_uint16(p, &rr->dnskey.flags, NULL);                  if (r < 0)                          goto fail; -                r = dns_packet_read_uint8(p, &proto, NULL); +                r = dns_packet_read_uint8(p, &rr->dnskey.protocol, NULL);                  if (r < 0)                          goto fail; -                /* protocol is required to be always 3 */ -                if (proto != 3) { -                        r = -EBADMSG; -                        goto fail; -                } -                  r = dns_packet_read_uint8(p, &rr->dnskey.algorithm, NULL);                  if (r < 0)                          goto fail; @@ -1744,7 +1796,6 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {                  }                  break; -        }          case DNS_TYPE_RRSIG:                  r = dns_packet_read_uint16(p, &rr->rrsig.type_covered, NULL); @@ -1792,8 +1843,16 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {                  break; -        case DNS_TYPE_NSEC: -                r = dns_packet_read_name(p, &rr->nsec.next_domain_name, false, NULL); +        case DNS_TYPE_NSEC: { + +                /* +                 * RFC6762, section 18.14 explicly states mDNS should use name compression. +                 * This contradicts RFC3845, section 2.1.1 +                 */ + +                bool allow_compressed = p->protocol == DNS_PROTOCOL_MDNS; + +                r = dns_packet_read_name(p, &rr->nsec.next_domain_name, allow_compressed, NULL);                  if (r < 0)                          goto fail; @@ -1806,7 +1865,7 @@ int dns_packet_read_rr(DnsPacket *p, DnsResourceRecord **ret, size_t *start) {                   * without the NSEC bit set. */                  break; - +        }          case DNS_TYPE_NSEC3: {                  uint8_t size; @@ -1976,17 +2035,3 @@ static const char* const dns_protocol_table[_DNS_PROTOCOL_MAX] = {          [DNS_PROTOCOL_LLMNR] = "llmnr",  };  DEFINE_STRING_TABLE_LOOKUP(dns_protocol, DnsProtocol); - -static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = { -        [DNSSEC_ALGORITHM_RSAMD5]             = "RSAMD5", -        [DNSSEC_ALGORITHM_DH]                 = "DH", -        [DNSSEC_ALGORITHM_DSA]                = "DSA", -        [DNSSEC_ALGORITHM_ECC]                = "ECC", -        [DNSSEC_ALGORITHM_RSASHA1]            = "RSASHA1", -        [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1]     = "DSA-NSEC3-SHA1", -        [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1", -        [DNSSEC_ALGORITHM_INDIRECT]           = "INDIRECT", -        [DNSSEC_ALGORITHM_PRIVATEDNS]         = "PRIVATEDNS", -        [DNSSEC_ALGORITHM_PRIVATEOID]         = "PRIVATEOID", -}; -DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int); diff --git a/src/resolve/resolved-dns-packet.h b/src/resolve/resolved-dns-packet.h index 25dfb2642f..3d84cb622b 100644 --- a/src/resolve/resolved-dns-packet.h +++ b/src/resolve/resolved-dns-packet.h @@ -88,8 +88,13 @@ struct DnsPacket {          uint16_t sender_port, destination_port;          uint32_t ttl; -        bool extracted; -        bool refuse_compression; +        /* For support of truncated packets */ +        DnsPacket *more; + +        bool on_stack:1; +        bool extracted:1; +        bool refuse_compression:1; +        bool canonical_form:1;  };  static inline uint8_t* DNS_PACKET_DATA(DnsPacket *p) { @@ -142,7 +147,9 @@ static inline unsigned DNS_PACKET_RRCOUNT(DnsPacket *p) {  }  int dns_packet_new(DnsPacket **p, DnsProtocol protocol, size_t mtu); -int dns_packet_new_query(DnsPacket **p, DnsProtocol protocol, size_t mtu); +int dns_packet_new_query(DnsPacket **p, DnsProtocol protocol, size_t mtu, bool dnssec_checking_disabled); + +void dns_packet_set_flags(DnsPacket *p, bool dnssec_checking_disabled, bool truncated);  DnsPacket *dns_packet_ref(DnsPacket *p);  DnsPacket *dns_packet_unref(DnsPacket *p); @@ -162,7 +169,7 @@ int dns_packet_append_raw_string(DnsPacket *p, const void *s, size_t size, size_  int dns_packet_append_label(DnsPacket *p, const char *s, size_t l, size_t *start);  int dns_packet_append_name(DnsPacket *p, const char *name, bool allow_compression, size_t *start);  int dns_packet_append_key(DnsPacket *p, const DnsResourceKey *key, size_t *start); -int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start); +int dns_packet_append_rr(DnsPacket *p, const DnsResourceRecord *rr, size_t *start, size_t *rdata_start);  int dns_packet_append_opt_rr(DnsPacket *p, uint16_t max_udp_size, bool edns0_do, size_t *start);  void dns_packet_truncate(DnsPacket *p, size_t sz); @@ -223,42 +230,25 @@ DnsProtocol dns_protocol_from_string(const char *s) _pure_;  #define LLMNR_MULTICAST_IPV4_ADDRESS ((struct in_addr) { .s_addr = htobe32(224U << 24 | 252U) })  #define LLMNR_MULTICAST_IPV6_ADDRESS ((struct in6_addr) { .s6_addr = { 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x03 } }) -#define DNSKEY_FLAG_ZONE_KEY (1u << 8) -#define DNSKEY_FLAG_SEP      (1u << 0) - -static inline uint16_t dnskey_to_flags(const DnsResourceRecord *rr) { -        return (rr->dnskey.zone_key_flag * DNSKEY_FLAG_ZONE_KEY | -                rr->dnskey.sep_flag * DNSKEY_FLAG_SEP); -} - -/* http://tools.ietf.org/html/rfc4034#appendix-A.1 */ -enum { -        DNSSEC_ALGORITHM_RSAMD5 = 1, -        DNSSEC_ALGORITHM_DH, -        DNSSEC_ALGORITHM_DSA, -        DNSSEC_ALGORITHM_ECC, -        DNSSEC_ALGORITHM_RSASHA1, -        DNSSEC_ALGORITHM_DSA_NSEC3_SHA1, -        DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1, -        DNSSEC_ALGORITHM_INDIRECT = 252, -        DNSSEC_ALGORITHM_PRIVATEDNS, -        DNSSEC_ALGORITHM_PRIVATEOID, -        _DNSSEC_ALGORITHM_MAX_DEFINED -}; +#define MDNS_MULTICAST_IPV4_ADDRESS  ((struct in_addr) { .s_addr = htobe32(224U << 24 | 251U) }) +#define MDNS_MULTICAST_IPV6_ADDRESS  ((struct in6_addr) { .s6_addr = { 0xFF, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0xfb } }) -const char* dnssec_algorithm_to_string(int i) _const_; -int dnssec_algorithm_from_string(const char *s) _pure_; +static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family, bool authenticated) { +        uint64_t f; -static inline uint64_t SD_RESOLVED_FLAGS_MAKE(DnsProtocol protocol, int family) { +        /* Converts a protocol + family into a flags field as used in queries and responses */ -        /* Converts a protocol + family into a flags field as used in queries */ +        f = authenticated ? SD_RESOLVED_AUTHENTICATED : 0;          switch (protocol) {          case DNS_PROTOCOL_DNS: -                return SD_RESOLVED_DNS; +                return f|SD_RESOLVED_DNS;          case DNS_PROTOCOL_LLMNR: -                return family == AF_INET6 ? SD_RESOLVED_LLMNR_IPV6 : SD_RESOLVED_LLMNR_IPV4; +                return f|(family == AF_INET6 ? SD_RESOLVED_LLMNR_IPV6 : SD_RESOLVED_LLMNR_IPV4); + +        case DNS_PROTOCOL_MDNS: +                return family == AF_INET6 ? SD_RESOLVED_MDNS_IPV6 : SD_RESOLVED_MDNS_IPV4;          default:                  break; diff --git a/src/resolve/resolved-dns-query.c b/src/resolve/resolved-dns-query.c index a96cf439ad..089d9fb70d 100644 --- a/src/resolve/resolved-dns-query.c +++ b/src/resolve/resolved-dns-query.c @@ -86,7 +86,6 @@ DnsQueryCandidate* dns_query_candidate_free(DnsQueryCandidate *c) {  }  static int dns_query_candidate_next_search_domain(DnsQueryCandidate *c) { -        _cleanup_(dns_search_domain_unrefp) DnsSearchDomain *previous = NULL;          DnsSearchDomain *next = NULL;          assert(c); @@ -431,15 +430,17 @@ static int dns_query_add_candidate(DnsQuery *q, DnsScope *s) {                  return r;          /* If this a single-label domain on DNS, we might append a suitable search domain first. */ -        r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question)); -        if (r < 0) -                goto fail; -        if (r > 0) { -                /* OK, we need a search domain now. Let's find one for this scope */ - -                r = dns_query_candidate_next_search_domain(c); -                if (r <= 0) /* if there's no search domain, then we won't add any transaction. */ +        if ((q->flags & SD_RESOLVED_NO_SEARCH) == 0)  { +                r = dns_scope_name_needs_search_domain(s, dns_question_first_name(q->question)); +                if (r < 0)                          goto fail; +                if (r > 0) { +                        /* OK, we need a search domain now. Let's find one for this scope */ + +                        r = dns_query_candidate_next_search_domain(c); +                        if (r <= 0) /* if there's no search domain, then we won't add any transaction. */ +                                goto fail; +                }          }          r = dns_query_candidate_setup_transactions(c); @@ -971,6 +972,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {          DnsTransactionState state = DNS_TRANSACTION_NO_SERVERS;          DnsTransaction *t;          Iterator i; +        bool has_authenticated = false, has_non_authenticated = false;          assert(q); @@ -998,6 +1000,11 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {                          q->answer = merged;                          q->answer_rcode = t->answer_rcode; +                        if (t->answer_authenticated) +                                has_authenticated = true; +                        else +                                has_non_authenticated = true; +                          state = DNS_TRANSACTION_SUCCESS;                          break;                  } @@ -1027,6 +1034,7 @@ static void dns_query_accept(DnsQuery *q, DnsQueryCandidate *c) {          q->answer_protocol = c->scope->protocol;          q->answer_family = c->scope->family; +        q->answer_authenticated = has_authenticated && !has_non_authenticated;          dns_search_domain_unref(q->answer_search_domain);          q->answer_search_domain = dns_search_domain_ref(c->search_domain); diff --git a/src/resolve/resolved-dns-query.h b/src/resolve/resolved-dns-query.h index a9d7904a8d..b71bb2352b 100644 --- a/src/resolve/resolved-dns-query.h +++ b/src/resolve/resolved-dns-query.h @@ -75,6 +75,7 @@ struct DnsQuery {          DnsProtocol answer_protocol;          int answer_family;          DnsSearchDomain *answer_search_domain; +        bool answer_authenticated;          /* Bus client information */          sd_bus_message *request; diff --git a/src/resolve/resolved-dns-question.h b/src/resolve/resolved-dns-question.h index e77116c03a..5ffb63e250 100644 --- a/src/resolve/resolved-dns-question.h +++ b/src/resolve/resolved-dns-question.h @@ -23,9 +23,10 @@  typedef struct DnsQuestion DnsQuestion; +#include "macro.h"  #include "resolved-dns-rr.h" -/* A simple array of resources keys */ +/* A simple array of resource keys */  struct DnsQuestion {          unsigned n_ref; @@ -55,10 +56,12 @@ const char *dns_question_first_name(DnsQuestion *q);  DEFINE_TRIVIAL_CLEANUP_FUNC(DnsQuestion*, dns_question_unref); -#define DNS_QUESTION_FOREACH(key, q)                                    \ -        for (unsigned _i = ({                                           \ +#define _DNS_QUESTION_FOREACH(u, key, q)                                \ +        for (unsigned UNIQ_T(i, u) = ({                                 \                                  (key) = ((q) && (q)->n_keys > 0) ? (q)->keys[0] : NULL; \                                  0;                                      \                          });                                             \ -             (q) && ((_i) < (q)->n_keys);                               \ -             _i++, (key) = (_i < (q)->n_keys ? (q)->keys[_i] : NULL)) +             (q) && (UNIQ_T(i, u) < (q)->n_keys);                       \ +             UNIQ_T(i, u)++, (key) = (UNIQ_T(i, u) < (q)->n_keys ? (q)->keys[UNIQ_T(i, u)] : NULL)) + +#define DNS_QUESTION_FOREACH(key, q) _DNS_QUESTION_FOREACH(UNIQ, key, q) diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 4a1abb0cdc..934a18334c 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -27,6 +27,7 @@  #include "hexdecoct.h"  #include "resolved-dns-packet.h"  #include "resolved-dns-rr.h" +#include "string-table.h"  #include "string-util.h"  #include "strv.h" @@ -50,12 +51,6 @@ DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *          return k;  } -DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key) { -        assert(key); - -        return dns_resource_key_new(key->class, DNS_TYPE_CNAME, DNS_RESOURCE_KEY_NAME(key)); -} -  DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname) {          int r; @@ -136,6 +131,10 @@ DnsResourceKey* dns_resource_key_ref(DnsResourceKey *k) {          if (!k)                  return NULL; +        /* Static/const keys created with DNS_RESOURCE_KEY_CONST will +         * set this to -1, they should not be reffed/unreffed */ +        assert(k->n_ref != (unsigned) -1); +          assert(k->n_ref > 0);          k->n_ref++; @@ -146,6 +145,7 @@ DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {          if (!k)                  return NULL; +        assert(k->n_ref != (unsigned) -1);          assert(k->n_ref > 0);          if (k->n_ref == 1) { @@ -157,6 +157,14 @@ DnsResourceKey* dns_resource_key_unref(DnsResourceKey *k) {          return NULL;  } +bool dns_resource_key_is_address(const DnsResourceKey *key) { +        assert(key); + +        /* Check if this is an A or AAAA resource key */ + +        return key->class == DNS_CLASS_IN && IN_SET(key->type, DNS_TYPE_A, DNS_TYPE_AAAA); +} +  int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b) {          int r; @@ -416,6 +424,7 @@ DnsResourceRecord* dns_resource_record_unref(DnsResourceRecord *rr) {                          free(rr->generic.data);                  } +                free(rr->wire_format);                  dns_resource_key_unref(rr->key);          } @@ -576,8 +585,8 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor                         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 && -                       a->dnskey.sep_flag == b->dnskey.sep_flag && +                return a->dnskey.flags == b->dnskey.flags && +                       a->dnskey.protocol == b->dnskey.protocol &&                         a->dnskey.algorithm == b->dnskey.algorithm &&                         a->dnskey.key_size == b->dnskey.key_size &&                         memcmp(a->dnskey.key, b->dnskey.key, a->dnskey.key_size) == 0; @@ -883,9 +892,10 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {                  if (!t)                          return -ENOMEM; -                r = asprintf(&s, "%s %u 3 %.*s%.*u %s", +                r = asprintf(&s, "%s %u %u %.*s%.*u %s",                               k, -                             dnskey_to_flags(rr), +                             rr->dnskey.flags, +                             rr->dnskey.protocol,                               alg ? -1 : 0, alg,                               alg ? 0 : 1, alg ? 0u : (unsigned) rr->dnskey.algorithm,                               t); @@ -993,6 +1003,51 @@ int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret) {          return 0;  } +int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical) { + +        DnsPacket packet = { +                .n_ref = 1, +                .protocol = DNS_PROTOCOL_DNS, +                .on_stack = true, +                .refuse_compression = true, +                .canonical_form = canonical, +        }; + +        size_t start, rds; +        int r; + +        assert(rr); + +        /* Generates the RR in wire-format, optionally in the +         * canonical form as discussed in the DNSSEC RFC 4034, Section +         * 6.2. We allocate a throw-away DnsPacket object on the stack +         * here, because we need some book-keeping for memory +         * management, and can reuse the DnsPacket serializer, that +         * can generate the canonical form, too, but also knows label +         * compression and suchlike. */ + +        if (rr->wire_format && rr->wire_format_canonical == canonical) +                return 0; + +        r = dns_packet_append_rr(&packet, rr, &start, &rds); +        if (r < 0) +                return r; + +        assert(start == 0); +        assert(packet._data); + +        free(rr->wire_format); +        rr->wire_format = packet._data; +        rr->wire_format_size = packet.size; +        rr->wire_format_rdata_offset = rds; +        rr->wire_format_canonical = canonical; + +        packet._data = NULL; +        dns_packet_unref(&packet); + +        return 0; +} +  const char *dns_class_to_string(uint16_t class) {          switch (class) { @@ -1049,3 +1104,25 @@ bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b) {          return dns_txt_item_equal(a->items_next, b->items_next);  } + +static const char* const dnssec_algorithm_table[_DNSSEC_ALGORITHM_MAX_DEFINED] = { +        [DNSSEC_ALGORITHM_RSAMD5]             = "RSAMD5", +        [DNSSEC_ALGORITHM_DH]                 = "DH", +        [DNSSEC_ALGORITHM_DSA]                = "DSA", +        [DNSSEC_ALGORITHM_ECC]                = "ECC", +        [DNSSEC_ALGORITHM_RSASHA1]            = "RSASHA1", +        [DNSSEC_ALGORITHM_DSA_NSEC3_SHA1]     = "DSA-NSEC3-SHA1", +        [DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1] = "RSASHA1-NSEC3-SHA1", +        [DNSSEC_ALGORITHM_RSASHA256]          = "RSASHA256", +        [DNSSEC_ALGORITHM_RSASHA512]          = "RSASHA512", +        [DNSSEC_ALGORITHM_INDIRECT]           = "INDIRECT", +        [DNSSEC_ALGORITHM_PRIVATEDNS]         = "PRIVATEDNS", +        [DNSSEC_ALGORITHM_PRIVATEOID]         = "PRIVATEOID", +}; +DEFINE_STRING_TABLE_LOOKUP(dnssec_algorithm, int); + +static const char* const dnssec_digest_table[_DNSSEC_DIGEST_MAX_DEFINED] = { +        [DNSSEC_DIGEST_SHA1] = "SHA1", +        [DNSSEC_DIGEST_SHA256] = "SHA256", +}; +DEFINE_STRING_TABLE_LOOKUP(dnssec_digest, int); diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index a092961823..5c2306ba96 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -41,12 +41,60 @@ enum {          _DNS_CLASS_INVALID = -1  }; +/* DNSKEY RR flags */ +#define DNSKEY_FLAG_ZONE_KEY (UINT16_C(1) << 8) +#define DNSKEY_FLAG_SEP      (UINT16_C(1) << 0) + +/* mDNS RR flags */ +#define MDNS_RR_CACHE_FLUSH  (UINT16_C(1) << 15) + +/* DNSSEC algorithm identifiers, see + * http://tools.ietf.org/html/rfc4034#appendix-A.1 and + * https://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml */ +enum { +        DNSSEC_ALGORITHM_RSAMD5 = 1, +        DNSSEC_ALGORITHM_DH, +        DNSSEC_ALGORITHM_DSA, +        DNSSEC_ALGORITHM_ECC, +        DNSSEC_ALGORITHM_RSASHA1, +        DNSSEC_ALGORITHM_DSA_NSEC3_SHA1, +        DNSSEC_ALGORITHM_RSASHA1_NSEC3_SHA1, +        DNSSEC_ALGORITHM_RSASHA256 = 8,  /* RFC 5702 */ +        DNSSEC_ALGORITHM_RSASHA512 = 10, /* RFC 5702 */ +        DNSSEC_ALGORITHM_INDIRECT = 252, +        DNSSEC_ALGORITHM_PRIVATEDNS, +        DNSSEC_ALGORITHM_PRIVATEOID, +        _DNSSEC_ALGORITHM_MAX_DEFINED +}; + +/* DNSSEC digest identifiers, see + * https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml */ +enum { +        DNSSEC_DIGEST_SHA1 = 1, +        DNSSEC_DIGEST_SHA256 = 2, +        _DNSSEC_DIGEST_MAX_DEFINED +}; +  struct DnsResourceKey {          unsigned n_ref;          uint16_t class, type;          char *_name; /* don't access directy, use DNS_RESOURCE_KEY_NAME()! */ +        bool cache_flush:1;  }; +/* Creates a temporary resource key. This is only useful to quickly + * look up something, without allocating a full DnsResourceKey object + * for it. Note that it is not OK to take references to this kind of + * resource key object. */ +#define DNS_RESOURCE_KEY_CONST(c, t, n)                 \ +        ((DnsResourceKey) {                             \ +                .n_ref = (unsigned) -1,                 \ +                .class = c,                             \ +                .type = t,                              \ +                ._name = (char*) n,                     \ +        }) + +  struct DnsTxtItem {          size_t length;          LIST_FIELDS(DnsTxtItem, items); @@ -57,7 +105,11 @@ struct DnsResourceRecord {          unsigned n_ref;          DnsResourceKey *key;          uint32_t ttl; -        bool unparseable; +        bool unparseable:1; +        bool wire_format_canonical:1; +        void *wire_format; +        size_t wire_format_size; +        size_t wire_format_rdata_offset;          union {                  struct {                          void *data; @@ -135,8 +187,8 @@ struct DnsResourceRecord {                  /* http://tools.ietf.org/html/rfc4034#section-2.1 */                  struct { -                        bool zone_key_flag:1; -                        bool sep_flag:1; +                        uint16_t flags; +                        uint8_t protocol;                          uint8_t algorithm;                          void* key;                          size_t key_size; @@ -186,19 +238,22 @@ static inline const char* DNS_RESOURCE_KEY_NAME(const DnsResourceKey *key) {  }  DnsResourceKey* dns_resource_key_new(uint16_t class, uint16_t type, const char *name); -DnsResourceKey* dns_resource_key_new_cname(const DnsResourceKey *key); -DnsResourceKey* dns_resource_key_new_dname(const DnsResourceKey *key);  DnsResourceKey* dns_resource_key_new_redirect(const DnsResourceKey *key, const DnsResourceRecord *cname);  int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key, char *name);  DnsResourceKey* dns_resource_key_new_consume(uint16_t class, uint16_t type, char *name);  DnsResourceKey* dns_resource_key_ref(DnsResourceKey *key);  DnsResourceKey* dns_resource_key_unref(DnsResourceKey *key); +bool dns_resource_key_is_address(const DnsResourceKey *key);  int dns_resource_key_equal(const DnsResourceKey *a, const DnsResourceKey *b);  int dns_resource_key_match_rr(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain);  int dns_resource_key_match_cname(const DnsResourceKey *key, const DnsResourceRecord *rr, const char *search_domain);  int dns_resource_key_to_string(const DnsResourceKey *key, char **ret);  DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceKey*, dns_resource_key_unref); +static inline bool dns_key_is_shared(const DnsResourceKey *key) { +        return IN_SET(key->type, DNS_TYPE_PTR); +} +  DnsResourceRecord* dns_resource_record_new(DnsResourceKey *key);  DnsResourceRecord* dns_resource_record_new_full(uint16_t class, uint16_t type, const char *name);  DnsResourceRecord* dns_resource_record_ref(DnsResourceRecord *rr); @@ -209,6 +264,8 @@ int dns_resource_record_equal(const DnsResourceRecord *a, const DnsResourceRecor  int dns_resource_record_to_string(const DnsResourceRecord *rr, char **ret);  DEFINE_TRIVIAL_CLEANUP_FUNC(DnsResourceRecord*, dns_resource_record_unref); +int dns_resource_record_to_wire_format(DnsResourceRecord *rr, bool canonical); +  DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i);  bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); @@ -216,3 +273,9 @@ const char *dns_class_to_string(uint16_t type);  int dns_class_from_string(const char *name, uint16_t *class);  extern const struct hash_ops dns_resource_key_hash_ops; + +const char* dnssec_algorithm_to_string(int i) _const_; +int dnssec_algorithm_from_string(const char *s) _pure_; + +const char *dnssec_digest_to_string(int i) _const_; +int dnssec_digest_from_string(const char *s) _pure_; diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index 09e6872d26..4d83ac597c 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -30,6 +30,7 @@  #include "random-util.h"  #include "resolved-dns-scope.h"  #include "resolved-llmnr.h" +#include "resolved-mdns.h"  #include "socket-util.h"  #include "strv.h" @@ -59,6 +60,7 @@ int dns_scope_new(Manager *m, DnsScope **ret, Link *l, DnsProtocol protocol, int          LIST_PREPEND(scopes, m->dns_scopes, s);          dns_scope_llmnr_membership(s, true); +        dns_scope_mdns_membership(s, true);          log_debug("New scope on link %s, protocol %s, family %s", l ? l->name : "*", dns_protocol_to_string(protocol), family == AF_UNSPEC ? "*" : af_to_name(family)); @@ -95,6 +97,7 @@ DnsScope* dns_scope_free(DnsScope *s) {          log_debug("Removing scope on link %s, protocol %s, family %s", s->link ? s->link->name : "*", dns_protocol_to_string(s->protocol), s->family == AF_UNSPEC ? "*" : af_to_name(s->family));          dns_scope_llmnr_membership(s, false); +        dns_scope_mdns_membership(s, false);          dns_scope_abort_transactions(s);          while (s->query_candidates) @@ -158,11 +161,10 @@ void dns_scope_packet_lost(DnsScope *s, usec_t usec) {                  s->resend_timeout = MIN(s->resend_timeout * 2, MULTICAST_RESEND_TIMEOUT_MAX_USEC);  } -int dns_scope_emit(DnsScope *s, int fd, DnsServer *server, DnsPacket *p) { +static int dns_scope_emit_one(DnsScope *s, int fd, DnsServer *server, DnsPacket *p) {          union in_addr_union addr;          int ifindex = 0, r;          int family; -        uint16_t port;          uint32_t mtu;          size_t saved_size = 0; @@ -228,7 +230,6 @@ int dns_scope_emit(DnsScope *s, int fd, DnsServer *server, DnsPacket *p) {                          return -EBUSY;                  family = s->family; -                port = LLMNR_PORT;                  if (family == AF_INET) {                          addr.in = LLMNR_MULTICAST_IPV4_ADDRESS; @@ -241,7 +242,30 @@ int dns_scope_emit(DnsScope *s, int fd, DnsServer *server, DnsPacket *p) {                  if (fd < 0)                          return fd; -                r = manager_send(s->manager, fd, ifindex, family, &addr, port, p); +                r = manager_send(s->manager, fd, ifindex, family, &addr, LLMNR_PORT, p); +                if (r < 0) +                        return r; + +                break; + +        case DNS_PROTOCOL_MDNS: +                if (!ratelimit_test(&s->ratelimit)) +                        return -EBUSY; + +                family = s->family; + +                if (family == AF_INET) { +                        addr.in = MDNS_MULTICAST_IPV4_ADDRESS; +                        fd = manager_mdns_ipv4_fd(s->manager); +                } else if (family == AF_INET6) { +                        addr.in6 = MDNS_MULTICAST_IPV6_ADDRESS; +                        fd = manager_mdns_ipv6_fd(s->manager); +                } else +                        return -EAFNOSUPPORT; +                if (fd < 0) +                        return fd; + +                r = manager_send(s->manager, fd, ifindex, family, &addr, MDNS_PORT, p);                  if (r < 0)                          return r; @@ -254,6 +278,31 @@ int dns_scope_emit(DnsScope *s, int fd, DnsServer *server, DnsPacket *p) {          return 1;  } +int dns_scope_emit(DnsScope *s, int fd, DnsServer *server, DnsPacket *p) { +        int r; + +        assert(s); +        assert(p); +        assert(p->protocol == s->protocol); +        assert((s->protocol == DNS_PROTOCOL_DNS) != (fd < 0)); + +        do { +                /* If there are multiple linked packets, set the TC bit in all but the last of them */ +                if (p->more) { +                        assert(p->protocol == DNS_PROTOCOL_MDNS); +                        dns_packet_set_flags(p, true, true); +                } + +                r = dns_scope_emit_one(s, fd, server, p); +                if (r < 0) +                        return r; + +                p = p->more; +        } while(p); + +        return 0; +} +  static int dns_scope_socket(DnsScope *s, int type, int family, const union in_addr_union *address, uint16_t port, DnsServer **server) {          DnsServer *srv = NULL;          _cleanup_close_ int fd = -1; @@ -368,13 +417,14 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co          assert(s);          assert(domain); -        if (ifindex != 0 && (!s->link || s->link->ifindex != ifindex)) -                return DNS_SCOPE_NO; +        /* Checks if the specified domain is something to look up on +         * this scope. Note that this accepts non-qualified hostnames, +         * i.e. those without any search path prefixed yet. */ -        if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family) & flags) == 0) +        if (ifindex != 0 && (!s->link || s->link->ifindex != ifindex))                  return DNS_SCOPE_NO; -        if (dns_name_is_root(domain)) +        if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family, 0) & flags) == 0)                  return DNS_SCOPE_NO;          /* Never resolve any loopback hostname or IP address via DNS, @@ -385,6 +435,12 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co              dns_name_equal(domain, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0)                  return DNS_SCOPE_NO; +        /* Never respond to some of the domains listed in RFC6303 */ +        if (dns_name_endswith(domain, "0.in-addr.arpa") > 0 || +            dns_name_equal(domain, "255.255.255.255.in-addr.arpa") > 0 || +            dns_name_equal(domain, "0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa") > 0) +                return DNS_SCOPE_NO; +          /* Always honour search domains for routing queries. Note that           * we return DNS_SCOPE_YES here, rather than just           * DNS_SCOPE_MAYBE, which means wildcard scopes won't be @@ -397,10 +453,16 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co          case DNS_PROTOCOL_DNS: -                if ((!dns_name_is_single_label(domain) || -                     (!(flags & SD_RESOLVED_NO_SEARCH) && dns_scope_has_search_domains(s))) && -                    dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 && -                    dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0) +                /* Exclude link-local IP ranges */ +                if (dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 && +                    dns_name_endswith(domain, "8.e.f.ip6.arpa") == 0 && +                    dns_name_endswith(domain, "9.e.f.ip6.arpa") == 0 && +                    dns_name_endswith(domain, "a.e.f.ip6.arpa") == 0 && +                    dns_name_endswith(domain, "b.e.f.ip6.arpa") == 0 && +                    /* If networks use .local in their private setups, they are supposed to also add .local to their search +                     * domains, which we already checked above. Otherwise, we consider .local specific to mDNS and won't +                     * send such queries ordinary DNS servers. */ +                    dns_name_endswith(domain, "local") == 0)                          return DNS_SCOPE_MAYBE;                  return DNS_SCOPE_NO; @@ -434,8 +496,27 @@ int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {          assert(s);          assert(key); -        if (s->protocol == DNS_PROTOCOL_DNS) -                return true; +        /* Check if it makes sense to resolve the specified key on +         * this scope. Note that this call assumes as fully qualified +         * name, i.e. the search suffixes already appended. */ + +        if (s->protocol == DNS_PROTOCOL_DNS) { + +                /* On classic DNS, lookin up non-address RRs is always +                 * fine. (Specifically, we want to permit looking up +                 * DNSKEY and DS records on the root and top-level +                 * domains.) */ +                if (!dns_resource_key_is_address(key)) +                        return true; + +                /* However, we refuse to look up A and AAAA RRs on the +                 * root and single-label domains, under the assumption +                 * that those should be resolved via LLMNR or search +                 * path only, and should not be leaked onto the +                 * internet. */ +                return !(dns_name_is_single_label(DNS_RESOURCE_KEY_NAME(key)) || +                         dns_name_is_root(DNS_RESOURCE_KEY_NAME(key))); +        }          /* On mDNS and LLMNR, send A and AAAA queries only on the           * respective scopes */ @@ -449,19 +530,15 @@ int dns_scope_good_key(DnsScope *s, DnsResourceKey *key) {          return true;  } -int dns_scope_llmnr_membership(DnsScope *s, bool b) { +static int dns_scope_multicast_membership(DnsScope *s, bool b, struct in_addr in, struct in6_addr in6) {          int fd;          assert(s); - -        if (s->protocol != DNS_PROTOCOL_LLMNR) -                return 0; -          assert(s->link);          if (s->family == AF_INET) {                  struct ip_mreqn mreqn = { -                        .imr_multiaddr = LLMNR_MULTICAST_IPV4_ADDRESS, +                        .imr_multiaddr = in,                          .imr_ifindex = s->link->ifindex,                  }; @@ -480,7 +557,7 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) {          } else if (s->family == AF_INET6) {                  struct ipv6_mreq mreq = { -                        .ipv6mr_multiaddr = LLMNR_MULTICAST_IPV6_ADDRESS, +                        .ipv6mr_multiaddr = in6,                          .ipv6mr_interface = s->link->ifindex,                  }; @@ -499,6 +576,22 @@ int dns_scope_llmnr_membership(DnsScope *s, bool b) {          return 0;  } +int dns_scope_llmnr_membership(DnsScope *s, bool b) { + +        if (s->protocol != DNS_PROTOCOL_LLMNR) +                return 0; + +        return dns_scope_multicast_membership(s, b, LLMNR_MULTICAST_IPV4_ADDRESS, LLMNR_MULTICAST_IPV6_ADDRESS); +} + +int dns_scope_mdns_membership(DnsScope *s, bool b) { + +        if (s->protocol != DNS_PROTOCOL_MDNS) +                return 0; + +        return dns_scope_multicast_membership(s, b, MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS); +} +  static int dns_scope_make_reply_packet(                  DnsScope *s,                  uint16_t id, @@ -549,7 +642,7 @@ static int dns_scope_make_reply_packet(          if (answer) {                  for (i = 0; i < answer->n_rrs; i++) { -                        r = dns_packet_append_rr(p, answer->items[i].rr, NULL); +                        r = dns_packet_append_rr(p, answer->items[i].rr, NULL, NULL);                          if (r < 0)                                  return r;                  } @@ -559,7 +652,7 @@ static int dns_scope_make_reply_packet(          if (soa) {                  for (i = 0; i < soa->n_rrs; i++) { -                        r = dns_packet_append_rr(p, soa->items[i].rr, NULL); +                        r = dns_packet_append_rr(p, soa->items[i].rr, NULL, NULL);                          if (r < 0)                                  return r;                  } @@ -733,7 +826,7 @@ static int dns_scope_make_conflict_packet(          if (r < 0)                  return r; -        r = dns_packet_append_rr(p, rr, NULL); +        r = dns_packet_append_rr(p, rr, NULL, NULL);          if (r < 0)                  return r; @@ -901,34 +994,13 @@ void dns_scope_dump(DnsScope *s, FILE *f) {  DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s) {          assert(s); -        /* Returns the list of *local* search domains -- not the -         * global ones. */ -          if (s->protocol != DNS_PROTOCOL_DNS)                  return NULL;          if (s->link)                  return s->link->search_domains; -        return NULL; -} - -bool dns_scope_has_search_domains(DnsScope *s) { -        assert(s); - -        /* Tests if there are *any* search domains suitable for this -         * scope. This means either local or global ones */ - -        if (s->protocol != DNS_PROTOCOL_DNS) -                return false; - -        if (s->manager->search_domains) -                return true; - -        if (s->link && s->link->search_domains) -                return true; - -        return false; +        return s->manager->search_domains;  }  bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) { diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 0480f702f8..2fc2e07deb 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -26,6 +26,7 @@  typedef struct DnsScope DnsScope;  #include "resolved-dns-cache.h" +#include "resolved-dns-dnssec.h"  #include "resolved-dns-packet.h"  #include "resolved-dns-server.h"  #include "resolved-dns-zone.h" @@ -44,6 +45,7 @@ struct DnsScope {          DnsProtocol protocol;          int family; +        DnssecMode dnssec_mode;          Link *link; @@ -91,6 +93,7 @@ DnsServer *dns_scope_get_dns_server(DnsScope *s);  void dns_scope_next_dns_server(DnsScope *s);  int dns_scope_llmnr_membership(DnsScope *s, bool b); +int dns_scope_mdns_membership(DnsScope *s, bool b);  void dns_scope_process_query(DnsScope *s, DnsStream *stream, DnsPacket *p); @@ -102,6 +105,5 @@ void dns_scope_check_conflicts(DnsScope *scope, DnsPacket *p);  void dns_scope_dump(DnsScope *s, FILE *f);  DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s); -bool dns_scope_has_search_domains(DnsScope *s);  bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name); diff --git a/src/resolve/resolved-dns-server.h b/src/resolve/resolved-dns-server.h index 00366a48c9..b07fc3af3d 100644 --- a/src/resolve/resolved-dns-server.h +++ b/src/resolve/resolved-dns-server.h @@ -61,10 +61,11 @@ struct DnsServer {          int family;          union in_addr_union address; +        bool marked:1; +          usec_t resend_timeout;          usec_t max_rtt; -        bool marked:1;          DnsServerFeatureLevel verified_features;          DnsServerFeatureLevel possible_features;          size_t received_udp_packet_max; diff --git a/src/resolve/resolved-dns-transaction.c b/src/resolve/resolved-dns-transaction.c index 90133cb332..90f07e6c4b 100644 --- a/src/resolve/resolved-dns-transaction.c +++ b/src/resolve/resolved-dns-transaction.c @@ -24,6 +24,7 @@  #include "dns-domain.h"  #include "fd-util.h"  #include "random-util.h" +#include "resolved-dns-cache.h"  #include "resolved-dns-transaction.h"  #include "resolved-llmnr.h"  #include "string-table.h" @@ -243,7 +244,7 @@ static int on_stream_complete(DnsStream *s, int error) {          }          if (dns_packet_validate_reply(p) <= 0) { -                log_debug("Invalid LLMNR TCP packet."); +                log_debug("Invalid TCP reply packet.");                  dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY);                  return 0;          } @@ -384,6 +385,18 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {                  break; +        case DNS_PROTOCOL_MDNS: +                assert(t->scope->link); + +                /* For mDNS we will not accept any packets from other interfaces */ +                if (p->ifindex != t->scope->link->ifindex) +                        return; + +                if (p->family != t->scope->family) +                        return; + +                break; +          case DNS_PROTOCOL_DNS:                  break; @@ -446,6 +459,13 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {          }          if (DNS_PACKET_TC(p)) { + +                /* Truncated packets for mDNS are not allowed. Give up immediately. */ +                if (t->scope->protocol == DNS_PROTOCOL_MDNS) { +                        dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); +                        return; +                } +                  /* Response was truncated, let's try again with good old TCP */                  r = dns_transaction_open_tcp(t);                  if (r == -ESRCH) { @@ -454,7 +474,7 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {                          return;                  }                  if (r < 0) { -                        /* On LLMNR, if we cannot connect to the host, +                        /* On LLMNR and mDNS, if we cannot connect to the host,                           * we immediately give up */                          if (t->scope->protocol == DNS_PROTOCOL_LLMNR) {                                  dns_transaction_complete(t, DNS_TRANSACTION_RESOURCES); @@ -481,21 +501,32 @@ void dns_transaction_process_reply(DnsTransaction *t, DnsPacket *p) {                  return;          } -        /* Install the answer as answer to the transaction */ -        dns_answer_unref(t->answer); -        t->answer = dns_answer_ref(p->answer); -        t->answer_rcode = DNS_PACKET_RCODE(p); +        if (t->scope->protocol == DNS_PROTOCOL_DNS) { +                /* Only consider responses with equivalent query section to the request */ +                if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) { +                        dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); +                        return; +                } -        /* Only consider responses with equivalent query section to the request */ -        if (p->question->n_keys != 1 || dns_resource_key_equal(p->question->keys[0], t->key) <= 0) { -                dns_transaction_complete(t, DNS_TRANSACTION_INVALID_REPLY); -                return; +                /* Install the answer as answer to the transaction */ +                dns_answer_unref(t->answer); +                t->answer = dns_answer_ref(p->answer); +                t->answer_rcode = DNS_PACKET_RCODE(p); +                t->answer_authenticated = t->scope->dnssec_mode == DNSSEC_TRUST && DNS_PACKET_AD(p); + +                /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */ +                if (DNS_PACKET_SHALL_CACHE(p)) +                        dns_cache_put(&t->scope->cache, +                                      t->key, +                                      DNS_PACKET_RCODE(p), +                                      p->answer, +                                      DNS_PACKET_ANCOUNT(p), +                                      t->answer_authenticated, +                                      0, +                                      p->family, +                                      &p->sender);          } -        /* According to RFC 4795, section 2.9. only the RRs from the answer section shall be cached */ -        if (DNS_PACKET_SHALL_CACHE(p)) -                dns_cache_put(&t->scope->cache, t->key, DNS_PACKET_RCODE(p), p->answer, DNS_PACKET_ANCOUNT(p), 0, p->family, &p->sender); -          if (DNS_PACKET_RCODE(p) == DNS_RCODE_SUCCESS)                  dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);          else @@ -562,21 +593,26 @@ static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdat          assert(s);          assert(t); -        /* Timeout reached? Increase the timeout for the server used */ -        switch (t->scope->protocol) { -        case DNS_PROTOCOL_DNS: -                assert(t->server); +        if (!t->initial_jitter_scheduled || t->initial_jitter_elapsed) { +                /* Timeout reached? Increase the timeout for the server used */ +                switch (t->scope->protocol) { +                case DNS_PROTOCOL_DNS: +                        assert(t->server); -                dns_server_packet_lost(t->server, t->current_features, usec - t->start_usec); +                        dns_server_packet_lost(t->server, t->current_features, usec - t->start_usec); -                break; -        case DNS_PROTOCOL_LLMNR: -        case DNS_PROTOCOL_MDNS: -                dns_scope_packet_lost(t->scope, usec - t->start_usec); +                        break; +                case DNS_PROTOCOL_LLMNR: +                case DNS_PROTOCOL_MDNS: +                        dns_scope_packet_lost(t->scope, usec - t->start_usec); -                break; -        default: -                assert_not_reached("Invalid DNS protocol."); +                        break; +                default: +                        assert_not_reached("Invalid DNS protocol."); +                } + +                if (t->initial_jitter_scheduled) +                        t->initial_jitter_elapsed = true;          }          /* ...and try again with a new server */ @@ -589,38 +625,6 @@ static int on_transaction_timeout(sd_event_source *s, usec_t usec, void *userdat          return 0;  } -static int dns_transaction_make_packet(DnsTransaction *t) { -        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; -        int r; - -        assert(t); - -        if (t->sent) -                return 0; - -        r = dns_packet_new_query(&p, t->scope->protocol, 0); -        if (r < 0) -                return r; - -        r = dns_scope_good_key(t->scope, t->key); -        if (r < 0) -                return r; -        if (r == 0) -                return -EDOM; - -        r = dns_packet_append_key(p, t->key, NULL); -        if (r < 0) -                return r; - -        DNS_PACKET_HEADER(p)->qdcount = htobe16(1); -        DNS_PACKET_HEADER(p)->id = t->id; - -        t->sent = p; -        p = NULL; - -        return 0; -} -  static usec_t transaction_get_resend_timeout(DnsTransaction *t) {          assert(t);          assert(t->scope); @@ -630,17 +634,18 @@ static usec_t transaction_get_resend_timeout(DnsTransaction *t) {                  assert(t->server);                  return t->server->resend_timeout; -        case DNS_PROTOCOL_LLMNR:          case DNS_PROTOCOL_MDNS: +                assert(t->n_attempts > 0); +                return (1 << (t->n_attempts - 1)) * USEC_PER_SEC; +        case DNS_PROTOCOL_LLMNR:                  return t->scope->resend_timeout;          default:                  assert_not_reached("Invalid DNS protocol.");          }  } -int dns_transaction_go(DnsTransaction *t) { +static int dns_transaction_prepare_next_attempt(DnsTransaction *t, usec_t ts) {          bool had_stream; -        usec_t ts;          int r;          assert(t); @@ -649,11 +654,6 @@ int dns_transaction_go(DnsTransaction *t) {          dns_transaction_stop(t); -        log_debug("Excercising transaction on scope %s on %s/%s", -                  dns_protocol_to_string(t->scope->protocol), -                  t->scope->link ? t->scope->link->name : "*", -                  t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family)); -          if (t->n_attempts >= TRANSACTION_ATTEMPTS_MAX(t->scope->protocol)) {                  dns_transaction_complete(t, DNS_TRANSACTION_ATTEMPTS_MAX_REACHED);                  return 0; @@ -666,8 +666,6 @@ int dns_transaction_go(DnsTransaction *t) {                  return 0;          } -        assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); -          t->n_attempts++;          t->start_usec = ts;          t->received = dns_packet_unref(t->received); @@ -675,7 +673,21 @@ int dns_transaction_go(DnsTransaction *t) {          t->answer_rcode = 0;          t->answer_source = _DNS_TRANSACTION_SOURCE_INVALID; -        /* Check the zone, but obly if this transaction is not used +        /* Check the trust anchor. Do so only on classic DNS, since DNSSEC does not apply otherwise. */ +        if (t->scope->protocol == DNS_PROTOCOL_DNS) { +                r = dns_trust_anchor_lookup(&t->scope->manager->trust_anchor, t->key, &t->answer); +                if (r < 0) +                        return r; +                if (r > 0) { +                        t->answer_rcode = DNS_RCODE_SUCCESS; +                        t->answer_source = DNS_TRANSACTION_TRUST_ANCHOR; +                        t->answer_authenticated = true; +                        dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS); +                        return 0; +                } +        } + +        /* Check the zone, but only if this transaction is not used           * for probing or verifying a zone item. */          if (set_isempty(t->zone_items)) { @@ -685,6 +697,7 @@ int dns_transaction_go(DnsTransaction *t) {                  if (r > 0) {                          t->answer_rcode = DNS_RCODE_SUCCESS;                          t->answer_source = DNS_TRANSACTION_ZONE; +                        t->answer_authenticated = true;                          dns_transaction_complete(t, DNS_TRANSACTION_SUCCESS);                          return 0;                  } @@ -702,7 +715,7 @@ int dns_transaction_go(DnsTransaction *t) {                  /* Let's then prune all outdated entries */                  dns_cache_prune(&t->scope->cache); -                r = dns_cache_lookup(&t->scope->cache, t->key, &t->answer_rcode, &t->answer); +                r = dns_cache_lookup(&t->scope->cache, t->key, &t->answer_rcode, &t->answer, &t->answer_authenticated);                  if (r < 0)                          return r;                  if (r > 0) { @@ -715,31 +728,203 @@ int dns_transaction_go(DnsTransaction *t) {                  }          } -        if (t->scope->protocol == DNS_PROTOCOL_LLMNR && !t->initial_jitter) { -                usec_t jitter; +        return 1; +} + +static int dns_transaction_make_packet_mdns(DnsTransaction *t) { + +        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; +        bool add_known_answers = false; +        DnsTransaction *other; +        unsigned qdcount; +        usec_t ts; +        int r; + +        assert(t); +        assert(t->scope->protocol == DNS_PROTOCOL_MDNS); + +        /* Discard any previously prepared packet, so we can start over and coaleasce again */ +        t->sent = dns_packet_unref(t->sent); + +        r = dns_packet_new_query(&p, t->scope->protocol, 0, false); +        if (r < 0) +                return r; + +        r = dns_packet_append_key(p, t->key, NULL); +        if (r < 0) +                return r; + +        qdcount = 1; + +        if (dns_key_is_shared(t->key)) +                add_known_answers = true; + +        /* +         * For mDNS, we want to coalesce as many open queries in pending transactions into one single +         * query packet on the wire as possible. To achieve that, we iterate through all pending transactions +         * in our current scope, and see whether their timing contraints allow them to be sent. +         */ + +        assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); + +        LIST_FOREACH(transactions_by_scope, other, t->scope->transactions) { + +                /* Skip ourselves */ +                if (other == t) +                        continue; + +                if (other->state != DNS_TRANSACTION_PENDING) +                        continue; + +                if (other->next_attempt_after > ts) +                        continue; + +                if (qdcount >= UINT16_MAX) +                        break; + +                r = dns_packet_append_key(p, other->key, NULL); + +                /* +                 * If we can't stuff more questions into the packet, just give up. +                 * One of the 'other' transactions will fire later and take care of the rest. +                 */ +                if (r == -EMSGSIZE) +                        break; + +                if (r < 0) +                        return r; + +                r = dns_transaction_prepare_next_attempt(other, ts); +                if (r <= 0) +                        continue; + +                ts += transaction_get_resend_timeout(other); + +                r = sd_event_add_time( +                                other->scope->manager->event, +                                &other->timeout_event_source, +                                clock_boottime_or_monotonic(), +                                ts, 0, +                                on_transaction_timeout, other); +                if (r < 0) +                        return r; + +                other->state = DNS_TRANSACTION_PENDING; +                other->next_attempt_after = ts; + +                qdcount ++; + +                if (dns_key_is_shared(other->key)) +                        add_known_answers = true; +        } + +        DNS_PACKET_HEADER(p)->qdcount = htobe16(qdcount); +        DNS_PACKET_HEADER(p)->id = t->id; + +        /* Append known answer section if we're asking for any shared record */ +        if (add_known_answers) { +                r = dns_cache_export_shared_to_packet(&t->scope->cache, p); +                if (r < 0) +                        return r; +        } + +        t->sent = p; +        p = NULL; + +        return 0; +} + +static int dns_transaction_make_packet(DnsTransaction *t) { +        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; +        int r; + +        assert(t); + +        if (t->scope->protocol == DNS_PROTOCOL_MDNS) +                return dns_transaction_make_packet_mdns(t); + +        if (t->sent) +                return 0; + +        r = dns_packet_new_query(&p, t->scope->protocol, 0, t->scope->dnssec_mode == DNSSEC_YES); +        if (r < 0) +                return r; + +        r = dns_scope_good_key(t->scope, t->key); +        if (r < 0) +                return r; +        if (r == 0) +                return -EDOM; + +        r = dns_packet_append_key(p, t->key, NULL); +        if (r < 0) +                return r; + +        DNS_PACKET_HEADER(p)->qdcount = htobe16(1); +        DNS_PACKET_HEADER(p)->id = t->id; + +        t->sent = p; +        p = NULL; + +        return 0; +} + +int dns_transaction_go(DnsTransaction *t) { +        usec_t ts; +        int r; + +        assert(t); + +        assert_se(sd_event_now(t->scope->manager->event, clock_boottime_or_monotonic(), &ts) >= 0); +        r = dns_transaction_prepare_next_attempt(t, ts); +        if (r <= 0) +                return r; + +        log_debug("Excercising transaction on scope %s on %s/%s", +                  dns_protocol_to_string(t->scope->protocol), +                  t->scope->link ? t->scope->link->name : "*", +                  t->scope->family == AF_UNSPEC ? "*" : af_to_name(t->scope->family)); + +        if (!t->initial_jitter_scheduled && +            (t->scope->protocol == DNS_PROTOCOL_LLMNR || +             t->scope->protocol == DNS_PROTOCOL_MDNS)) { +                usec_t jitter, accuracy;                  /* RFC 4795 Section 2.7 suggests all queries should be                   * delayed by a random time from 0 to JITTER_INTERVAL. */ -                t->initial_jitter = true; +                t->initial_jitter_scheduled = true;                  random_bytes(&jitter, sizeof(jitter)); -                jitter %= LLMNR_JITTER_INTERVAL_USEC; + +                switch (t->scope->protocol) { +                case DNS_PROTOCOL_LLMNR: +                        jitter %= LLMNR_JITTER_INTERVAL_USEC; +                        accuracy = LLMNR_JITTER_INTERVAL_USEC; +                        break; +                case DNS_PROTOCOL_MDNS: +                        jitter %= MDNS_JITTER_RANGE_USEC; +                        jitter += MDNS_JITTER_MIN_USEC; +                        accuracy = MDNS_JITTER_RANGE_USEC; +                        break; +                default: +                        assert_not_reached("bad protocol"); +                }                  r = sd_event_add_time(                                  t->scope->manager->event,                                  &t->timeout_event_source,                                  clock_boottime_or_monotonic(), -                                ts + jitter, -                                LLMNR_JITTER_INTERVAL_USEC, +                                ts + jitter, accuracy,                                  on_transaction_timeout, t);                  if (r < 0)                          return r;                  t->n_attempts = 0; +                t->next_attempt_after = ts;                  t->state = DNS_TRANSACTION_PENDING; -                log_debug("Delaying LLMNR transaction for " USEC_FMT "us.", jitter); +                log_debug("Delaying %s transaction for " USEC_FMT "us.", dns_protocol_to_string(t->scope->protocol), jitter);                  return 0;          } @@ -786,16 +971,20 @@ int dns_transaction_go(DnsTransaction *t) {                  return dns_transaction_go(t);          } +        ts += transaction_get_resend_timeout(t); +          r = sd_event_add_time(                          t->scope->manager->event,                          &t->timeout_event_source,                          clock_boottime_or_monotonic(), -                        ts + transaction_get_resend_timeout(t), 0, +                        ts, 0,                          on_transaction_timeout, t);          if (r < 0)                  return r;          t->state = DNS_TRANSACTION_PENDING; +        t->next_attempt_after = ts; +          return 1;  } @@ -817,5 +1006,6 @@ static const char* const dns_transaction_source_table[_DNS_TRANSACTION_SOURCE_MA          [DNS_TRANSACTION_NETWORK] = "network",          [DNS_TRANSACTION_CACHE] = "cache",          [DNS_TRANSACTION_ZONE] = "zone", +        [DNS_TRANSACTION_TRUST_ANCHOR] = "trust-anchor",  };  DEFINE_STRING_TABLE_LOOKUP(dns_transaction_source, DnsTransactionSource); diff --git a/src/resolve/resolved-dns-transaction.h b/src/resolve/resolved-dns-transaction.h index 5778913cc8..af08b20e44 100644 --- a/src/resolve/resolved-dns-transaction.h +++ b/src/resolve/resolved-dns-transaction.h @@ -44,6 +44,7 @@ enum DnsTransactionSource {          DNS_TRANSACTION_NETWORK,          DNS_TRANSACTION_CACHE,          DNS_TRANSACTION_ZONE, +        DNS_TRANSACTION_TRUST_ANCHOR,          _DNS_TRANSACTION_SOURCE_MAX,          _DNS_TRANSACTION_SOURCE_INVALID = -1  }; @@ -61,15 +62,18 @@ struct DnsTransaction {          DnsTransactionState state;          uint16_t id; -        bool initial_jitter; +        bool initial_jitter_scheduled; +        bool initial_jitter_elapsed;          DnsPacket *sent, *received;          DnsAnswer *answer;          int answer_rcode;          DnsTransactionSource answer_source; +        bool answer_authenticated;          usec_t start_usec; +        usec_t next_attempt_after;          sd_event_source *timeout_event_source;          unsigned n_attempts; @@ -117,6 +121,10 @@ DnsTransactionSource dns_transaction_source_from_string(const char *s) _pure_;  /* LLMNR Jitter interval, see RFC 4795 Section 7 */  #define LLMNR_JITTER_INTERVAL_USEC (100 * USEC_PER_MSEC) +/* mDNS Jitter interval, see RFC 6762 Section 5.2 */ +#define MDNS_JITTER_MIN_USEC   (20 * USEC_PER_MSEC) +#define MDNS_JITTER_RANGE_USEC (100 * USEC_PER_MSEC) +  /* Maximum attempts to send DNS requests, across all DNS servers */  #define DNS_TRANSACTION_ATTEMPTS_MAX 16 diff --git a/src/resolve/resolved-dns-trust-anchor.c b/src/resolve/resolved-dns-trust-anchor.c new file mode 100644 index 0000000000..e55bdaa1ed --- /dev/null +++ b/src/resolve/resolved-dns-trust-anchor.c @@ -0,0 +1,101 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** +  This file is part of systemd. + +  Copyright 2015 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 "alloc-util.h" +#include "resolved-dns-trust-anchor.h" + +/* The DS RR from https://data.iana.org/root-anchors/root-anchors.xml */ +static const uint8_t root_digest[] = +        { 0x49, 0xAA, 0xC1, 0x1D, 0x7B, 0x6F, 0x64, 0x46, 0x70, 0x2E, 0x54, 0xA1, 0x60, 0x73, 0x71, 0x60, +          0x7A, 0x1A, 0x41, 0x85, 0x52, 0x00, 0xFD, 0x2C, 0xE1, 0xCD, 0xDE, 0x32, 0xF2, 0x4E, 0x8F, 0xB5 }; + +int dns_trust_anchor_load(DnsTrustAnchor *d) { +        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *rr = NULL; +        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; +        int r; + +        assert(d); + +        r = hashmap_ensure_allocated(&d->by_key, &dns_resource_key_hash_ops); +        if (r < 0) +                return r; + +        if (hashmap_get(d->by_key, &DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_DS, "."))) +                return 0; + +        /* Add the RR from https://data.iana.org/root-anchors/root-anchors.xml */ +        rr = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, ""); +        if (!rr) +                return -ENOMEM; + +        rr->ds.key_tag = 19036; +        rr->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; +        rr->ds.digest_type = DNSSEC_DIGEST_SHA256; +        rr->ds.digest_size = sizeof(root_digest); +        rr->ds.digest = memdup(root_digest, rr->ds.digest_size); +        if (!rr->ds.digest) +                return  -ENOMEM; + +        answer = dns_answer_new(1); +        if (!answer) +                return -ENOMEM; + +        r = dns_answer_add(answer, rr, 0); +        if (r < 0) +                return r; + +        r = hashmap_put(d->by_key, rr->key, answer); +        if (r < 0) +                return r; + +        answer = NULL; +        return 0; +} + +void dns_trust_anchor_flush(DnsTrustAnchor *d) { +        DnsAnswer *a; + +        assert(d); + +        while ((a = hashmap_steal_first(d->by_key))) +                dns_answer_unref(a); + +        d->by_key = hashmap_free(d->by_key); +} + +int dns_trust_anchor_lookup(DnsTrustAnchor *d, DnsResourceKey *key, DnsAnswer **ret) { +        DnsAnswer *a; + +        assert(d); +        assert(key); +        assert(ret); + +        /* We only serve DS and DNSKEY RRs. */ +        if (!IN_SET(key->type, DNS_TYPE_DS, DNS_TYPE_DNSKEY)) +                return 0; + +        a = hashmap_get(d->by_key, key); +        if (!a) +                return 0; + +        *ret = dns_answer_ref(a); +        return 1; +} diff --git a/src/resolve/resolved-dns-trust-anchor.h b/src/resolve/resolved-dns-trust-anchor.h new file mode 100644 index 0000000000..06f3723914 --- /dev/null +++ b/src/resolve/resolved-dns-trust-anchor.h @@ -0,0 +1,39 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** +  This file is part of systemd. + +  Copyright 2015 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/>. +***/ + +typedef struct DnsTrustAnchor DnsTrustAnchor; + +#include "hashmap.h" +#include "resolved-dns-answer.h" +#include "resolved-dns-rr.h" + +/* This contains a fixed database mapping domain names to DS or DNSKEY records. */ + +struct DnsTrustAnchor { +        Hashmap *by_key; +}; + +int dns_trust_anchor_load(DnsTrustAnchor *d); +void dns_trust_anchor_flush(DnsTrustAnchor *d); + +int dns_trust_anchor_lookup(DnsTrustAnchor *d, DnsResourceKey* key, DnsAnswer **answer); diff --git a/src/resolve/resolved-dns-zone.c b/src/resolve/resolved-dns-zone.c index 493d11dd14..78f44d51a2 100644 --- a/src/resolve/resolved-dns-zone.c +++ b/src/resolve/resolved-dns-zone.c @@ -163,7 +163,6 @@ static int dns_zone_link_item(DnsZone *z, DnsZoneItem *i) {  }  static int dns_zone_item_probe_start(DnsZoneItem *i)  { -        _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL;          DnsTransaction *t;          int r; @@ -172,12 +171,14 @@ static int dns_zone_item_probe_start(DnsZoneItem *i)  {          if (i->probe_transaction)                  return 0; -        key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)); -        if (!key) -                return -ENOMEM; - -        t = dns_scope_find_transaction(i->scope, key, false); +        t = dns_scope_find_transaction(i->scope, &DNS_RESOURCE_KEY_CONST(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)), false);          if (!t) { +                _cleanup_(dns_resource_key_unrefp) DnsResourceKey *key = NULL; + +                key = dns_resource_key_new(i->rr->key->class, DNS_TYPE_ANY, DNS_RESOURCE_KEY_NAME(i->rr->key)); +                if (!key) +                        return -ENOMEM; +                  r = dns_transaction_new(&t, i->scope, key);                  if (r < 0)                          return r; diff --git a/src/resolve/resolved-gperf.gperf b/src/resolve/resolved-gperf.gperf index 50662656d5..c815eae850 100644 --- a/src/resolve/resolved-gperf.gperf +++ b/src/resolve/resolved-gperf.gperf @@ -18,3 +18,4 @@ Resolve.DNS,          config_parse_dns_servers,    DNS_SERVER_SYSTEM,   0  Resolve.FallbackDNS,  config_parse_dns_servers,    DNS_SERVER_FALLBACK, 0  Resolve.Domains,      config_parse_search_domains, 0,                   0  Resolve.LLMNR,        config_parse_support,        0,                   offsetof(Manager, llmnr_support) +Resolve.DNSSEC,       config_parse_dnssec,         0,                   0 diff --git a/src/resolve/resolved-link.c b/src/resolve/resolved-link.c index ddd9427dab..84100bd988 100644 --- a/src/resolve/resolved-link.c +++ b/src/resolve/resolved-link.c @@ -77,6 +77,8 @@ Link *link_free(Link *l) {          dns_scope_free(l->unicast_scope);          dns_scope_free(l->llmnr_ipv4_scope);          dns_scope_free(l->llmnr_ipv6_scope); +        dns_scope_free(l->mdns_ipv4_scope); +        dns_scope_free(l->mdns_ipv6_scope);          free(l);          return NULL; @@ -118,6 +120,28 @@ static void link_allocate_scopes(Link *l) {                  }          } else                  l->llmnr_ipv6_scope = dns_scope_free(l->llmnr_ipv6_scope); + +        if (link_relevant(l, AF_INET) && +            l->mdns_support != SUPPORT_NO && +            l->manager->mdns_support != SUPPORT_NO) { +                if (!l->mdns_ipv4_scope) { +                        r = dns_scope_new(l->manager, &l->mdns_ipv4_scope, l, DNS_PROTOCOL_MDNS, AF_INET); +                        if (r < 0) +                                log_warning_errno(r, "Failed to allocate mDNS IPv4 scope: %m"); +                } +        } else +                l->mdns_ipv4_scope = dns_scope_free(l->mdns_ipv4_scope); + +        if (link_relevant(l, AF_INET6) && +            l->mdns_support != SUPPORT_NO && +            l->manager->mdns_support != SUPPORT_NO) { +                if (!l->mdns_ipv6_scope) { +                        r = dns_scope_new(l->manager, &l->mdns_ipv6_scope, l, DNS_PROTOCOL_MDNS, AF_INET6); +                        if (r < 0) +                                log_warning_errno(r, "Failed to allocate mDNS IPv6 scope: %m"); +                } +        } else +                l->mdns_ipv6_scope = dns_scope_free(l->mdns_ipv6_scope);  }  void link_add_rrs(Link *l, bool force_remove) { diff --git a/src/resolve/resolved-link.h b/src/resolve/resolved-link.h index eb00015bd5..a3b406bbc2 100644 --- a/src/resolve/resolved-link.h +++ b/src/resolve/resolved-link.h @@ -67,10 +67,13 @@ struct Link {          unsigned n_search_domains;          Support llmnr_support; +        Support mdns_support;          DnsScope *unicast_scope;          DnsScope *llmnr_ipv4_scope;          DnsScope *llmnr_ipv6_scope; +        DnsScope *mdns_ipv4_scope; +        DnsScope *mdns_ipv6_scope;          char name[IF_NAMESIZE];          uint32_t mtu; diff --git a/src/resolve/resolved-llmnr.c b/src/resolve/resolved-llmnr.c index 6a7ff9d245..ed754c3899 100644 --- a/src/resolve/resolved-llmnr.c +++ b/src/resolve/resolved-llmnr.c @@ -461,10 +461,8 @@ int manager_llmnr_ipv6_tcp_fd(Manager *m) {          }          r = sd_event_add_io(m->event, &m->llmnr_ipv6_tcp_event_source, m->llmnr_ipv6_tcp_fd, EPOLLIN, on_llmnr_stream, m); -        if (r < 0)  { -                r = -errno; +        if (r < 0)                  goto fail; -        }          return m->llmnr_ipv6_tcp_fd; diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 62562f0d24..a2677f442a 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -40,6 +40,7 @@  #include "resolved-llmnr.h"  #include "resolved-manager.h"  #include "resolved-resolv-conf.h" +#include "resolved-mdns.h"  #include "socket-util.h"  #include "string-table.h"  #include "string-util.h" @@ -472,12 +473,17 @@ int manager_new(Manager **ret) {          m->llmnr_ipv4_udp_fd = m->llmnr_ipv6_udp_fd = -1;          m->llmnr_ipv4_tcp_fd = m->llmnr_ipv6_tcp_fd = -1; +        m->mdns_ipv4_fd = m->mdns_ipv6_fd = -1;          m->hostname_fd = -1;          m->llmnr_support = SUPPORT_YES;          m->read_resolv_conf = true;          m->need_builtin_fallbacks = true; +        r = dns_trust_anchor_load(&m->trust_anchor); +        if (r < 0) +                return r; +          r = sd_event_default(&m->event);          if (r < 0)                  return r; @@ -524,6 +530,10 @@ int manager_start(Manager *m) {          if (r < 0)                  return r; +        r = manager_mdns_start(m); +        if (r < 0) +                return r; +          return 0;  } @@ -555,6 +565,7 @@ Manager *manager_free(Manager *m) {          sd_event_source_unref(m->rtnl_event_source);          manager_llmnr_stop(m); +        manager_mdns_stop(m);          sd_bus_slot_unref(m->prepare_for_sleep_slot);          sd_event_source_unref(m->bus_retry_event_source); @@ -572,6 +583,8 @@ Manager *manager_free(Manager *m) {          free(m->llmnr_hostname);          free(m->mdns_hostname); +        dns_trust_anchor_flush(&m->trust_anchor); +          free(m);          return NULL; @@ -1018,11 +1031,25 @@ DnsScope* manager_find_scope(Manager *m, DnsPacket *p) {          if (!l)                  return NULL; -        if (p->protocol == DNS_PROTOCOL_LLMNR) { +        switch (p->protocol) { +        case DNS_PROTOCOL_LLMNR:                  if (p->family == AF_INET)                          return l->llmnr_ipv4_scope;                  else if (p->family == AF_INET6)                          return l->llmnr_ipv6_scope; + +                break; + +        case DNS_PROTOCOL_MDNS: +                if (p->family == AF_INET) +                        return l->mdns_ipv4_scope; +                else if (p->family == AF_INET6) +                        return l->mdns_ipv6_scope; + +                break; + +        default: +                break;          }          return NULL; diff --git a/src/resolve/resolved-manager.h b/src/resolve/resolved-manager.h index d00c444583..b52273403a 100644 --- a/src/resolve/resolved-manager.h +++ b/src/resolve/resolved-manager.h @@ -44,6 +44,7 @@ enum Support {  #include "resolved-dns-search-domain.h"  #include "resolved-dns-server.h"  #include "resolved-dns-stream.h" +#include "resolved-dns-trust-anchor.h"  #include "resolved-link.h"  #define MANAGER_SEARCH_DOMAINS_MAX 32 @@ -53,6 +54,7 @@ struct Manager {          sd_event *event;          Support llmnr_support; +        Support mdns_support;          /* Network */          Hashmap *links; @@ -85,6 +87,8 @@ struct Manager {          bool read_resolv_conf:1;          usec_t resolv_conf_mtime; +        DnsTrustAnchor trust_anchor; +          LIST_HEAD(DnsScope, dns_scopes);          DnsScope *unicast_scope; @@ -99,6 +103,13 @@ struct Manager {          sd_event_source *llmnr_ipv4_tcp_event_source;          sd_event_source *llmnr_ipv6_tcp_event_source; +        /* mDNS */ +        int mdns_ipv4_fd; +        int mdns_ipv6_fd; + +        sd_event_source *mdns_ipv4_event_source; +        sd_event_source *mdns_ipv6_event_source; +          /* dbus */          sd_bus *bus;          sd_event_source *bus_retry_event_source; diff --git a/src/resolve/resolved-mdns.c b/src/resolve/resolved-mdns.c new file mode 100644 index 0000000000..abe63d58c1 --- /dev/null +++ b/src/resolve/resolved-mdns.c @@ -0,0 +1,286 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** +  This file is part of systemd. + +  Copyright 2015 Daniel Mack + +  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 <resolv.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +#include "fd-util.h" +#include "resolved-manager.h" +#include "resolved-mdns.h" + +void manager_mdns_stop(Manager *m) { +        assert(m); + +        m->mdns_ipv4_event_source = sd_event_source_unref(m->mdns_ipv4_event_source); +        m->mdns_ipv4_fd = safe_close(m->mdns_ipv4_fd); + +        m->mdns_ipv6_event_source = sd_event_source_unref(m->mdns_ipv6_event_source); +        m->mdns_ipv6_fd = safe_close(m->mdns_ipv6_fd); +} + +int manager_mdns_start(Manager *m) { +        int r; + +        assert(m); + +        if (m->mdns_support == SUPPORT_NO) +                return 0; + +        r = manager_mdns_ipv4_fd(m); +        if (r == -EADDRINUSE) +                goto eaddrinuse; +        if (r < 0) +                return r; + +        if (socket_ipv6_is_supported()) { +                r = manager_mdns_ipv6_fd(m); +                if (r == -EADDRINUSE) +                        goto eaddrinuse; +                if (r < 0) +                        return r; +        } + +        return 0; + +eaddrinuse: +        log_warning("There appears to be another mDNS responder running. Turning off mDNS support."); +        m->mdns_support = SUPPORT_NO; +        manager_mdns_stop(m); + +        return 0; +} + +static int on_mdns_packet(sd_event_source *s, int fd, uint32_t revents, void *userdata) { +        _cleanup_(dns_packet_unrefp) DnsPacket *p = NULL; +        Manager *m = userdata; +        DnsScope *scope; +        int r; + +        r = manager_recv(m, fd, DNS_PROTOCOL_MDNS, &p); +        if (r <= 0) +                return r; + +        scope = manager_find_scope(m, p); +        if (!scope) { +                log_warning("Got mDNS UDP packet on unknown scope. Ignoring."); +                return 0; +        } + +        if (dns_packet_validate_reply(p) > 0) { +                unsigned i; + +                log_debug("Got mDNS reply packet"); + +                /* +                 * mDNS is different from regular DNS and LLMNR with regard to handling responses. +                 * While on other protocols, we can ignore every answer that doesn't match a question +                 * we broadcast earlier, RFC6762, section 18.1 recommends looking at and caching all +                 * incoming information, regardless of the DNS packet ID. +                 * +                 * Hence, extract the packet here, and try to find a transaction for answer the we got +                 * and complete it. Also store the new information in scope's cache. +                 */ +                r = dns_packet_extract(p); +                if (r < 0) { +                        log_debug("mDNS packet extraction failed."); +                        return 0; +                } + +                dns_scope_check_conflicts(scope, p); + +                for (i = 0; i < p->answer->n_rrs; i++) { +                        DnsResourceRecord *rr; +                        DnsTransaction *t; + +                        rr = p->answer->items[i].rr; + +                        t = dns_scope_find_transaction(scope, rr->key, false); +                        if (t) +                                dns_transaction_process_reply(t, p); +                } + +                dns_cache_put(&scope->cache, NULL, DNS_PACKET_RCODE(p), p->answer, +                              p->answer->n_rrs, false, 0, p->family, &p->sender); + +        } else if (dns_packet_validate_query(p) > 0)  { +                log_debug("Got mDNS query packet for id %u", DNS_PACKET_ID(p)); + +                dns_scope_process_query(scope, NULL, p); +        } else +                log_debug("Invalid mDNS UDP packet."); + +        return 0; +} + +int manager_mdns_ipv4_fd(Manager *m) { +        union sockaddr_union sa = { +                .in.sin_family = AF_INET, +                .in.sin_port = htobe16(MDNS_PORT), +        }; +        static const int one = 1, pmtu = IP_PMTUDISC_DONT, ttl = 255; +        int r; + +        assert(m); + +        if (m->mdns_ipv4_fd >= 0) +                return m->mdns_ipv4_fd; + +        m->mdns_ipv4_fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); +        if (m->mdns_ipv4_fd < 0) +                return -errno; + +        r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_TTL, &ttl, sizeof(ttl)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_MULTICAST_TTL, &ttl, sizeof(ttl)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_MULTICAST_LOOP, &one, sizeof(one)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv4_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_PKTINFO, &one, sizeof(one)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_RECVTTL, &one, sizeof(one)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        /* Disable Don't-Fragment bit in the IP header */ +        r = setsockopt(m->mdns_ipv4_fd, IPPROTO_IP, IP_MTU_DISCOVER, &pmtu, sizeof(pmtu)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = bind(m->mdns_ipv4_fd, &sa.sa, sizeof(sa.in)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = sd_event_add_io(m->event, &m->mdns_ipv4_event_source, m->mdns_ipv4_fd, EPOLLIN, on_mdns_packet, m); +        if (r < 0) +                goto fail; + +        return m->mdns_ipv4_fd; + +fail: +        m->mdns_ipv4_fd = safe_close(m->mdns_ipv4_fd); +        return r; +} + +int manager_mdns_ipv6_fd(Manager *m) { +        union sockaddr_union sa = { +                .in6.sin6_family = AF_INET6, +                .in6.sin6_port = htobe16(MDNS_PORT), +        }; +        static const int one = 1, ttl = 255; +        int r; + +        assert(m); + +        if (m->mdns_ipv6_fd >= 0) +                return m->mdns_ipv6_fd; + +        m->mdns_ipv6_fd = socket(AF_INET6, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0); +        if (m->mdns_ipv6_fd < 0) +                return -errno; + +        r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_UNICAST_HOPS, &ttl, sizeof(ttl)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        /* RFC 4795, section 2.5 recommends setting the TTL of UDP packets to 255. */ +        r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, &ttl, sizeof(ttl)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_MULTICAST_LOOP, &one, sizeof(one)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv6_fd, SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = setsockopt(m->mdns_ipv6_fd, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &one, sizeof(one)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = bind(m->mdns_ipv6_fd, &sa.sa, sizeof(sa.in6)); +        if (r < 0) { +                r = -errno; +                goto fail; +        } + +        r = sd_event_add_io(m->event, &m->mdns_ipv6_event_source, m->mdns_ipv6_fd, EPOLLIN, on_mdns_packet, m); +        if (r < 0) +                goto fail; + +        return m->mdns_ipv6_fd; + +fail: +        m->mdns_ipv6_fd = safe_close(m->mdns_ipv6_fd); +        return r; +} diff --git a/src/resolve/resolved-mdns.h b/src/resolve/resolved-mdns.h new file mode 100644 index 0000000000..8a84010615 --- /dev/null +++ b/src/resolve/resolved-mdns.h @@ -0,0 +1,32 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +#pragma once + +/*** +  This file is part of systemd. + +  Copyright 2015 Daniel Mack + +  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 "resolved-manager.h" + +#define MDNS_PORT 5353 + +int manager_mdns_ipv4_fd(Manager *m); +int manager_mdns_ipv6_fd(Manager *m); + +void manager_mdns_stop(Manager *m); +int manager_mdns_start(Manager *m); diff --git a/src/resolve/resolved.conf.in b/src/resolve/resolved.conf.in index 39ecf83217..efc9c6733a 100644 --- a/src/resolve/resolved.conf.in +++ b/src/resolve/resolved.conf.in @@ -16,3 +16,4 @@  #FallbackDNS=@DNS_SERVERS@  #Domains=  #LLMNR=yes +#DNSSEC=no diff --git a/src/resolve/test-dnssec.c b/src/resolve/test-dnssec.c new file mode 100644 index 0000000000..0b2ffeeddd --- /dev/null +++ b/src/resolve/test-dnssec.c @@ -0,0 +1,217 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** +  This file is part of systemd. + +  Copyright 2015 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 <arpa/inet.h> +#include <netinet/in.h> +#include <sys/socket.h> + +#include "alloc-util.h" +#include "resolved-dns-dnssec.h" +#include "resolved-dns-rr.h" +#include "string-util.h" + +static void test_dnssec_verify_rrset(void) { + +        static const uint8_t signature_blob[] = { +                0x7f, 0x79, 0xdd, 0x5e, 0x89, 0x79, 0x18, 0xd0, 0x34, 0x86, 0x8c, 0x72, 0x77, 0x75, 0x48, 0x4d, +                0xc3, 0x7d, 0x38, 0x04, 0xab, 0xcd, 0x9e, 0x4c, 0x82, 0xb0, 0x92, 0xca, 0xe9, 0x66, 0xe9, 0x6e, +                0x47, 0xc7, 0x68, 0x8c, 0x94, 0xf6, 0x69, 0xcb, 0x75, 0x94, 0xe6, 0x30, 0xa6, 0xfb, 0x68, 0x64, +                0x96, 0x1a, 0x84, 0xe1, 0xdc, 0x16, 0x4c, 0x83, 0x6c, 0x44, 0xf2, 0x74, 0x4d, 0x74, 0x79, 0x8f, +                0xf3, 0xf4, 0x63, 0x0d, 0xef, 0x5a, 0xe7, 0xe2, 0xfd, 0xf2, 0x2b, 0x38, 0x7c, 0x28, 0x96, 0x9d, +                0xb6, 0xcd, 0x5c, 0x3b, 0x57, 0xe2, 0x24, 0x78, 0x65, 0xd0, 0x9e, 0x77, 0x83, 0x09, 0x6c, 0xff, +                0x3d, 0x52, 0x3f, 0x6e, 0xd1, 0xed, 0x2e, 0xf9, 0xee, 0x8e, 0xa6, 0xbe, 0x9a, 0xa8, 0x87, 0x76, +                0xd8, 0x77, 0xcc, 0x96, 0xa0, 0x98, 0xa1, 0xd1, 0x68, 0x09, 0x43, 0xcf, 0x56, 0xd9, 0xd1, 0x66, +        }; + +        static const uint8_t dnskey_blob[] = { +                0x03, 0x01, 0x00, 0x01, 0x9b, 0x49, 0x9b, 0xc1, 0xf9, 0x9a, 0xe0, 0x4e, 0xcf, 0xcb, 0x14, 0x45, +                0x2e, 0xc9, 0xf9, 0x74, 0xa7, 0x18, 0xb5, 0xf3, 0xde, 0x39, 0x49, 0xdf, 0x63, 0x33, 0x97, 0x52, +                0xe0, 0x8e, 0xac, 0x50, 0x30, 0x8e, 0x09, 0xd5, 0x24, 0x3d, 0x26, 0xa4, 0x49, 0x37, 0x2b, 0xb0, +                0x6b, 0x1b, 0xdf, 0xde, 0x85, 0x83, 0xcb, 0x22, 0x4e, 0x60, 0x0a, 0x91, 0x1a, 0x1f, 0xc5, 0x40, +                0xb1, 0xc3, 0x15, 0xc1, 0x54, 0x77, 0x86, 0x65, 0x53, 0xec, 0x10, 0x90, 0x0c, 0x91, 0x00, 0x5e, +                0x15, 0xdc, 0x08, 0x02, 0x4c, 0x8c, 0x0d, 0xc0, 0xac, 0x6e, 0xc4, 0x3e, 0x1b, 0x80, 0x19, 0xe4, +                0xf7, 0x5f, 0x77, 0x51, 0x06, 0x87, 0x61, 0xde, 0xa2, 0x18, 0x0f, 0x40, 0x8b, 0x79, 0x72, 0xfa, +                0x8d, 0x1a, 0x44, 0x47, 0x0d, 0x8e, 0x3a, 0x2d, 0xc7, 0x39, 0xbf, 0x56, 0x28, 0x97, 0xd9, 0x20, +                0x4f, 0x00, 0x51, 0x3b, +        }; + +        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *a = NULL, *rrsig = NULL, *dnskey = NULL; +        _cleanup_(dns_answer_unrefp) DnsAnswer *answer = NULL; +        _cleanup_free_ char *x = NULL, *y = NULL, *z = NULL; + +        a = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_A, "nAsA.gov"); +        assert_se(a); + +        a->a.in_addr.s_addr = inet_addr("52.0.14.116"); + +        assert_se(dns_resource_record_to_string(a, &x) >= 0); +        log_info("A: %s", x); + +        rrsig = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_RRSIG, "NaSa.GOV."); +        assert_se(rrsig); + +        rrsig->rrsig.type_covered = DNS_TYPE_A; +        rrsig->rrsig.algorithm = DNSSEC_ALGORITHM_RSASHA256; +        rrsig->rrsig.labels = 2; +        rrsig->rrsig.original_ttl = 600; +        rrsig->rrsig.expiration = 0x5683135c; +        rrsig->rrsig.inception = 0x565b7da8; +        rrsig->rrsig.key_tag = 63876; +        rrsig->rrsig.signer = strdup("Nasa.Gov."); +        assert_se(rrsig->rrsig.signer); +        rrsig->rrsig.signature_size = sizeof(signature_blob); +        rrsig->rrsig.signature = memdup(signature_blob, rrsig->rrsig.signature_size); +        assert_se(rrsig->rrsig.signature); + +        assert_se(dns_resource_record_to_string(rrsig, &y) >= 0); +        log_info("RRSIG: %s", y); + +        dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nASA.gOV"); +        assert_se(dnskey); + +        dnskey->dnskey.flags = 256; +        dnskey->dnskey.protocol = 3; +        dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; +        dnskey->dnskey.key_size = sizeof(dnskey_blob); +        dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob)); +        assert_se(dnskey->dnskey.key); + +        assert_se(dns_resource_record_to_string(dnskey, &z) >= 0); +        log_info("DNSKEY: %s", z); +        log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey)); + +        assert_se(dnssec_key_match_rrsig(a->key, rrsig) > 0); +        assert_se(dnssec_rrsig_match_dnskey(rrsig, dnskey) > 0); + +        answer = dns_answer_new(1); +        assert_se(answer); +        assert_se(dns_answer_add(answer, a, 0) >= 0); + +        /* Validate the RR as it if was 2015-12-2 today */ +        assert_se(dnssec_verify_rrset(answer, a->key, rrsig, dnskey, 1449092754*USEC_PER_SEC) == DNSSEC_VERIFIED); +} + +static void test_dnssec_verify_dns_key(void) { + +        static const uint8_t ds1_fprint[] = { +                0x46, 0x8B, 0xC8, 0xDD, 0xC7, 0xE8, 0x27, 0x03, 0x40, 0xBB, 0x8A, 0x1F, 0x3B, 0x2E, 0x45, 0x9D, +                0x80, 0x67, 0x14, 0x01, +        }; +        static const uint8_t ds2_fprint[] = { +                0x8A, 0xEE, 0x80, 0x47, 0x05, 0x5F, 0x83, 0xD1, 0x48, 0xBA, 0x8F, 0xF6, 0xDD, 0xA7, 0x60, 0xCE, +                0x94, 0xF7, 0xC7, 0x5E, 0x52, 0x4C, 0xF2, 0xE9, 0x50, 0xB9, 0x2E, 0xCB, 0xEF, 0x96, 0xB9, 0x98, +        }; +        static const uint8_t dnskey_blob[] = { +                0x03, 0x01, 0x00, 0x01, 0xa8, 0x12, 0xda, 0x4f, 0xd2, 0x7d, 0x54, 0x14, 0x0e, 0xcc, 0x5b, 0x5e, +                0x45, 0x9c, 0x96, 0x98, 0xc0, 0xc0, 0x85, 0x81, 0xb1, 0x47, 0x8c, 0x7d, 0xe8, 0x39, 0x50, 0xcc, +                0xc5, 0xd0, 0xf2, 0x00, 0x81, 0x67, 0x79, 0xf6, 0xcc, 0x9d, 0xad, 0x6c, 0xbb, 0x7b, 0x6f, 0x48, +                0x97, 0x15, 0x1c, 0xfd, 0x0b, 0xfe, 0xd3, 0xd7, 0x7d, 0x9f, 0x81, 0x26, 0xd3, 0xc5, 0x65, 0x49, +                0xcf, 0x46, 0x62, 0xb0, 0x55, 0x6e, 0x47, 0xc7, 0x30, 0xef, 0x51, 0xfb, 0x3e, 0xc6, 0xef, 0xde, +                0x27, 0x3f, 0xfa, 0x57, 0x2d, 0xa7, 0x1d, 0x80, 0x46, 0x9a, 0x5f, 0x14, 0xb3, 0xb0, 0x2c, 0xbe, +                0x72, 0xca, 0xdf, 0xb2, 0xff, 0x36, 0x5b, 0x4f, 0xec, 0x58, 0x8e, 0x8d, 0x01, 0xe9, 0xa9, 0xdf, +                0xb5, 0x60, 0xad, 0x52, 0x4d, 0xfc, 0xa9, 0x3e, 0x8d, 0x35, 0x95, 0xb3, 0x4e, 0x0f, 0xca, 0x45, +                0x1b, 0xf7, 0xef, 0x3a, 0x88, 0x25, 0x08, 0xc7, 0x4e, 0x06, 0xc1, 0x62, 0x1a, 0xce, 0xd8, 0x77, +                0xbd, 0x02, 0x65, 0xf8, 0x49, 0xfb, 0xce, 0xf6, 0xa8, 0x09, 0xfc, 0xde, 0xb2, 0x09, 0x9d, 0x39, +                0xf8, 0x63, 0x9c, 0x32, 0x42, 0x7c, 0xa0, 0x30, 0x86, 0x72, 0x7a, 0x4a, 0xc6, 0xd4, 0xb3, 0x2d, +                0x24, 0xef, 0x96, 0x3f, 0xc2, 0xda, 0xd3, 0xf2, 0x15, 0x6f, 0xda, 0x65, 0x4b, 0x81, 0x28, 0x68, +                0xf4, 0xfe, 0x3e, 0x71, 0x4f, 0x50, 0x96, 0x72, 0x58, 0xa1, 0x89, 0xdd, 0x01, 0x61, 0x39, 0x39, +                0xc6, 0x76, 0xa4, 0xda, 0x02, 0x70, 0x3d, 0xc0, 0xdc, 0x8d, 0x70, 0x72, 0x04, 0x90, 0x79, 0xd4, +                0xec, 0x65, 0xcf, 0x49, 0x35, 0x25, 0x3a, 0x14, 0x1a, 0x45, 0x20, 0xeb, 0x31, 0xaf, 0x92, 0xba, +                0x20, 0xd3, 0xcd, 0xa7, 0x13, 0x44, 0xdc, 0xcf, 0xf0, 0x27, 0x34, 0xb9, 0xe7, 0x24, 0x6f, 0x73, +                0xe7, 0xea, 0x77, 0x03, +        }; + +        _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *dnskey = NULL, *ds1 = NULL, *ds2 = NULL; +        _cleanup_free_ char *a = NULL, *b = NULL, *c = NULL; + +        /* The two DS RRs in effect for nasa.gov on 2015-12-01. */ +        ds1 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "nasa.gov"); +        assert_se(ds1); + +        ds1->ds.key_tag = 47857; +        ds1->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; +        ds1->ds.digest_type = DNSSEC_DIGEST_SHA1; +        ds1->ds.digest_size = sizeof(ds1_fprint); +        ds1->ds.digest = memdup(ds1_fprint, ds1->ds.digest_size); +        assert_se(ds1->ds.digest); + +        assert_se(dns_resource_record_to_string(ds1, &a) >= 0); +        log_info("DS1: %s", a); + +        ds2 = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DS, "NASA.GOV"); +        assert_se(ds2); + +        ds2->ds.key_tag = 47857; +        ds2->ds.algorithm = DNSSEC_ALGORITHM_RSASHA256; +        ds2->ds.digest_type = DNSSEC_DIGEST_SHA256; +        ds2->ds.digest_size = sizeof(ds2_fprint); +        ds2->ds.digest = memdup(ds2_fprint, ds2->ds.digest_size); +        assert_se(ds2->ds.digest); + +        assert_se(dns_resource_record_to_string(ds2, &b) >= 0); +        log_info("DS2: %s", b); + +        dnskey = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNSKEY, "nasa.GOV"); +        assert_se(dnskey); + +        dnskey->dnskey.flags = 257; +        dnskey->dnskey.protocol = 3; +        dnskey->dnskey.algorithm = DNSSEC_ALGORITHM_RSASHA256; +        dnskey->dnskey.key_size = sizeof(dnskey_blob); +        dnskey->dnskey.key = memdup(dnskey_blob, sizeof(dnskey_blob)); +        assert_se(dnskey->dnskey.key); + +        assert_se(dns_resource_record_to_string(dnskey, &c) >= 0); +        log_info("DNSKEY: %s", c); +        log_info("DNSKEY keytag: %u", dnssec_keytag(dnskey)); + +        assert_se(dnssec_verify_dnskey(dnskey, ds1) > 0); +        assert_se(dnssec_verify_dnskey(dnskey, ds2) > 0); +} + +static void test_dnssec_canonicalize_one(const char *original, const char *canonical, int r) { +        char canonicalized[DNSSEC_CANONICAL_HOSTNAME_MAX]; + +        assert_se(dnssec_canonicalize(original, canonicalized, sizeof(canonicalized)) == r); +        if (r < 0) +                return; + +        assert_se(streq(canonicalized, canonical)); +} + +static void test_dnssec_canonicalize(void) { +        test_dnssec_canonicalize_one("", ".", 1); +        test_dnssec_canonicalize_one(".", ".", 1); +        test_dnssec_canonicalize_one("foo", "foo.", 4); +        test_dnssec_canonicalize_one("foo.", "foo.", 4); +        test_dnssec_canonicalize_one("FOO.", "foo.", 4); +        test_dnssec_canonicalize_one("FOO.bar.", "foo.bar.", 8); +        test_dnssec_canonicalize_one("FOO..bar.", NULL, -EINVAL); +} + +int main(int argc, char*argv[]) { + +        test_dnssec_canonicalize(); +        test_dnssec_verify_dns_key(); +        test_dnssec_verify_rrset(); + +        return 0; +} diff --git a/src/shared/acl-util.c b/src/shared/acl-util.c index 35f2e1b67d..b4028564c2 100644 --- a/src/shared/acl-util.c +++ b/src/shared/acl-util.c @@ -71,6 +71,7 @@ int acl_find_uid(acl_t acl, uid_t uid, acl_entry_t *entry) {  int calc_acl_mask_if_needed(acl_t *acl_p) {          acl_entry_t i;          int r; +        bool need = false;          assert(acl_p); @@ -85,17 +86,16 @@ int calc_acl_mask_if_needed(acl_t *acl_p) {                  if (tag == ACL_MASK)                          return 0; -                if (IN_SET(tag, ACL_USER, ACL_GROUP)) { -                        if (acl_calc_mask(acl_p) < 0) -                                return -errno; - -                        return 1; -                } +                if (IN_SET(tag, ACL_USER, ACL_GROUP)) +                        need = true;          }          if (r < 0)                  return -errno; -        return 0; +        if (need && acl_calc_mask(acl_p) < 0) +                return -errno; + +        return need;  }  int add_base_acls_if_needed(acl_t *acl_p, const char *path) { @@ -398,3 +398,34 @@ int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl) {          old = NULL;          return 0;  } + +int add_acls_for_user(int fd, uid_t uid) { +        _cleanup_(acl_freep) acl_t acl = NULL; +        acl_entry_t entry; +        acl_permset_t permset; +        int r; + +        acl = acl_get_fd(fd); +        if (!acl) +                return -errno; + +        r = acl_find_uid(acl, uid, &entry); +        if (r <= 0) { +                if (acl_create_entry(&acl, &entry) < 0 || +                    acl_set_tag_type(entry, ACL_USER) < 0 || +                    acl_set_qualifier(entry, &uid) < 0) +                        return -errno; +        } + +        /* We do not recalculate the mask unconditionally here, +         * so that the fchmod() mask above stays intact. */ +        if (acl_get_permset(entry, &permset) < 0 || +            acl_add_perm(permset, ACL_READ) < 0) +                return -errno; + +        r = calc_acl_mask_if_needed(&acl); +        if (r < 0) +                return r; + +        return acl_set_fd(fd, acl); +} diff --git a/src/shared/acl-util.h b/src/shared/acl-util.h index 256a6a5900..1d7f45e2a8 100644 --- a/src/shared/acl-util.h +++ b/src/shared/acl-util.h @@ -35,6 +35,7 @@ int add_base_acls_if_needed(acl_t *acl_p, const char *path);  int acl_search_groups(const char* path, char ***ret_groups);  int parse_acl(const char *text, acl_t *acl_access, acl_t *acl_default, bool want_mask);  int acls_for_file(const char *path, acl_type_t type, acl_t new, acl_t *acl); +int add_acls_for_user(int fd, uid_t uid);  /* acl_free takes multiple argument types.   * Multiple cleanup functions are necessary. */ diff --git a/src/shared/acpi-fpdt.c b/src/shared/acpi-fpdt.c index 30e03c0652..dcdef50a18 100644 --- a/src/shared/acpi-fpdt.c +++ b/src/shared/acpi-fpdt.c @@ -19,9 +19,10 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <fcntl.h> +#include <stddef.h>  #include <stdint.h> -#include <stdio.h>  #include <string.h>  #include <unistd.h> @@ -30,7 +31,6 @@  #include "fd-util.h"  #include "fileio.h"  #include "time-util.h" -#include "util.h"  struct acpi_table_header {          char signature[4]; diff --git a/src/shared/apparmor-util.c b/src/shared/apparmor-util.c index f6ac43adfe..f8cbb333d5 100644 --- a/src/shared/apparmor-util.c +++ b/src/shared/apparmor-util.c @@ -19,11 +19,12 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stddef.h> +  #include "alloc-util.h"  #include "apparmor-util.h"  #include "fileio.h"  #include "parse-util.h" -#include "util.h"  bool mac_apparmor_use(void) {          static int cached_use = -1; diff --git a/src/shared/architecture.c b/src/shared/architecture.c index 73937bd5a7..ca6821b4d8 100644 --- a/src/shared/architecture.c +++ b/src/shared/architecture.c @@ -22,6 +22,7 @@  #include <sys/utsname.h>  #include "architecture.h" +#include "macro.h"  #include "string-table.h"  #include "string-util.h" diff --git a/src/shared/architecture.h b/src/shared/architecture.h index 61d067cad7..c6af4a5b33 100644 --- a/src/shared/architecture.h +++ b/src/shared/architecture.h @@ -23,6 +23,7 @@  #include <endian.h> +#include "macro.h"  #include "util.h"  /* A cleaned up architecture definition. We don't want to get lost in diff --git a/src/shared/ask-password-api.c b/src/shared/ask-password-api.c index fbe2b6fecb..bc12f89f02 100644 --- a/src/shared/ask-password-api.c +++ b/src/shared/ask-password-api.c @@ -21,13 +21,22 @@  #include <errno.h>  #include <fcntl.h> +#include <inttypes.h> +#include <limits.h>  #include <poll.h> +#include <signal.h>  #include <stdbool.h>  #include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h>  #include <string.h>  #include <sys/inotify.h>  #include <sys/signalfd.h>  #include <sys/socket.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/uio.h>  #include <sys/un.h>  #include <termios.h>  #include <unistd.h> @@ -38,6 +47,8 @@  #include "fileio.h"  #include "formats-util.h"  #include "io-util.h" +#include "log.h" +#include "macro.h"  #include "missing.h"  #include "mkdir.h"  #include "random-util.h" @@ -46,6 +57,7 @@  #include "string-util.h"  #include "strv.h"  #include "terminal-util.h" +#include "time-util.h"  #include "umask-util.h"  #include "util.h" diff --git a/src/shared/base-filesystem.c b/src/shared/base-filesystem.c index e605490c32..2a7a38dd14 100644 --- a/src/shared/base-filesystem.c +++ b/src/shared/base-filesystem.c @@ -20,8 +20,11 @@  ***/  #include <errno.h> +#include <fcntl.h> +#include <stdbool.h>  #include <stdlib.h>  #include <sys/stat.h> +#include <syslog.h>  #include <unistd.h>  #include "alloc-util.h" diff --git a/src/shared/boot-timestamps.c b/src/shared/boot-timestamps.c index 879aca9374..63daf932f0 100644 --- a/src/shared/boot-timestamps.c +++ b/src/shared/boot-timestamps.c @@ -23,6 +23,8 @@  #include "acpi-fpdt.h"  #include "boot-timestamps.h"  #include "efivars.h" +#include "macro.h" +#include "time-util.h"  int boot_timestamps(const dual_timestamp *n, dual_timestamp *firmware, dual_timestamp *loader) {          usec_t x = 0, y = 0, a; diff --git a/src/shared/bus-util.c b/src/shared/bus-util.c index de4c4367ca..5c6dc34700 100644 --- a/src/shared/bus-util.c +++ b/src/shared/bus-util.c @@ -19,14 +19,24 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/resource.h>  #include <sys/socket.h> +#include <unistd.h> +#include "sd-bus-protocol.h"  #include "sd-bus.h"  #include "sd-daemon.h"  #include "sd-event.h" +#include "sd-id128.h"  #include "alloc-util.h" -#include "bus-error.h"  #include "bus-internal.h"  #include "bus-label.h"  #include "bus-message.h" @@ -35,7 +45,12 @@  #include "def.h"  #include "env-util.h"  #include "escape.h" +#include "extract-word.h"  #include "fd-util.h" +#include "hashmap.h" +#include "install.h" +#include "kdbus.h" +#include "log.h"  #include "macro.h"  #include "missing.h"  #include "parse-util.h" @@ -49,6 +64,7 @@  #include "string-util.h"  #include "strv.h"  #include "syslog-util.h" +#include "time-util.h"  #include "unit-name.h"  #include "user-util.h"  #include "utf8.h" diff --git a/src/shared/bus-util.h b/src/shared/bus-util.h index ec731d375e..a5e3b6a0b5 100644 --- a/src/shared/bus-util.h +++ b/src/shared/bus-util.h @@ -21,11 +21,18 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <sys/types.h> + +#include "sd-bus-vtable.h"  #include "sd-bus.h"  #include "sd-event.h"  #include "hashmap.h"  #include "install.h" +#include "macro.h"  #include "string-util.h"  #include "time-util.h" diff --git a/src/shared/cgroup-show.c b/src/shared/cgroup-show.c index 129ffc7056..d256b5a7cc 100644 --- a/src/shared/cgroup-show.c +++ b/src/shared/cgroup-show.c @@ -21,7 +21,9 @@  #include <dirent.h>  #include <errno.h> +#include <stddef.h>  #include <stdio.h> +#include <stdlib.h>  #include <string.h>  #include "alloc-util.h" @@ -31,11 +33,11 @@  #include "formats-util.h"  #include "locale-util.h"  #include "macro.h" +#include "output-mode.h"  #include "path-util.h"  #include "process-util.h"  #include "string-util.h"  #include "terminal-util.h" -#include "util.h"  static int compare(const void *a, const void *b) {          const pid_t *p = a, *q = b; diff --git a/src/shared/cgroup-show.h b/src/shared/cgroup-show.h index 5842bdd15e..24b758658d 100644 --- a/src/shared/cgroup-show.h +++ b/src/shared/cgroup-show.h @@ -25,6 +25,7 @@  #include <sys/types.h>  #include "logs-show.h" +#include "output-mode.h"  int show_cgroup_by_path(const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags);  int show_cgroup(const char *controller, const char *path, const char *prefix, unsigned columns, bool kernel_threads, OutputFlags flags); diff --git a/src/shared/clean-ipc.c b/src/shared/clean-ipc.c index 71cc613704..2c494d3a31 100644 --- a/src/shared/clean-ipc.c +++ b/src/shared/clean-ipc.c @@ -20,22 +20,29 @@  ***/  #include <dirent.h> +#include <errno.h>  #include <fcntl.h> +#include <limits.h>  #include <mqueue.h> +#include <stdbool.h> +#include <stdio.h> +#include <string.h>  #include <sys/ipc.h>  #include <sys/msg.h>  #include <sys/sem.h>  #include <sys/shm.h>  #include <sys/stat.h> +#include <unistd.h>  #include "clean-ipc.h"  #include "dirent-util.h"  #include "fd-util.h"  #include "fileio.h"  #include "formats-util.h" +#include "log.h" +#include "macro.h"  #include "string-util.h"  #include "strv.h" -#include "util.h"  static int clean_sysvipc_shm(uid_t delete_uid) {          _cleanup_fclose_ FILE *f = NULL; diff --git a/src/shared/condition.c b/src/shared/condition.c index a69719116c..dedaf2291f 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -20,9 +20,13 @@  ***/  #include <errno.h> +#include <fcntl.h>  #include <fnmatch.h> +#include <limits.h>  #include <stdlib.h>  #include <string.h> +#include <sys/stat.h> +#include <time.h>  #include <unistd.h>  #include "sd-id128.h" @@ -38,6 +42,8 @@  #include "glob-util.h"  #include "hostname-util.h"  #include "ima-util.h" +#include "list.h" +#include "macro.h"  #include "mount-util.h"  #include "parse-util.h"  #include "path-util.h" @@ -231,7 +237,7 @@ static int condition_test_security(Condition *c) {          assert(c->type == CONDITION_SECURITY);          if (streq(c->parameter, "selinux")) -                return mac_selinux_use(); +                return mac_selinux_have();          if (streq(c->parameter, "smack"))                  return mac_smack_use();          if (streq(c->parameter, "apparmor")) diff --git a/src/shared/conf-parser.c b/src/shared/conf-parser.c index 486122b0fd..2aae49fbce 100644 --- a/src/shared/conf-parser.c +++ b/src/shared/conf-parser.c @@ -20,15 +20,17 @@  ***/  #include <errno.h> +#include <limits.h> +#include <stdint.h>  #include <stdio.h>  #include <stdlib.h>  #include <string.h> - -#include "sd-messages.h" +#include <sys/types.h>  #include "alloc-util.h"  #include "conf-files.h"  #include "conf-parser.h" +#include "extract-word.h"  #include "fd-util.h"  #include "fs-util.h"  #include "log.h" @@ -40,8 +42,8 @@  #include "string-util.h"  #include "strv.h"  #include "syslog-util.h" +#include "time-util.h"  #include "utf8.h" -#include "util.h"  int config_item_table_lookup(                  const void *table, diff --git a/src/shared/conf-parser.h b/src/shared/conf-parser.h index 2872b22d9d..027ed209d9 100644 --- a/src/shared/conf-parser.h +++ b/src/shared/conf-parser.h @@ -21,9 +21,14 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <stdbool.h> +#include <stddef.h>  #include <stdio.h> +#include <syslog.h> +#include "alloc-util.h" +#include "log.h"  #include "macro.h"  /* An abstract parser for simple, line based, shallow configuration diff --git a/src/shared/dev-setup.c b/src/shared/dev-setup.c index ad3c17d5bd..ff583faa6e 100644 --- a/src/shared/dev-setup.c +++ b/src/shared/dev-setup.c @@ -26,6 +26,7 @@  #include "alloc-util.h"  #include "dev-setup.h"  #include "label.h" +#include "log.h"  #include "path-util.h"  #include "user-util.h"  #include "util.h" diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 4cf6355b71..0466857042 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -24,9 +24,18 @@  #include <stringprep.h>  #endif +#include <endian.h> +#include <netinet/in.h> +#include <stdio.h> +#include <string.h> +#include <sys/socket.h> +  #include "alloc-util.h"  #include "dns-domain.h" +#include "hashmap.h"  #include "hexdecoct.h" +#include "in-addr-util.h" +#include "macro.h"  #include "parse-util.h"  #include "string-util.h"  #include "strv.h" @@ -53,12 +62,12 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {                  if (*n == 0)                          break; -                if (sz <= 0) -                        return -ENOSPC; -                  if (r >= DNS_LABEL_MAX)                          return -EINVAL; +                if (sz <= 0) +                        return -ENOBUFS; +                  if (*n == '\\') {                          /* Escaped character */ @@ -185,10 +194,14 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha  int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {          char *q; -        if (l > DNS_LABEL_MAX) +        /* DNS labels must be between 1 and 63 characters long. A +         * zero-length label does not exist. See RFC 2182, Section +         * 11. */ + +        if (l <= 0 || l > DNS_LABEL_MAX)                  return -EINVAL;          if (sz < 1) -                return -ENOSPC; +                return -ENOBUFS;          assert(p);          assert(dest); @@ -198,10 +211,11 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {                  if (*p == '.' || *p == '\\') { +                        /* Dot or backslash */ +                          if (sz < 3) -                                return -ENOSPC; +                                return -ENOBUFS; -                        /* Dot or backslash */                          *(q++) = '\\';                          *(q++) = *p; @@ -216,7 +230,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {                          /* Proper character */                          if (sz < 2) -                                return -ENOSPC; +                                return -ENOBUFS;                          *(q++) = *p;                          sz -= 1; @@ -226,7 +240,7 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {                          /* Everything else */                          if (sz < 5) -                                return -ENOSPC; +                                return -ENOBUFS;                          *(q++) = '\\';                          *(q++) = '0' + (char) ((uint8_t) *p / 100); @@ -253,7 +267,7 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {          assert(p);          assert(ret); -        if (l > DNS_LABEL_MAX) +        if (l <= 0 || l > DNS_LABEL_MAX)                  return -EINVAL;          s = new(char, DNS_LABEL_ESCAPED_MAX); @@ -273,32 +287,52 @@ int dns_label_escape_new(const char *p, size_t l, char **ret) {  int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {  #ifdef HAVE_LIBIDN          _cleanup_free_ uint32_t *input = NULL; -        size_t input_size; +        size_t input_size, l;          const char *p;          bool contains_8bit = false; +        char buffer[DNS_LABEL_MAX+1];          assert(encoded);          assert(decoded); -        assert(decoded_max >= DNS_LABEL_MAX); + +        /* Converts an U-label into an A-label */          if (encoded_size <= 0) -                return 0; +                return -EINVAL;          for (p = encoded; p < encoded + encoded_size; p++)                  if ((uint8_t) *p > 127)                          contains_8bit = true; -        if (!contains_8bit) +        if (!contains_8bit) { +                if (encoded_size > DNS_LABEL_MAX) +                        return -EINVAL; +                  return 0; +        }          input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);          if (!input)                  return -ENOMEM; -        if (idna_to_ascii_4i(input, input_size, decoded, 0) != 0) +        if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0)                  return -EINVAL; -        return strlen(decoded); +        l = strlen(buffer); + +        /* Verify that the the result is not longer than one DNS label. */ +        if (l <= 0 || l > DNS_LABEL_MAX) +                return -EINVAL; +        if (l > decoded_max) +                return -ENOBUFS; + +        memcpy(decoded, buffer, l); + +        /* If there's room, append a trailing NUL byte, but only then */ +        if (decoded_max > l) +                decoded[l] = 0; + +        return (int) l;  #else          return 0;  #endif @@ -312,11 +346,14 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,          uint32_t *output = NULL;          size_t w; -        /* To be invoked after unescaping */ +        /* To be invoked after unescaping. Converts an A-label into an U-label. */          assert(encoded);          assert(decoded); +        if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX) +                return -EINVAL; +          if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1)                  return 0; @@ -336,11 +373,16 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,          if (!result)                  return -ENOMEM;          if (w <= 0) -                return 0; -        if (w+1 > decoded_max)                  return -EINVAL; +        if (w > decoded_max) +                return -ENOBUFS; + +        memcpy(decoded, result, w); + +        /* Append trailing NUL byte if there's space, but only then. */ +        if (decoded_max > w) +                decoded[w] = 0; -        memcpy(decoded, result, w+1);          return w;  #else          return 0; @@ -357,7 +399,6 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {          assert(a);          for (;;) { -                _cleanup_free_ char *t = NULL;                  char label[DNS_LABEL_MAX];                  int k; @@ -410,6 +451,9 @@ int dns_name_concat(const char *a, const char *b, char **_ret) {                  n += r;          } +        if (n > DNS_HOSTNAME_MAX) +                return -EINVAL; +          if (_ret) {                  if (!GREEDY_REALLOC(ret, allocated, n + 1))                          return -ENOMEM; @@ -512,24 +556,32 @@ int dns_name_equal(const char *x, const char *y) {                  r = dns_label_unescape(&x, la, sizeof(la));                  if (r < 0)                          return r; - -                k = dns_label_undo_idna(la, r, la, sizeof(la)); -                if (k < 0) -                        return k; -                if (k > 0) -                        r = k; +                if (r > 0) { +                        k = dns_label_undo_idna(la, r, la, sizeof(la)); +                        if (k < 0) +                                return k; +                        if (k > 0) +                                r = k; +                }                  q = dns_label_unescape(&y, lb, sizeof(lb));                  if (q < 0)                          return q; -                w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); -                if (w < 0) -                        return w; -                if (w > 0) -                        q = w; +                if (q > 0) { +                        w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); +                        if (w < 0) +                                return w; +                        if (w > 0) +                                q = w; +                } + +                /* If one name had fewer labels than the other, this +                 * will show up as empty label here, which the +                 * strcasecmp() below will properly consider different +                 * from a non-empty label. */                  la[r] = lb[q] = 0; -                if (strcasecmp(la, lb)) +                if (strcasecmp(la, lb) != 0)                          return false;          }  } @@ -550,11 +602,13 @@ int dns_name_endswith(const char *name, const char *suffix) {                  r = dns_label_unescape(&n, ln, sizeof(ln));                  if (r < 0)                          return r; -                k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); -                if (k < 0) -                        return k; -                if (k > 0) -                        r = k; +                if (r > 0) { +                        k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); +                        if (k < 0) +                                return k; +                        if (k > 0) +                                r = k; +                }                  if (!saved_n)                          saved_n = n; @@ -562,11 +616,13 @@ int dns_name_endswith(const char *name, const char *suffix) {                  q = dns_label_unescape(&s, ls, sizeof(ls));                  if (q < 0)                          return q; -                w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); -                if (w < 0) -                        return w; -                if (w > 0) -                        q = w; +                if (q > 0) { +                        w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); +                        if (w < 0) +                                return w; +                        if (w > 0) +                                q = w; +                }                  if (r == 0 && q == 0)                          return true; @@ -606,11 +662,13 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char                  r = dns_label_unescape(&n, ln, sizeof(ln));                  if (r < 0)                          return r; -                k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); -                if (k < 0) -                        return k; -                if (k > 0) -                        r = k; +                if (r > 0) { +                        k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); +                        if (k < 0) +                                return k; +                        if (k > 0) +                                r = k; +                }                  if (!saved_after)                          saved_after = n; @@ -618,11 +676,13 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char                  q = dns_label_unescape(&s, ls, sizeof(ls));                  if (q < 0)                          return q; -                w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); -                if (w < 0) -                        return w; -                if (w > 0) -                        q = w; +                if (q > 0) { +                        w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); +                        if (w < 0) +                                return w; +                        if (w > 0) +                                q = w; +                }                  if (r == 0 && q == 0)                          break; @@ -813,37 +873,60 @@ bool dns_name_is_single_label(const char *name) {          return dns_name_is_root(name);  } -/* Encode a domain name according to RFC 1035 Section 3.1 */ -int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len) { -        uint8_t *label_length; -        uint8_t *out; +/* Encode a domain name according to RFC 1035 Section 3.1, without compression */ +int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical) { +        uint8_t *label_length, *out;          int r; -        assert_return(buffer, -EINVAL); -        assert_return(domain, -EINVAL); -        assert_return(domain[0], -EINVAL); +        assert(domain); +        assert(buffer);          out = buffer;          do { -                /* reserve a byte for label length */ -                if (len == 0) +                /* Reserve a byte for label length */ +                if (len <= 0)                          return -ENOBUFS;                  len--;                  label_length = out;                  out++; -                /* convert and copy a single label */ +                /* Convert and copy a single label. Note that +                 * dns_label_unescape() returns 0 when it hits the end +                 * of the domain name, which we rely on here to encode +                 * the trailing NUL byte. */                  r = dns_label_unescape(&domain, (char *) out, len);                  if (r < 0)                          return r; -                /* fill label length, move forward */ +                if (canonical) { +                        size_t i; + +                        /* Optionally, output the name in DNSSEC +                         * canonical format, as described in RFC 4034, +                         * section 6.2. Or in other words: in +                         * lower-case. */ + +                        for (i = 0; i < (size_t) r; i++) { +                                if (out[i] >= 'A' && out[i] <= 'Z') +                                        out[i] = out[i] - 'A' + 'a'; +                        } +                } + +                /* Fill label length, move forward */                  *label_length = r;                  out += r;                  len -= r; +          } while (r != 0); +        /* Verify the maximum size of the encoded name. The trailing +         * dot + NUL byte account are included this time, hence +         * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this +         * time. */ +        if (out - buffer > DNS_HOSTNAME_MAX + 2) +                return -EINVAL; +          return out - buffer;  } diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 99c72574db..3f8f621802 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -22,12 +22,26 @@  #pragma once +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +  #include "hashmap.h"  #include "in-addr-util.h" +/* Length of a single label, with all escaping removed, excluding any trailing dot or NUL byte */  #define DNS_LABEL_MAX 63 + +/* Worst case length of a single label, with all escaping applied and room for a trailing NUL byte. */  #define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1) +/* Maximum length of a full hostname, consisting of a series of unescaped labels, and no trailing dot or NUL byte */ +#define DNS_HOSTNAME_MAX 253 + +/* Maximum length of a full hostname, on the wire, including the final NUL byte */ +#define DNS_WIRE_FOMAT_HOSTNAME_MAX 255 +  int dns_label_unescape(const char **name, char *dest, size_t sz);  int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);  int dns_label_escape(const char *p, size_t l, char *dest, size_t sz); @@ -71,7 +85,7 @@ int dns_name_address(const char *p, int *family, union in_addr_union *a);  bool dns_name_is_root(const char *name);  bool dns_name_is_single_label(const char *name); -int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len); +int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical);  bool dns_srv_type_is_valid(const char *name);  bool dns_service_name_is_valid(const char *name); diff --git a/src/shared/dropin.c b/src/shared/dropin.c index 0d44401cc2..692e8b8338 100644 --- a/src/shared/dropin.c +++ b/src/shared/dropin.c @@ -19,17 +19,27 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <dirent.h> +#include <errno.h> +#include <stdarg.h> +#include <stdio.h> +#include <stdlib.h> +  #include "alloc-util.h"  #include "conf-files.h"  #include "dropin.h"  #include "escape.h"  #include "fd-util.h"  #include "fileio-label.h" +#include "hashmap.h" +#include "log.h" +#include "macro.h"  #include "mkdir.h"  #include "path-util.h" +#include "set.h"  #include "string-util.h"  #include "strv.h" -#include "util.h" +#include "unit-name.h"  int drop_in_file(const char *dir, const char *unit, unsigned level,                   const char *name, char **_p, char **_q) { diff --git a/src/shared/dropin.h b/src/shared/dropin.h index d4531fca2d..a8d647e990 100644 --- a/src/shared/dropin.h +++ b/src/shared/dropin.h @@ -21,6 +21,7 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include "hashmap.h"  #include "macro.h"  #include "set.h"  #include "unit-name.h" diff --git a/src/shared/efivars.c b/src/shared/efivars.c index 89deeb9b55..13af68d539 100644 --- a/src/shared/efivars.c +++ b/src/shared/efivars.c @@ -19,17 +19,27 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <dirent.h> +#include <errno.h>  #include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h>  #include <string.h> +#include <sys/stat.h>  #include <unistd.h> +#include "sd-id128.h" +  #include "alloc-util.h"  #include "dirent-util.h"  #include "efivars.h"  #include "fd-util.h"  #include "io-util.h" +#include "macro.h"  #include "parse-util.h"  #include "stdio-util.h" +#include "time-util.h"  #include "utf8.h"  #include "util.h"  #include "virt.h" diff --git a/src/shared/efivars.h b/src/shared/efivars.h index 5cb4c3af4e..94af9717b0 100644 --- a/src/shared/efivars.h +++ b/src/shared/efivars.h @@ -22,6 +22,8 @@  ***/  #include <stdbool.h> +#include <stddef.h> +#include <stdint.h>  #include "sd-id128.h" diff --git a/src/shared/firewall-util.c b/src/shared/firewall-util.c index 5acfb0191b..9606122345 100644 --- a/src/shared/firewall-util.c +++ b/src/shared/firewall-util.c @@ -19,9 +19,14 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <alloca.h>  #include <arpa/inet.h> +#include <endian.h> +#include <errno.h>  #include <net/if.h> -#include <sys/types.h> +#include <stddef.h> +#include <string.h> +#include <sys/socket.h>  #include <linux/netfilter_ipv4/ip_tables.h>  #include <linux/netfilter/nf_nat.h>  #include <linux/netfilter/xt_addrtype.h> @@ -29,7 +34,8 @@  #include "alloc-util.h"  #include "firewall-util.h" -#include "util.h" +#include "in-addr-util.h" +#include "macro.h"  DEFINE_TRIVIAL_CLEANUP_FUNC(struct xtc_handle*, iptc_free); diff --git a/src/shared/firewall-util.h b/src/shared/firewall-util.h index 93152e3978..463e09bcaf 100644 --- a/src/shared/firewall-util.h +++ b/src/shared/firewall-util.h @@ -21,6 +21,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> +#include <stdint.h> +  #include "in-addr-util.h"  #ifdef HAVE_LIBIPTC diff --git a/src/shared/fstab-util.c b/src/shared/fstab-util.c index eb2845cddf..d013901973 100644 --- a/src/shared/fstab-util.c +++ b/src/shared/fstab-util.c @@ -19,9 +19,16 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <mntent.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +  #include "alloc-util.h"  #include "device-nodes.h"  #include "fstab-util.h" +#include "macro.h"  #include "mount-util.h"  #include "parse-util.h"  #include "path-util.h" diff --git a/src/shared/generator.c b/src/shared/generator.c index 9998c64416..37de3f7cb1 100644 --- a/src/shared/generator.c +++ b/src/shared/generator.c @@ -19,6 +19,7 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <unistd.h>  #include "alloc-util.h" @@ -28,11 +29,13 @@  #include "fileio.h"  #include "fstab-util.h"  #include "generator.h" +#include "log.h" +#include "macro.h"  #include "mkdir.h" -#include "mount-util.h"  #include "path-util.h"  #include "special.h"  #include "string-util.h" +#include "time-util.h"  #include "unit-name.h"  #include "util.h" diff --git a/src/shared/import-util.c b/src/shared/import-util.c index ddc8c00a2d..29ce732b56 100644 --- a/src/shared/import-util.c +++ b/src/shared/import-util.c @@ -19,9 +19,14 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <string.h> +  #include "alloc-util.h"  #include "btrfs-util.h"  #include "import-util.h" +#include "log.h" +#include "macro.h"  #include "path-util.h"  #include "string-table.h"  #include "string-util.h" diff --git a/src/shared/install-printf.c b/src/shared/install-printf.c index 74b909d34d..645b3ce33c 100644 --- a/src/shared/install-printf.c +++ b/src/shared/install-printf.c @@ -19,15 +19,18 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -#include <stdlib.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> -#include "alloc-util.h"  #include "formats-util.h"  #include "install-printf.h" +#include "install.h" +#include "macro.h"  #include "specifier.h"  #include "unit-name.h"  #include "user-util.h" -#include "util.h"  static int specifier_prefix_and_instance(char specifier, void *data, void *userdata, char **ret) {          UnitFileInstallInfo *i = userdata; diff --git a/src/shared/install.c b/src/shared/install.c index 17e03e59cd..b37f8922df 100644 --- a/src/shared/install.c +++ b/src/shared/install.c @@ -19,22 +19,31 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <dirent.h>  #include <errno.h>  #include <fcntl.h>  #include <fnmatch.h> +#include <limits.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h>  #include <string.h> +#include <sys/stat.h>  #include <unistd.h>  #include "alloc-util.h"  #include "conf-files.h"  #include "conf-parser.h"  #include "dirent-util.h" +#include "extract-word.h"  #include "fd-util.h"  #include "fileio.h"  #include "fs-util.h"  #include "hashmap.h"  #include "install-printf.h"  #include "install.h" +#include "log.h" +#include "macro.h"  #include "mkdir.h"  #include "path-lookup.h"  #include "path-util.h" @@ -45,7 +54,6 @@  #include "string-util.h"  #include "strv.h"  #include "unit-name.h" -#include "util.h"  #define UNIT_FILE_FOLLOW_SYMLINK_MAX 64 diff --git a/src/shared/install.h b/src/shared/install.h index 45a417df92..5519fbcf8f 100644 --- a/src/shared/install.h +++ b/src/shared/install.h @@ -30,7 +30,10 @@ typedef struct UnitFileChange UnitFileChange;  typedef struct UnitFileList UnitFileList;  typedef struct UnitFileInstallInfo UnitFileInstallInfo; +#include <stdbool.h> +  #include "hashmap.h" +#include "macro.h"  #include "path-lookup.h"  #include "strv.h"  #include "unit-name.h" diff --git a/src/shared/logs-show.c b/src/shared/logs-show.c index 0d7892ac1e..193dad1943 100644 --- a/src/shared/logs-show.c +++ b/src/shared/logs-show.c @@ -21,9 +21,17 @@  #include <errno.h>  #include <fcntl.h> +#include <signal.h> +#include <stdint.h> +#include <stdlib.h>  #include <string.h>  #include <sys/socket.h> +#include <syslog.h>  #include <time.h> +#include <unistd.h> + +#include "sd-id128.h" +#include "sd-journal.h"  #include "alloc-util.h"  #include "fd-util.h" @@ -34,11 +42,15 @@  #include "journal-internal.h"  #include "log.h"  #include "logs-show.h" +#include "macro.h" +#include "output-mode.h"  #include "parse-util.h"  #include "process-util.h" +#include "sparse-endian.h"  #include "string-table.h"  #include "string-util.h"  #include "terminal-util.h" +#include "time-util.h"  #include "utf8.h"  #include "util.h" diff --git a/src/shared/logs-show.h b/src/shared/logs-show.h index 98927bbc59..396050936d 100644 --- a/src/shared/logs-show.h +++ b/src/shared/logs-show.h @@ -22,11 +22,15 @@  ***/  #include <stdbool.h> +#include <stddef.h> +#include <stdio.h>  #include <sys/types.h>  #include "sd-journal.h" +#include "macro.h"  #include "output-mode.h" +#include "time-util.h"  #include "util.h"  int output_journal( diff --git a/src/shared/machine-image.c b/src/shared/machine-image.c index 2c1da0a40d..2ded0ff698 100644 --- a/src/shared/machine-image.c +++ b/src/shared/machine-image.c @@ -19,10 +19,15 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <dirent.h> +#include <errno.h>  #include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/stat.h> +#include <unistd.h>  #include <linux/fs.h> -#include <sys/statfs.h> -  #include "alloc-util.h"  #include "btrfs-util.h"  #include "chattr-util.h" @@ -30,6 +35,10 @@  #include "dirent-util.h"  #include "fd-util.h"  #include "fs-util.h" +#include "hashmap.h" +#include "lockfile-util.h" +#include "log.h" +#include "macro.h"  #include "machine-image.h"  #include "mkdir.h"  #include "path-util.h" @@ -37,7 +46,9 @@  #include "string-table.h"  #include "string-util.h"  #include "strv.h" +#include "time-util.h"  #include "utf8.h" +#include "util.h"  #include "xattr-util.h"  static const char image_search_path[] = diff --git a/src/shared/machine-image.h b/src/shared/machine-image.h index 038db7453c..5e9d8f6980 100644 --- a/src/shared/machine-image.h +++ b/src/shared/machine-image.h @@ -21,8 +21,12 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> +#include <stdint.h> +  #include "hashmap.h"  #include "lockfile-util.h" +#include "macro.h"  #include "time-util.h"  typedef enum ImageType { diff --git a/src/shared/machine-pool.c b/src/shared/machine-pool.c index 4172a63fd0..23cbd8d600 100644 --- a/src/shared/machine-pool.c +++ b/src/shared/machine-pool.c @@ -19,10 +19,23 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <fcntl.h> +#include <linux/loop.h> +#include <signal.h> +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/ioctl.h>  #include <sys/mount.h>  #include <sys/prctl.h> +#include <sys/stat.h> +#include <sys/statfs.h>  #include <sys/statvfs.h> -#include <sys/vfs.h> +#include <unistd.h> + +#include "sd-bus-protocol.h" +#include "sd-bus.h"  #include "alloc-util.h"  #include "btrfs-util.h" @@ -30,7 +43,10 @@  #include "fileio.h"  #include "fs-util.h"  #include "lockfile-util.h" +#include "log.h"  #include "machine-pool.h" +#include "macro.h" +#include "missing.h"  #include "mkdir.h"  #include "mount-util.h"  #include "parse-util.h" @@ -39,7 +55,6 @@  #include "signal-util.h"  #include "stat-util.h"  #include "string-util.h" -#include "util.h"  #define VAR_LIB_MACHINES_SIZE_START (1024UL*1024UL*500UL)  #define VAR_LIB_MACHINES_FREE_MIN (1024UL*1024UL*750UL) diff --git a/src/shared/machine-pool.h b/src/shared/machine-pool.h index fe01d3d47c..a1f2c5c626 100644 --- a/src/shared/machine-pool.h +++ b/src/shared/machine-pool.h @@ -21,6 +21,8 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdint.h> +  #include "sd-bus.h"  /* Grow the /var/lib/machines directory after each 10MiB written */ diff --git a/src/shared/pager.c b/src/shared/pager.c index d149bc1722..07ce926d75 100644 --- a/src/shared/pager.c +++ b/src/shared/pager.c @@ -19,7 +19,11 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -#include <fcntl.h> +#include <errno.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h>  #include <stdlib.h>  #include <string.h>  #include <sys/prctl.h> @@ -28,13 +32,13 @@  #include "copy.h"  #include "fd-util.h"  #include "locale-util.h" +#include "log.h"  #include "macro.h"  #include "pager.h"  #include "process-util.h"  #include "signal-util.h"  #include "string-util.h"  #include "terminal-util.h" -#include "util.h"  static pid_t pager_pid = 0; diff --git a/src/shared/path-lookup.c b/src/shared/path-lookup.c index 4a82bd18cd..90114001ee 100644 --- a/src/shared/path-lookup.c +++ b/src/shared/path-lookup.c @@ -26,6 +26,8 @@  #include "alloc-util.h"  #include "install.h" +#include "log.h" +#include "macro.h"  #include "path-lookup.h"  #include "path-util.h"  #include "string-util.h" diff --git a/src/shared/path-lookup.h b/src/shared/path-lookup.h index e35c8d3c04..b8036718ba 100644 --- a/src/shared/path-lookup.h +++ b/src/shared/path-lookup.h @@ -21,6 +21,7 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h>  #include "macro.h"  typedef struct LookupPaths { diff --git a/src/shared/ptyfwd.c b/src/shared/ptyfwd.c index 2666b8f7e2..e6a7a488c9 100644 --- a/src/shared/ptyfwd.c +++ b/src/shared/ptyfwd.c @@ -19,15 +19,27 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <limits.h> +#include <signal.h> +#include <stddef.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h>  #include <sys/epoll.h>  #include <sys/ioctl.h> +#include <sys/time.h>  #include <termios.h> +#include <unistd.h> + +#include "sd-event.h"  #include "alloc-util.h"  #include "fd-util.h" +#include "log.h" +#include "macro.h"  #include "ptyfwd.h" -#include "util.h" +#include "time-util.h"  struct PTYForward {          sd_event *event; diff --git a/src/shared/ptyfwd.h b/src/shared/ptyfwd.h index 9b3214221b..002590d1cf 100644 --- a/src/shared/ptyfwd.h +++ b/src/shared/ptyfwd.h @@ -25,6 +25,8 @@  #include "sd-event.h" +#include "macro.h" +  typedef struct PTYForward PTYForward;  typedef enum PTYForwardFlags { diff --git a/src/shared/seccomp-util.c b/src/shared/seccomp-util.c index 09baf51661..bd1d44a0ab 100644 --- a/src/shared/seccomp-util.c +++ b/src/shared/seccomp-util.c @@ -19,11 +19,13 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h>  #include <seccomp.h> +#include <stddef.h> +#include "macro.h"  #include "seccomp-util.h"  #include "string-util.h" -#include "util.h"  const char* seccomp_arch_to_string(uint32_t c) { diff --git a/src/shared/seccomp-util.h b/src/shared/seccomp-util.h index 60d97154ec..79ee8c728d 100644 --- a/src/shared/seccomp-util.h +++ b/src/shared/seccomp-util.h @@ -22,6 +22,7 @@  ***/  #include <seccomp.h> +#include <stdint.h>  const char* seccomp_arch_to_string(uint32_t c);  int seccomp_arch_from_string(const char *n, uint32_t *ret); diff --git a/src/shared/sleep-config.c b/src/shared/sleep-config.c index 39b836d053..7ba11e2f0e 100644 --- a/src/shared/sleep-config.c +++ b/src/shared/sleep-config.c @@ -19,7 +19,13 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stdbool.h> +#include <stddef.h>  #include <stdio.h> +#include <string.h> +#include <syslog.h> +#include <unistd.h>  #include "alloc-util.h"  #include "conf-parser.h" @@ -27,11 +33,11 @@  #include "fd-util.h"  #include "fileio.h"  #include "log.h" +#include "macro.h"  #include "parse-util.h"  #include "sleep-config.h"  #include "string-util.h"  #include "strv.h" -#include "util.h"  #define USE(x, y) do{ (x) = (y); (y) = NULL; } while(0) diff --git a/src/shared/spawn-polkit-agent.c b/src/shared/spawn-polkit-agent.c index 8ea6cb830b..ada4bdb17e 100644 --- a/src/shared/spawn-polkit-agent.c +++ b/src/shared/spawn-polkit-agent.c @@ -28,9 +28,11 @@  #include "fd-util.h"  #include "io-util.h"  #include "log.h" +#include "macro.h"  #include "process-util.h"  #include "spawn-polkit-agent.h"  #include "stdio-util.h" +#include "time-util.h"  #include "util.h"  #ifdef ENABLE_POLKIT diff --git a/src/shared/specifier.c b/src/shared/specifier.c index c5c4a4d7d7..841f4654b0 100644 --- a/src/shared/specifier.c +++ b/src/shared/specifier.c @@ -19,15 +19,20 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdlib.h>  #include <string.h>  #include <sys/utsname.h> +#include "sd-id128.h" +  #include "alloc-util.h"  #include "hostname-util.h"  #include "macro.h"  #include "specifier.h"  #include "string-util.h" -#include "util.h"  /*   * Generic infrastructure for replacing %x style specifiers in diff --git a/src/shared/switch-root.c b/src/shared/switch-root.c index fc885f6cb8..b1bbbdaadd 100644 --- a/src/shared/switch-root.c +++ b/src/shared/switch-root.c @@ -21,14 +21,16 @@  #include <errno.h>  #include <fcntl.h> +#include <limits.h>  #include <stdbool.h> -#include <string.h> +#include <stdio.h>  #include <sys/mount.h>  #include <sys/stat.h>  #include <unistd.h>  #include "base-filesystem.h"  #include "fd-util.h" +#include "log.h"  #include "missing.h"  #include "mkdir.h"  #include "path-util.h" diff --git a/src/shared/switch-root.h b/src/shared/switch-root.h index adf893a922..1350fd9b1c 100644 --- a/src/shared/switch-root.h +++ b/src/shared/switch-root.h @@ -2,6 +2,7 @@  #pragma once +#include <stdbool.h>  /***    This file is part of systemd. diff --git a/src/shared/sysctl-util.c b/src/shared/sysctl-util.c index 70caa542e7..a2cb6e9763 100644 --- a/src/shared/sysctl-util.c +++ b/src/shared/sysctl-util.c @@ -19,19 +19,14 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ -#include <errno.h> -#include <getopt.h> -#include <limits.h> -#include <stdbool.h>  #include <stdio.h> -#include <stdlib.h>  #include <string.h>  #include "fileio.h"  #include "log.h" +#include "macro.h"  #include "string-util.h"  #include "sysctl-util.h" -#include "util.h"  char *sysctl_normalize(char *s) {          char *n; diff --git a/src/shared/uid-range.c b/src/shared/uid-range.c index 079dd8752c..1ecef5a44c 100644 --- a/src/shared/uid-range.c +++ b/src/shared/uid-range.c @@ -19,9 +19,13 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <errno.h> +#include <stdlib.h> +#include <string.h> + +#include "macro.h"  #include "uid-range.h"  #include "user-util.h" -#include "util.h"  static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {          assert(range); diff --git a/src/shared/utmp-wtmp.c b/src/shared/utmp-wtmp.c index 13b32a0509..e72f6fa1a2 100644 --- a/src/shared/utmp-wtmp.c +++ b/src/shared/utmp-wtmp.c @@ -22,7 +22,11 @@  #include <errno.h>  #include <fcntl.h>  #include <poll.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h>  #include <string.h> +#include <sys/time.h>  #include <sys/utsname.h>  #include <unistd.h>  #include <utmpx.h> @@ -34,7 +38,9 @@  #include "path-util.h"  #include "string-util.h"  #include "terminal-util.h" +#include "time-util.h"  #include "user-util.h" +#include "util.h"  #include "utmp-wtmp.h"  int utmp_get_runlevel(int *runlevel, int *previous) { diff --git a/src/shared/utmp-wtmp.h b/src/shared/utmp-wtmp.h index e0ceb873ac..3aec3f959d 100644 --- a/src/shared/utmp-wtmp.h +++ b/src/shared/utmp-wtmp.h @@ -21,6 +21,10 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> +#include <sys/types.h> + +#include "time-util.h"  #include "util.h"  #ifdef HAVE_UTMP diff --git a/src/shared/watchdog.c b/src/shared/watchdog.c index 7131e94cdb..bc171817ea 100644 --- a/src/shared/watchdog.c +++ b/src/shared/watchdog.c @@ -22,11 +22,13 @@  #include <errno.h>  #include <fcntl.h>  #include <sys/ioctl.h> +#include <syslog.h>  #include <unistd.h>  #include <linux/watchdog.h>  #include "fd-util.h"  #include "log.h" +#include "time-util.h"  #include "watchdog.h"  static int watchdog_fd = -1; diff --git a/src/shared/watchdog.h b/src/shared/watchdog.h index b748b15857..fd1c11a644 100644 --- a/src/shared/watchdog.h +++ b/src/shared/watchdog.h @@ -21,6 +21,9 @@    along with systemd; If not, see <http://www.gnu.org/licenses/>.  ***/ +#include <stdbool.h> + +#include "time-util.h"  #include "util.h"  int watchdog_set_timeout(usec_t *usec); diff --git a/src/systemd/_sd-common.h b/src/systemd/_sd-common.h index 18765bff32..6b5e6c50f9 100644 --- a/src/systemd/_sd-common.h +++ b/src/systemd/_sd-common.h @@ -57,10 +57,10 @@  #  ifdef __cplusplus  #    define _SD_BEGIN_DECLARATIONS                              \          extern "C" {                                            \ -        struct __useless_struct_to_allow_trailing_semicolon__ +        struct _sd_useless_struct_to_allow_trailing_semicolon_  #  else  #    define _SD_BEGIN_DECLARATIONS                              \ -        struct __useless_struct_to_allow_trailing_semicolon__ +        struct _sd_useless_struct_to_allow_trailing_semicolon_  #  endif  #endif @@ -68,10 +68,10 @@  #  ifdef __cplusplus  #    define _SD_END_DECLARATIONS                                \          }                                                       \ -        struct __useless_struct_to_allow_trailing_semicolon__ +        struct _sd_useless_cpp_struct_to_allow_trailing_semicolon_  #  else  #    define _SD_END_DECLARATIONS                                \ -        struct __useless_struct_to_allow_trailing_semicolon__ +        struct _sd_useless_struct_to_allow_trailing_semicolon_  #  endif  #endif @@ -80,6 +80,6 @@                  if (*p)                                         \                          func(*p);                               \          }                                                       \ -        struct __useless_struct_to_allow_trailing_semicolon__ +        struct _sd_useless_struct_to_allow_trailing_semicolon_  #endif diff --git a/src/test/test-acl-util.c b/src/test/test-acl-util.c new file mode 100644 index 0000000000..91866daf2d --- /dev/null +++ b/src/test/test-acl-util.c @@ -0,0 +1,87 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** +  This file is part of systemd. + +  Copyright 2015 Zbigniew Jędrzejewski-Szmek + +  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 <fcntl.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "acl-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "string-util.h" +#include "user-util.h" + +static void test_add_acls_for_user(void) { +        char fn[] = "/tmp/test-empty.XXXXXX"; +        _cleanup_close_ int fd = -1; +        char *cmd; +        uid_t uid; +        int r; + +        fd = mkostemp_safe(fn, O_RDWR|O_CLOEXEC); +        assert_se(fd >= 0); + +        /* Use the mode that user journal files use */ +        assert_se(fchmod(fd, 0640) == 0); + +        cmd = strjoina("ls -l ", fn); +        assert_se(system(cmd) == 0); + +        cmd = strjoina("getfacl -p ", fn); +        assert_se(system(cmd) == 0); + +        if (getuid() == 0) { +                const char *nobody = "nobody"; +                r = get_user_creds(&nobody, &uid, NULL, NULL, NULL); +                if (r < 0) +                        uid = 0; +        } else +                uid = getuid(); + +        r = add_acls_for_user(fd, uid); +        assert_se(r >= 0); + +        cmd = strjoina("ls -l ", fn); +        assert_se(system(cmd) == 0); + +        cmd = strjoina("getfacl -p ", fn); +        assert_se(system(cmd) == 0); + +        /* set the acls again */ + +        r = add_acls_for_user(fd, uid); +        assert_se(r >= 0); + +        cmd = strjoina("ls -l ", fn); +        assert_se(system(cmd) == 0); + +        cmd = strjoina("getfacl -p ", fn); +        assert_se(system(cmd) == 0); + +        unlink(fn); +} + +int main(int argc, char **argv) { +        test_add_acls_for_user(); + +        return 0; +} diff --git a/src/test/test-condition.c b/src/test/test-condition.c index f224c6cdd8..8903d10db7 100644 --- a/src/test/test-condition.c +++ b/src/test/test-condition.c @@ -203,7 +203,7 @@ static void test_condition_test_security(void) {          condition_free(condition);          condition = condition_new(CONDITION_SECURITY, "selinux", false, true); -        assert_se(condition_test(condition) != mac_selinux_use()); +        assert_se(condition_test(condition) != mac_selinux_have());          condition_free(condition);          condition = condition_new(CONDITION_SECURITY, "ima", false, false); diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index f010e4e19a..de003e251c 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -39,7 +39,7 @@ static void test_dns_label_unescape_one(const char *what, const char *expect, si  static void test_dns_label_unescape(void) {          test_dns_label_unescape_one("hallo", "hallo", 6, 5); -        test_dns_label_unescape_one("hallo", "hallo", 4, -ENOSPC); +        test_dns_label_unescape_one("hallo", "hallo", 4, -ENOBUFS);          test_dns_label_unescape_one("", "", 10, 0);          test_dns_label_unescape_one("hallo\\.foobar", "hallo.foobar", 20, 12);          test_dns_label_unescape_one("hallo.foobar", "hallo", 10, 5); @@ -56,7 +56,7 @@ static void test_dns_name_to_wire_format_one(const char *what, const char *expec          uint8_t buffer[buffer_sz];          int r; -        r = dns_name_to_wire_format(what, buffer, buffer_sz); +        r = dns_name_to_wire_format(what, buffer, buffer_sz, false);          assert_se(r == ret);          if (r < 0) @@ -66,11 +66,38 @@ static void test_dns_name_to_wire_format_one(const char *what, const char *expec  }  static void test_dns_name_to_wire_format(void) { -        const char out1[] = { 3, 'f', 'o', 'o', 0 }; -        const char out2[] = { 5, 'h', 'a', 'l', 'l', 'o', 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; -        const char out3[] = { 4, ' ', 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; - -        test_dns_name_to_wire_format_one("", NULL, 0, -EINVAL); +        static const char out0[] = { 0 }; +        static const char out1[] = { 3, 'f', 'o', 'o', 0 }; +        static const char out2[] = { 5, 'h', 'a', 'l', 'l', 'o', 3, 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; +        static const char out3[] = { 4, ' ', 'f', 'o', 'o', 3, 'b', 'a', 'r', 0 }; +        static const char out4[] = { 9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     9, 'a', '1', '2', '3', '4', '5', '6', '7', '8', +                                     3, 'a', '1', '2', 0 }; + +        test_dns_name_to_wire_format_one("", out0, sizeof(out0), sizeof(out0));          test_dns_name_to_wire_format_one("foo", out1, sizeof(out1), sizeof(out1));          test_dns_name_to_wire_format_one("foo", out1, sizeof(out1) + 1, sizeof(out1)); @@ -80,6 +107,9 @@ static void test_dns_name_to_wire_format(void) {          test_dns_name_to_wire_format_one("hallo.foo..bar", NULL, 32, -EINVAL);          test_dns_name_to_wire_format_one("\\032foo.bar", out3, sizeof(out3), sizeof(out3)); + +        test_dns_name_to_wire_format_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", NULL, 500, -EINVAL); +        test_dns_name_to_wire_format_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", out4, sizeof(out4), sizeof(out4));  }  static void test_dns_label_unescape_suffix_one(const char *what, const char *expect1, const char *expect2, size_t buffer_sz, int ret1, int ret2) { @@ -102,7 +132,7 @@ static void test_dns_label_unescape_suffix_one(const char *what, const char *exp  static void test_dns_label_unescape_suffix(void) {          test_dns_label_unescape_suffix_one("hallo", "hallo", "", 6, 5, 0); -        test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOSPC, -ENOSPC); +        test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOBUFS, -ENOBUFS);          test_dns_label_unescape_suffix_one("", "", "", 10, 0, 0);          test_dns_label_unescape_suffix_one("hallo\\.foobar", "hallo.foobar", "", 20, 12, 0);          test_dns_label_unescape_suffix_one("hallo.foobar", "foobar", "hallo", 10, 6, 5); @@ -136,7 +166,7 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex  }  static void test_dns_label_escape(void) { -        test_dns_label_escape_one("", 0, "", 0); +        test_dns_label_escape_one("", 0, NULL, -EINVAL);          test_dns_label_escape_one("hallo", 5, "hallo", 5);          test_dns_label_escape_one("hallo", 6, NULL, -EINVAL);          test_dns_label_escape_one("hallo hallo.foobar,waldi", 24, "hallo\\032hallo\\.foobar\\044waldi", 31); @@ -314,6 +344,24 @@ static void test_dns_name_is_valid(void) {          test_dns_name_is_valid_one("\\zbar", 0);          test_dns_name_is_valid_one("ä", 1);          test_dns_name_is_valid_one("\n", 0); + +        /* 256 characters*/ +        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345", 0); + +        /* 255 characters*/ +        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a1234", 0); + +        /* 254 characters*/ +        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a123", 0); + +        /* 253 characters*/ +        test_dns_name_is_valid_one("a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12345678.a12", 1); + +        /* label of 64 chars length */ +        test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a123", 0); + +        /* label of 63 chars length */ +        test_dns_name_is_valid_one("a123456789a123456789a123456789a123456789a123456789a123456789a12", 1);  }  static void test_dns_service_name_is_valid(void) { diff --git a/src/test/test-engine.c b/src/test/test-engine.c index c98d01168c..e23eec7370 100644 --- a/src/test/test-engine.c +++ b/src/test/test-engine.c @@ -25,6 +25,7 @@  #include "bus-util.h"  #include "manager.h" +#include "test-helper.h"  int main(int argc, char *argv[]) {          _cleanup_(sd_bus_error_free) sd_bus_error err = SD_BUS_ERROR_NULL; @@ -38,8 +39,8 @@ int main(int argc, char *argv[]) {          /* prepare the test */          assert_se(set_unit_path(TEST_DIR) >= 0);          r = manager_new(MANAGER_USER, true, &m); -        if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { -                printf("Skipping test: manager_new: %s", strerror(-r)); +        if (MANAGER_SKIP_TEST(r)) { +                printf("Skipping test: manager_new: %s\n", strerror(-r));                  return EXIT_TEST_SKIP;          }          assert_se(r >= 0); diff --git a/src/test/test-execute.c b/src/test/test-execute.c index 03ec0fcfc7..753afadb0a 100644 --- a/src/test/test-execute.c +++ b/src/test/test-execute.c @@ -29,6 +29,7 @@  #include "mkdir.h"  #include "path-util.h"  #include "rm-rf.h" +#include "test-helper.h"  #include "unit.h"  #include "util.h" @@ -296,8 +297,8 @@ int main(int argc, char *argv[]) {          assert_se(unsetenv("VAR3") == 0);          r = manager_new(MANAGER_USER, true, &m); -        if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT)) { -                printf("Skipping test: manager_new: %s", strerror(-r)); +        if (MANAGER_SKIP_TEST(r)) { +                printf("Skipping test: manager_new: %s\n", strerror(-r));                  return EXIT_TEST_SKIP;          }          assert_se(r >= 0); diff --git a/src/test/test-helper.h b/src/test/test-helper.h index f75dd3374a..c0f6a91787 100644 --- a/src/test/test-helper.h +++ b/src/test/test-helper.h @@ -23,9 +23,21 @@  #include "sd-daemon.h" +#include "macro.h" +  #define TEST_REQ_RUNNING_SYSTEMD(x)                                 \          if (sd_booted() > 0) {                                      \                  x;                                                  \          } else {                                                    \                  printf("systemd not booted skipping '%s'\n", #x);   \          } + +#define MANAGER_SKIP_TEST(r)                                    \ +        IN_SET(r,                                               \ +               -EPERM,                                          \ +               -EACCES,                                         \ +               -EADDRINUSE,                                     \ +               -EHOSTDOWN,                                      \ +               -ENOENT,                                         \ +               -ENOMEDIUM /* cannot determine cgroup */         \ +               ) diff --git a/src/test/test-path.c b/src/test/test-path.c index 8302bdd283..7a3b145414 100644 --- a/src/test/test-path.c +++ b/src/test/test-path.c @@ -29,6 +29,7 @@  #include "rm-rf.h"  #include "string-util.h"  #include "strv.h" +#include "test-helper.h"  #include "unit.h"  #include "util.h" @@ -44,8 +45,8 @@ static int setup_test(Manager **m) {          assert_se(m);          r = manager_new(MANAGER_USER, true, &tmp); -        if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { -                printf("Skipping test: manager_new: %s", strerror(-r)); +        if (MANAGER_SKIP_TEST(r)) { +                printf("Skipping test: manager_new: %s\n", strerror(-r));                  return -EXIT_TEST_SKIP;          }          assert_se(r >= 0); diff --git a/src/test/test-rbtree.c b/src/test/test-rbtree.c new file mode 100644 index 0000000000..8ae416c557 --- /dev/null +++ b/src/test/test-rbtree.c @@ -0,0 +1,362 @@ +/*** +  This file is part of systemd. See COPYING for details. + +  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/>. +***/ + +/* + * Tests for RB-Tree + */ + +#undef NDEBUG +#include <assert.h> +#include <stddef.h> +#include <stdlib.h> +#include "c-rbtree.h" + +/* verify that all API calls are exported */ +static void test_api(void) { +        CRBTree t = {}; +        CRBNode n = C_RBNODE_INIT(n); + +        assert(!c_rbnode_is_linked(&n)); + +        /* init, is_linked, add, remove, remove_init */ + +        c_rbtree_add(&t, NULL, &t.root, &n); +        assert(c_rbnode_is_linked(&n)); + +        c_rbtree_remove_init(&t, &n); +        assert(!c_rbnode_is_linked(&n)); + +        c_rbtree_add(&t, NULL, &t.root, &n); +        assert(c_rbnode_is_linked(&n)); + +        c_rbtree_remove(&t, &n); +        assert(c_rbnode_is_linked(&n)); /* @n wasn't touched */ + +        c_rbnode_init(&n); +        assert(!c_rbnode_is_linked(&n)); + +        /* first, last, leftmost, rightmost, next, prev */ + +        assert(!c_rbtree_first(&t)); +        assert(!c_rbtree_last(&t)); +        assert(&n == c_rbnode_leftmost(&n)); +        assert(&n == c_rbnode_rightmost(&n)); +        assert(!c_rbnode_next(&n)); +        assert(!c_rbnode_prev(&n)); +} + +/* copied from c-rbtree.c, relies on internal representation */ +static inline _Bool c_rbnode_is_red(CRBNode *n) { +        return !((unsigned long)n->__parent_and_color & 1UL); +} + +/* copied from c-rbtree.c, relies on internal representation */ +static inline _Bool c_rbnode_is_black(CRBNode *n) { +        return !!((unsigned long)n->__parent_and_color & 1UL); +} + +static size_t validate(CRBTree *t) { +        unsigned int i_black, n_black; +        CRBNode *n, *p, *o; +        size_t count = 0; + +        assert(t); +        assert(!t->root || c_rbnode_is_black(t->root)); + +        /* traverse to left-most child, count black nodes */ +        i_black = 0; +        n = t->root; +        while (n && n->left) { +                if (c_rbnode_is_black(n)) +                        ++i_black; +                n = n->left; +        } +        n_black = i_black; + +        /* +         * Traverse tree and verify correctness: +         *  1) A node is either red or black +         *  2) The root is black +         *  3) All leaves are black +         *  4) Every red node must have two black child nodes +         *  5) Every path to a leaf contains the same number of black nodes +         * +         * Note that NULL nodes are considered black, which is why we don't +         * check for 3). +         */ +        o = NULL; +        while (n) { +                ++count; + +                /* verify natural order */ +                assert(n > o); +                o = n; + +                /* verify consistency */ +                assert(!n->right || c_rbnode_parent(n->right) == n); +                assert(!n->left || c_rbnode_parent(n->left) == n); + +                /* verify 2) */ +                if (!c_rbnode_parent(n)) +                        assert(c_rbnode_is_black(n)); + +                if (c_rbnode_is_red(n)) { +                        /* verify 4) */ +                        assert(!n->left || c_rbnode_is_black(n->left)); +                        assert(!n->right || c_rbnode_is_black(n->right)); +                } else { +                        /* verify 1) */ +                        assert(c_rbnode_is_black(n)); +                } + +                /* verify 5) */ +                if (!n->left && !n->right) +                        assert(i_black == n_black); + +                /* get next node */ +                if (n->right) { +                        n = n->right; +                        if (c_rbnode_is_black(n)) +                                ++i_black; + +                        while (n->left) { +                                n = n->left; +                                if (c_rbnode_is_black(n)) +                                        ++i_black; +                        } +                } else { +                        while ((p = c_rbnode_parent(n)) && n == p->right) { +                                n = p; +                                if (c_rbnode_is_black(p->right)) +                                        --i_black; +                        } + +                        n = p; +                        if (p && c_rbnode_is_black(p->left)) +                                --i_black; +                } +        } + +        return count; +} + +static void insert(CRBTree *t, CRBNode *n) { +        CRBNode **i, *p; + +        assert(t); +        assert(n); +        assert(!c_rbnode_is_linked(n)); + +        i = &t->root; +        p = NULL; +        while (*i) { +                p = *i; +                if (n < *i) { +                        i = &(*i)->left; +                } else { +                        assert(n > *i); +                        i = &(*i)->right; +                } +        } + +        c_rbtree_add(t, p, i, n); +} + +static void shuffle(void **nodes, size_t n_memb) { +        unsigned int i, j; +        void *t; + +        for (i = 0; i < n_memb; ++i) { +                j = rand() % n_memb; +                t = nodes[j]; +                nodes[j] = nodes[i]; +                nodes[i] = t; +        } +} + +/* run some pseudo-random tests on the tree */ +static void test_shuffle(void) { +        CRBNode *nodes[256]; +        CRBTree t = {}; +        unsigned int i, j; +        size_t n; + +        /* allocate and initialize all nodes */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { +                nodes[i] = malloc(sizeof(*nodes[i])); +                assert(nodes[i]); +                c_rbnode_init(nodes[i]); +        } + +        /* shuffle nodes and validate *empty* tree */ +        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); +        n = validate(&t); +        assert(n == 0); + +        /* add all nodes and validate after each insertion */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { +                insert(&t, nodes[i]); +                n = validate(&t); +                assert(n == i + 1); +        } + +        /* shuffle nodes again */ +        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + +        /* remove all nodes (in different order) and validate on each round */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { +                c_rbtree_remove(&t, nodes[i]); +                n = validate(&t); +                assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); +                c_rbnode_init(nodes[i]); +        } + +        /* shuffle nodes and validate *empty* tree again */ +        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); +        n = validate(&t); +        assert(n == 0); + +        /* add all nodes again */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { +                insert(&t, nodes[i]); +                n = validate(&t); +                assert(n == i + 1); +        } + +        /* 4 times, remove half of the nodes and add them again */ +        for (j = 0; j < 4; ++j) { +                /* shuffle nodes again */ +                shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + +                /* remove half of the nodes */ +                for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) { +                        c_rbtree_remove(&t, nodes[i]); +                        n = validate(&t); +                        assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); +                        c_rbnode_init(nodes[i]); +                } + +                /* shuffle the removed half */ +                shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes) / 2); + +                /* add the removed half again */ +                for (i = 0; i < sizeof(nodes) / sizeof(*nodes) / 2; ++i) { +                        insert(&t, nodes[i]); +                        n = validate(&t); +                        assert(n == sizeof(nodes) / sizeof(*nodes) / 2 + i + 1); +                } +        } + +        /* shuffle nodes again */ +        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + +        /* remove all */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { +                c_rbtree_remove(&t, nodes[i]); +                n = validate(&t); +                assert(n == sizeof(nodes) / sizeof(*nodes) - i - 1); +                c_rbnode_init(nodes[i]); +        } + +        /* free nodes again */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) +                free(nodes[i]); +} + +typedef struct { +        unsigned long key; +        CRBNode rb; +} Node; + +#define node_from_rb(_rb) ((Node *)((char *)(_rb) - offsetof(Node, rb))) + +static int compare(CRBTree *t, void *k, CRBNode *n) { +        unsigned long key = (unsigned long)k; +        Node *node = node_from_rb(n); + +        return (key < node->key) ? -1 : (key > node->key) ? 1 : 0; +} + +/* run tests against the c_rbtree_find*() helpers */ +static void test_map(void) { +        CRBNode **slot, *p; +        CRBTree t = {}; +        Node *nodes[2048]; +        unsigned long i; + +        /* allocate and initialize all nodes */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { +                nodes[i] = malloc(sizeof(*nodes[i])); +                assert(nodes[i]); +                nodes[i]->key = i; +                c_rbnode_init(&nodes[i]->rb); +        } + +        /* shuffle nodes */ +        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + +        /* add all nodes, and verify that each node is linked */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { +                assert(!c_rbnode_is_linked(&nodes[i]->rb)); +                assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); + +                slot = c_rbtree_find_slot(&t, compare, (void *)nodes[i]->key, &p); +                assert(slot); +                c_rbtree_add(&t, p, slot, &nodes[i]->rb); + +                assert(c_rbnode_is_linked(&nodes[i]->rb)); +                assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); +        } + +        /* shuffle nodes again */ +        shuffle((void **)nodes, sizeof(nodes) / sizeof(*nodes)); + +        /* remove all nodes (in different order) */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) { +                assert(c_rbnode_is_linked(&nodes[i]->rb)); +                assert(nodes[i] == c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); + +                c_rbtree_remove_init(&t, &nodes[i]->rb); + +                assert(!c_rbnode_is_linked(&nodes[i]->rb)); +                assert(!c_rbtree_find_entry(&t, compare, (void *)nodes[i]->key, Node, rb)); +        } + +        /* free nodes again */ +        for (i = 0; i < sizeof(nodes) / sizeof(*nodes); ++i) +                free(nodes[i]); +} + +int main(int argc, char **argv) { +        unsigned int i; + +        /* we want stable tests, so use fixed seed */ +        srand(0xdeadbeef); + +        test_api(); + +        /* +         * The tests are pseudo random; run them multiple times, each run will +         * have different orders and thus different results. +         */ +        for (i = 0; i < 4; ++i) { +                test_shuffle(); +                test_map(); +        } + +        return 0; +} diff --git a/src/test/test-rlimit-util.c b/src/test/test-rlimit-util.c new file mode 100644 index 0000000000..00d3ecc0de --- /dev/null +++ b/src/test/test-rlimit-util.c @@ -0,0 +1,69 @@ +/*** +  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. + +  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 <sys/resource.h> + +#include "capability-util.h" +#include "macro.h" +#include "rlimit-util.h" +#include "string-util.h" +#include "util.h" + +int main(int argc, char *argv[]) { +        struct rlimit old, new, high; +        struct rlimit err = { +                .rlim_cur = 10, +                .rlim_max = 5, +        }; + +        log_parse_environment(); +        log_open(); + +        assert_se(drop_capability(CAP_SYS_RESOURCE) == 0); + +        assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); +        new.rlim_cur = MIN(5U, old.rlim_max); +        new.rlim_max = MIN(10U, old.rlim_max); +        assert_se(setrlimit(RLIMIT_NOFILE, &new) >= 0); + +        assert_se(rlimit_from_string("LimitNOFILE") == RLIMIT_NOFILE); +        assert_se(rlimit_from_string("DefaultLimitNOFILE") == -1); + +        assert_se(streq_ptr(rlimit_to_string(RLIMIT_NOFILE), "LimitNOFILE")); +        assert_se(rlimit_to_string(-1) == NULL); + +        assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); +        assert_se(setrlimit_closest(RLIMIT_NOFILE, &old) == 0); +        assert_se(getrlimit(RLIMIT_NOFILE, &new) == 0); +        assert_se(old.rlim_cur == new.rlim_cur); +        assert_se(old.rlim_max == new.rlim_max); + +        assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); +        high = RLIMIT_MAKE_CONST(old.rlim_max + 1); +        assert_se(setrlimit_closest(RLIMIT_NOFILE, &high) == 0); +        assert_se(getrlimit(RLIMIT_NOFILE, &new) == 0); +        assert_se(new.rlim_max == old.rlim_max); +        assert_se(new.rlim_cur == new.rlim_max); + +        assert_se(getrlimit(RLIMIT_NOFILE, &old) == 0); +        assert_se(setrlimit_closest(RLIMIT_NOFILE, &err) == -EINVAL); +        assert_se(getrlimit(RLIMIT_NOFILE, &new) == 0); +        assert_se(old.rlim_cur == new.rlim_cur); +        assert_se(old.rlim_max == new.rlim_max); + +        return 0; +} diff --git a/src/test/test-sched-prio.c b/src/test/test-sched-prio.c index 8396ae60f3..60b5160cec 100644 --- a/src/test/test-sched-prio.c +++ b/src/test/test-sched-prio.c @@ -23,6 +23,7 @@  #include "macro.h"  #include "manager.h" +#include "test-helper.h"  int main(int argc, char *argv[]) {          Manager *m = NULL; @@ -35,8 +36,8 @@ int main(int argc, char *argv[]) {          /* prepare the test */          assert_se(set_unit_path(TEST_DIR) >= 0);          r = manager_new(MANAGER_USER, true, &m); -        if (IN_SET(r, -EPERM, -EACCES, -EADDRINUSE, -EHOSTDOWN, -ENOENT, -ENOEXEC)) { -                printf("Skipping test: manager_new: %s", strerror(-r)); +        if (MANAGER_SKIP_TEST(r)) { +                printf("Skipping test: manager_new: %s\n", strerror(-r));                  return EXIT_TEST_SKIP;          }          assert_se(r >= 0); diff --git a/src/udev/scsi_id/scsi.h b/src/udev/scsi_id/scsi.h index 3f99ae7724..1054551d0b 100644 --- a/src/udev/scsi_id/scsi.h +++ b/src/udev/scsi_id/scsi.h @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * scsi.h   * @@ -24,25 +26,25 @@ struct scsi_ioctl_command {  /*   * Default 5 second timeout   */ -#define DEF_TIMEOUT        5000 +#define DEF_TIMEOUT 5000 -#define SENSE_BUFF_LEN        32 +#define SENSE_BUFF_LEN 32  /*   * The request buffer size passed to the SCSI INQUIRY commands, use 254,   * as this is a nice value for some devices, especially some of the usb   * mass storage devices.   */ -#define        SCSI_INQ_BUFF_LEN        254 +#define SCSI_INQ_BUFF_LEN 254  /*   * SCSI INQUIRY vendor and model (really product) lengths.   */ -#define VENDOR_LENGTH        8 -#define        MODEL_LENGTH        16 +#define VENDOR_LENGTH 8 +#define MODEL_LENGTH 16 -#define INQUIRY_CMD     0x12 -#define INQUIRY_CMDLEN  6 +#define INQUIRY_CMD 0x12 +#define INQUIRY_CMDLEN 6  /*   * INQUIRY VPD page 0x83 identifier descriptor related values. Reference the @@ -52,34 +54,34 @@ struct scsi_ioctl_command {  /*   * id type values of id descriptors. These are assumed to fit in 4 bits.   */ -#define SCSI_ID_VENDOR_SPECIFIC        0 -#define SCSI_ID_T10_VENDOR        1 -#define SCSI_ID_EUI_64                2 -#define SCSI_ID_NAA                3 -#define SCSI_ID_RELPORT                4 +#define SCSI_ID_VENDOR_SPECIFIC 0 +#define SCSI_ID_T10_VENDOR      1 +#define SCSI_ID_EUI_64          2 +#define SCSI_ID_NAA             3 +#define SCSI_ID_RELPORT         4  #define SCSI_ID_TGTGROUP        5  #define SCSI_ID_LUNGROUP        6 -#define SCSI_ID_MD5                7 -#define SCSI_ID_NAME                8 +#define SCSI_ID_MD5             7 +#define SCSI_ID_NAME            8  /*   * Supported NAA values. These fit in 4 bits, so the "don't care" value   * cannot conflict with real values.   */ -#define        SCSI_ID_NAA_DONT_CARE                0xff -#define        SCSI_ID_NAA_IEEE_REG                5 -#define        SCSI_ID_NAA_IEEE_REG_EXTENDED        6 +#define SCSI_ID_NAA_DONT_CARE         0xff +#define SCSI_ID_NAA_IEEE_REG          0x05 +#define SCSI_ID_NAA_IEEE_REG_EXTENDED 0x06  /*   * Supported Code Set values.   */ -#define        SCSI_ID_BINARY        1 -#define        SCSI_ID_ASCII        2 +#define SCSI_ID_BINARY 1 +#define SCSI_ID_ASCII  2  struct scsi_id_search_values { -        u_char        id_type; -        u_char        naa_type; -        u_char        code_set; +        u_char id_type; +        u_char naa_type; +        u_char code_set;  };  /* @@ -87,13 +89,13 @@ struct scsi_id_search_values {   * used a 1 bit right and masked version of these. So now CHECK_CONDITION   * and friends (in <scsi/scsi.h>) are deprecated.   */ -#define SCSI_CHECK_CONDITION 0x2 -#define SCSI_CONDITION_MET 0x4 -#define SCSI_BUSY 0x8 -#define SCSI_IMMEDIATE 0x10 +#define SCSI_CHECK_CONDITION         0x02 +#define SCSI_CONDITION_MET           0x04 +#define SCSI_BUSY                    0x08 +#define SCSI_IMMEDIATE               0x10  #define SCSI_IMMEDIATE_CONDITION_MET 0x14 -#define SCSI_RESERVATION_CONFLICT 0x18 -#define SCSI_COMMAND_TERMINATED 0x22 -#define SCSI_TASK_SET_FULL 0x28 -#define SCSI_ACA_ACTIVE 0x30 -#define SCSI_TASK_ABORTED 0x40 +#define SCSI_RESERVATION_CONFLICT    0x18 +#define SCSI_COMMAND_TERMINATED      0x22 +#define SCSI_TASK_SET_FULL           0x28 +#define SCSI_ACA_ACTIVE              0x30 +#define SCSI_TASK_ABORTED            0x40 diff --git a/src/udev/scsi_id/scsi_id.c b/src/udev/scsi_id/scsi_id.c index 4655691642..e9ab7dce59 100644 --- a/src/udev/scsi_id/scsi_id.c +++ b/src/udev/scsi_id/scsi_id.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) IBM Corp. 2003   * Copyright (C) SUSE Linux Products GmbH, 2006 diff --git a/src/udev/scsi_id/scsi_id.h b/src/udev/scsi_id/scsi_id.h index 141b116a88..25f3d1a3b7 100644 --- a/src/udev/scsi_id/scsi_id.h +++ b/src/udev/scsi_id/scsi_id.h @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) IBM Corp. 2003   * diff --git a/src/udev/scsi_id/scsi_serial.c b/src/udev/scsi_id/scsi_serial.c index c7ef783684..bc18af05af 100644 --- a/src/udev/scsi_id/scsi_serial.c +++ b/src/udev/scsi_id/scsi_serial.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) IBM Corp. 2003   * @@ -50,11 +52,11 @@   * is normally one or some small number of descriptors.   */  static const struct scsi_id_search_values id_search_list[] = { -        { SCSI_ID_TGTGROUP,        SCSI_ID_NAA_DONT_CARE,        SCSI_ID_BINARY }, -        { SCSI_ID_NAA,        SCSI_ID_NAA_IEEE_REG_EXTENDED,        SCSI_ID_BINARY }, -        { SCSI_ID_NAA,        SCSI_ID_NAA_IEEE_REG_EXTENDED,        SCSI_ID_ASCII }, -        { SCSI_ID_NAA,        SCSI_ID_NAA_IEEE_REG,        SCSI_ID_BINARY }, -        { SCSI_ID_NAA,        SCSI_ID_NAA_IEEE_REG,        SCSI_ID_ASCII }, +        { SCSI_ID_TGTGROUP, SCSI_ID_NAA_DONT_CARE,         SCSI_ID_BINARY }, +        { SCSI_ID_NAA,      SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_BINARY }, +        { SCSI_ID_NAA,      SCSI_ID_NAA_IEEE_REG_EXTENDED, SCSI_ID_ASCII  }, +        { SCSI_ID_NAA,      SCSI_ID_NAA_IEEE_REG,          SCSI_ID_BINARY }, +        { SCSI_ID_NAA,      SCSI_ID_NAA_IEEE_REG,          SCSI_ID_ASCII  },          /*           * Devices already exist using NAA values that are now marked           * reserved. These should not conflict with other values, or it is @@ -64,14 +66,14 @@ static const struct scsi_id_search_values id_search_list[] = {           * non-IEEE descriptors in a random order will get different           * names.           */ -        { SCSI_ID_NAA,        SCSI_ID_NAA_DONT_CARE,        SCSI_ID_BINARY }, -        { SCSI_ID_NAA,        SCSI_ID_NAA_DONT_CARE,        SCSI_ID_ASCII }, -        { SCSI_ID_EUI_64,        SCSI_ID_NAA_DONT_CARE,        SCSI_ID_BINARY }, -        { SCSI_ID_EUI_64,        SCSI_ID_NAA_DONT_CARE,        SCSI_ID_ASCII }, -        { SCSI_ID_T10_VENDOR,        SCSI_ID_NAA_DONT_CARE,        SCSI_ID_BINARY }, -        { SCSI_ID_T10_VENDOR,        SCSI_ID_NAA_DONT_CARE,        SCSI_ID_ASCII }, -        { SCSI_ID_VENDOR_SPECIFIC,        SCSI_ID_NAA_DONT_CARE,        SCSI_ID_BINARY }, -        { SCSI_ID_VENDOR_SPECIFIC,        SCSI_ID_NAA_DONT_CARE,        SCSI_ID_ASCII }, +        { SCSI_ID_NAA,             SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, +        { SCSI_ID_NAA,             SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII  }, +        { SCSI_ID_EUI_64,          SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, +        { SCSI_ID_EUI_64,          SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII  }, +        { SCSI_ID_T10_VENDOR,      SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, +        { SCSI_ID_T10_VENDOR,      SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII  }, +        { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_BINARY }, +        { SCSI_ID_VENDOR_SPECIFIC, SCSI_ID_NAA_DONT_CARE, SCSI_ID_ASCII  },  };  static const char hex_str[]="0123456789abcdef"; @@ -81,21 +83,21 @@ static const char hex_str[]="0123456789abcdef";   * are used here.   */ -#define DID_NO_CONNECT                        0x01        /* Unable to connect before timeout */ -#define DID_BUS_BUSY                        0x02        /* Bus remain busy until timeout */ -#define DID_TIME_OUT                        0x03        /* Timed out for some other reason */ -#define DRIVER_TIMEOUT                        0x06 -#define DRIVER_SENSE                        0x08        /* Sense_buffer has been set */ +#define DID_NO_CONNECT               0x01        /* Unable to connect before timeout */ +#define DID_BUS_BUSY                 0x02        /* Bus remain busy until timeout */ +#define DID_TIME_OUT                 0x03        /* Timed out for some other reason */ +#define DRIVER_TIMEOUT               0x06 +#define DRIVER_SENSE                 0x08        /* Sense_buffer has been set */  /* The following "category" function returns one of the following */  #define SG_ERR_CAT_CLEAN                0        /* No errors or other information */  #define SG_ERR_CAT_MEDIA_CHANGED        1        /* interpreted from sense buffer */  #define SG_ERR_CAT_RESET                2        /* interpreted from sense buffer */ -#define SG_ERR_CAT_TIMEOUT                3 -#define SG_ERR_CAT_RECOVERED                4        /* Successful command after recovered err */ -#define SG_ERR_CAT_NOTSUPPORTED                5        /* Illegal / unsupported command */ -#define SG_ERR_CAT_SENSE                98        /* Something else in the sense buffer */ -#define SG_ERR_CAT_OTHER                99        /* Some other error/warning */ +#define SG_ERR_CAT_TIMEOUT              3 +#define SG_ERR_CAT_RECOVERED            4        /* Successful command after recovered err */ +#define SG_ERR_CAT_NOTSUPPORTED         5        /* Illegal / unsupported command */ +#define SG_ERR_CAT_SENSE               98        /* Something else in the sense buffer */ +#define SG_ERR_CAT_OTHER               99        /* Some other error/warning */  static int do_scsi_page80_inquiry(struct udev *udev,                                    struct scsi_id_device *dev_scsi, int fd, @@ -212,7 +214,7 @@ static int scsi_dump_sense(struct udev *udev,                  s = sense_buffer[7] + 8;                  if (sb_len < s) {                          log_debug("%s: sense buffer too small %d bytes, %d bytes too short", -                            dev_scsi->kernel, sb_len, s - sb_len); +                                  dev_scsi->kernel, sb_len, s - sb_len);                          return -1;                  }                  if ((code == 0x0) || (code == 0x1)) { @@ -222,7 +224,7 @@ static int scsi_dump_sense(struct udev *udev,                                   * Possible?                                   */                                  log_debug("%s: sense result too" " small %d bytes", -                                    dev_scsi->kernel, s); +                                          dev_scsi->kernel, s);                                  return -1;                          }                          asc = sense_buffer[12]; @@ -233,15 +235,15 @@ static int scsi_dump_sense(struct udev *udev,                          ascq = sense_buffer[3];                  } else {                          log_debug("%s: invalid sense code 0x%x", -                            dev_scsi->kernel, code); +                                  dev_scsi->kernel, code);                          return -1;                  }                  log_debug("%s: sense key 0x%x ASC 0x%x ASCQ 0x%x", -                    dev_scsi->kernel, sense_key, asc, ascq); +                          dev_scsi->kernel, sense_key, asc, ascq);          } else {                  if (sb_len < 4) {                          log_debug("%s: sense buffer too small %d bytes, %d bytes too short", -                            dev_scsi->kernel, sb_len, 4 - sb_len); +                                  dev_scsi->kernel, sb_len, 4 - sb_len);                          return -1;                  } @@ -249,9 +251,9 @@ static int scsi_dump_sense(struct udev *udev,                          log_debug("%s: old sense key: 0x%x", dev_scsi->kernel, sense_buffer[0] & 0x0f);                  else                          log_debug("%s: sense = %2x %2x", -                            dev_scsi->kernel, sense_buffer[0], sense_buffer[2]); +                                  dev_scsi->kernel, sense_buffer[0], sense_buffer[2]);                  log_debug("%s: non-extended sense class %d code 0x%0x", -                    dev_scsi->kernel, sense_class, code); +                          dev_scsi->kernel, sense_class, code);          } @@ -282,7 +284,7 @@ static int scsi_dump(struct udev *udev,          }          log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x 0x%x", -            dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status); +                  dev_scsi->kernel, io->driver_status, io->host_status, io->msg_status, io->status);          if (io->status == SCSI_CHECK_CONDITION)                  return scsi_dump_sense(udev, dev_scsi, io->sbp, io->sb_len_wr);          else @@ -302,8 +304,7 @@ static int scsi_dump_v4(struct udev *udev,          }          log_debug("%s: sg_io failed status 0x%x 0x%x 0x%x", -            dev_scsi->kernel, io->driver_status, io->transport_status, -             io->device_status); +                  dev_scsi->kernel, io->driver_status, io->transport_status, io->device_status);          if (io->device_status == SCSI_CHECK_CONDITION)                  return scsi_dump_sense(udev, dev_scsi, (unsigned char *)(uintptr_t)io->response,                                         io->response_len); @@ -399,7 +400,7 @@ resend:  error:          if (retval < 0)                  log_debug("%s: Unable to get INQUIRY vpd %d page 0x%x.", -                    dev_scsi->kernel, evpd, page); +                          dev_scsi->kernel, evpd, page);          return retval;  } @@ -421,7 +422,7 @@ static int do_scsi_page0_inquiry(struct udev *udev,                  return 1;          }          if (buffer[3] > len) { -                log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel,         buffer[3]); +                log_debug("%s: page 0 buffer too long %d", dev_scsi->kernel, buffer[3]);                  return 1;          } @@ -464,7 +465,7 @@ static int prepend_vendor_model(struct udev *udev,           */          if (ind != (VENDOR_LENGTH + MODEL_LENGTH)) {                  log_debug("%s: expected length %d, got length %d", -                     dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind); +                          dev_scsi->kernel, (VENDOR_LENGTH + MODEL_LENGTH), ind);                  return -1;          }          return ind; @@ -529,7 +530,7 @@ static int check_fill_0x83_id(struct udev *udev,          if (max_len < len) {                  log_debug("%s: length %d too short - need %d", -                    dev_scsi->kernel, max_len, len); +                          dev_scsi->kernel, max_len, len);                  return 1;          } @@ -785,7 +786,7 @@ static int do_scsi_page80_inquiry(struct udev *udev,          len = 1 + VENDOR_LENGTH + MODEL_LENGTH + buf[3];          if (max_len < len) {                  log_debug("%s: length %d too short - need %d", -                     dev_scsi->kernel, max_len, len); +                          dev_scsi->kernel, max_len, len);                  return 1;          }          /* diff --git a/src/udev/udev-builtin-blkid.c b/src/udev/udev-builtin-blkid.c index d0e47ec6d8..0b1ae706e7 100644 --- a/src/udev/udev-builtin-blkid.c +++ b/src/udev/udev-builtin-blkid.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * probe disks for filesystems and partitions   * diff --git a/src/udev/udev-builtin-btrfs.c b/src/udev/udev-builtin-btrfs.c index cfaa463804..467010f5b3 100644 --- a/src/udev/udev-builtin-btrfs.c +++ b/src/udev/udev-builtin-btrfs.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /***    This file is part of systemd. diff --git a/src/udev/udev-builtin-hwdb.c b/src/udev/udev-builtin-hwdb.c index f4a065a97d..a9e312e2c0 100644 --- a/src/udev/udev-builtin-hwdb.c +++ b/src/udev/udev-builtin-hwdb.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /***    This file is part of systemd. diff --git a/src/udev/udev-builtin-input_id.c b/src/udev/udev-builtin-input_id.c index fddafbd4dc..1d31829a08 100644 --- a/src/udev/udev-builtin-input_id.c +++ b/src/udev/udev-builtin-input_id.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * expose input properties via udev   * diff --git a/src/udev/udev-builtin-keyboard.c b/src/udev/udev-builtin-keyboard.c index aa10beafb0..b80be52567 100644 --- a/src/udev/udev-builtin-keyboard.c +++ b/src/udev/udev-builtin-keyboard.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /***    This file is part of systemd. diff --git a/src/udev/udev-builtin-kmod.c b/src/udev/udev-builtin-kmod.c index 9665f678fd..9210d1cc71 100644 --- a/src/udev/udev-builtin-kmod.c +++ b/src/udev/udev-builtin-kmod.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * load kernel modules   * diff --git a/src/udev/udev-builtin-net_id.c b/src/udev/udev-builtin-net_id.c index bf5c9c6b77..e549fdbee9 100644 --- a/src/udev/udev-builtin-net_id.c +++ b/src/udev/udev-builtin-net_id.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /***    This file is part of systemd. diff --git a/src/udev/udev-builtin-path_id.c b/src/udev/udev-builtin-path_id.c index aa18c7e420..7851cec17f 100644 --- a/src/udev/udev-builtin-path_id.c +++ b/src/udev/udev-builtin-path_id.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * compose persistent device path   * diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c index 3ebe36f043..b650a15bd8 100644 --- a/src/udev/udev-builtin-uaccess.c +++ b/src/udev/udev-builtin-uaccess.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * manage device node user ACL   * diff --git a/src/udev/udev-builtin-usb_id.c b/src/udev/udev-builtin-usb_id.c index 587649eff0..40d1e8cc47 100644 --- a/src/udev/udev-builtin-usb_id.c +++ b/src/udev/udev-builtin-usb_id.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * USB device properties and persistent device path   * diff --git a/src/udev/udev-builtin.c b/src/udev/udev-builtin.c index e6b36f124f..18fb6615d5 100644 --- a/src/udev/udev-builtin.c +++ b/src/udev/udev-builtin.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /***    This file is part of systemd. diff --git a/src/udev/udev-ctrl.c b/src/udev/udev-ctrl.c index 962de22f43..10dd747256 100644 --- a/src/udev/udev-ctrl.c +++ b/src/udev/udev-ctrl.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * libudev - interface to udev device information   * diff --git a/src/udev/udev-event.c b/src/udev/udev-event.c index 2ef8bfe59e..c1dcee6c73 100644 --- a/src/udev/udev-event.c +++ b/src/udev/udev-event.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2003-2013 Kay Sievers <kay@vrfy.org>   * @@ -848,11 +850,11 @@ void udev_event_execute_rules(struct udev_event *event,                          /* disable watch during event processing */                          if (major(udev_device_get_devnum(dev)) != 0)                                  udev_watch_end(event->udev, event->dev_db); -                } -                if (major(udev_device_get_devnum(dev)) == 0 && -                    streq(udev_device_get_action(dev), "move")) -                        udev_device_copy_properties(dev, event->dev_db); +                        if (major(udev_device_get_devnum(dev)) == 0 && +                            streq(udev_device_get_action(dev), "move")) +                                udev_device_copy_properties(dev, event->dev_db); +                }                  udev_rules_apply_to_event(rules, event,                                            timeout_usec, timeout_warn_usec, diff --git a/src/udev/udev-node.c b/src/udev/udev-node.c index c2edf2c5cd..39ae2cc1b1 100644 --- a/src/udev/udev-node.c +++ b/src/udev/udev-node.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2003-2013 Kay Sievers <kay@vrfy.org>   * diff --git a/src/udev/udev-rules.c b/src/udev/udev-rules.c index c06ace09cf..7342f2849e 100644 --- a/src/udev/udev-rules.c +++ b/src/udev/udev-rules.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2003-2012 Kay Sievers <kay@vrfy.org>   * diff --git a/src/udev/udev-watch.c b/src/udev/udev-watch.c index f1fdccaed8..60de703706 100644 --- a/src/udev/udev-watch.c +++ b/src/udev/udev-watch.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org>   * Copyright (C) 2009 Canonical Ltd. diff --git a/src/udev/udev.h b/src/udev/udev.h index 1f9c8120c0..4f4002056c 100644 --- a/src/udev/udev.h +++ b/src/udev/udev.h @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2003 Greg Kroah-Hartman <greg@kroah.com>   * Copyright (C) 2003-2010 Kay Sievers <kay@vrfy.org> diff --git a/src/udev/udevadm-control.c b/src/udev/udevadm-control.c index 989decbe95..119033c2af 100644 --- a/src/udev/udevadm-control.c +++ b/src/udev/udevadm-control.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2005-2011 Kay Sievers <kay@vrfy.org>   * diff --git a/src/udev/udevadm-hwdb.c b/src/udev/udevadm-hwdb.c index 948ad0f5a5..53f0871957 100644 --- a/src/udev/udevadm-hwdb.c +++ b/src/udev/udevadm-hwdb.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /***    This file is part of systemd. diff --git a/src/udev/udevadm-info.c b/src/udev/udevadm-info.c index 7182668f23..ca67c385b4 100644 --- a/src/udev/udevadm-info.c +++ b/src/udev/udevadm-info.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2004-2009 Kay Sievers <kay@vrfy.org>   * diff --git a/src/udev/udevadm-monitor.c b/src/udev/udevadm-monitor.c index f9cb5e63a2..1579894082 100644 --- a/src/udev/udevadm-monitor.c +++ b/src/udev/udevadm-monitor.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2004-2010 Kay Sievers <kay@vrfy.org>   * diff --git a/src/udev/udevadm-settle.c b/src/udev/udevadm-settle.c index 6a5dc6e9e4..2cc9f123bd 100644 --- a/src/udev/udevadm-settle.c +++ b/src/udev/udevadm-settle.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2006-2009 Kay Sievers <kay@vrfy.org>   * Copyright (C) 2009 Canonical Ltd. diff --git a/src/udev/udevadm-test-builtin.c b/src/udev/udevadm-test-builtin.c index 0b180d03eb..7389ca1b72 100644 --- a/src/udev/udevadm-test-builtin.c +++ b/src/udev/udevadm-test-builtin.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2011 Kay Sievers <kay@vrfy.org>   * diff --git a/src/udev/udevadm-test.c b/src/udev/udevadm-test.c index ff427cf292..00ad917efc 100644 --- a/src/udev/udevadm-test.c +++ b/src/udev/udevadm-test.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2003-2004 Greg Kroah-Hartman <greg@kroah.com>   * Copyright (C) 2004-2008 Kay Sievers <kay@vrfy.org> diff --git a/src/udev/udevadm-trigger.c b/src/udev/udevadm-trigger.c index 9d52345d92..1385b87b3a 100644 --- a/src/udev/udevadm-trigger.c +++ b/src/udev/udevadm-trigger.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2008-2009 Kay Sievers <kay@vrfy.org>   * diff --git a/src/udev/udevadm-util.c b/src/udev/udevadm-util.c index 3539c1d6ab..94cbe21f3e 100644 --- a/src/udev/udevadm-util.c +++ b/src/udev/udevadm-util.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2008-2009 Kay Sievers <kay@vrfy.org>   * diff --git a/src/udev/udevadm-util.h b/src/udev/udevadm-util.h index 37e4fe8369..5882096081 100644 --- a/src/udev/udevadm-util.h +++ b/src/udev/udevadm-util.h @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2014 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl>   * diff --git a/src/udev/udevadm.c b/src/udev/udevadm.c index 60f122ebda..af1b5a9186 100644 --- a/src/udev/udevadm.c +++ b/src/udev/udevadm.c @@ -1,4 +1,5 @@  /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2007-2012 Kay Sievers <kay@vrfy.org>   * diff --git a/src/udev/udevd.c b/src/udev/udevd.c index 8b2f5d4e30..366e7fbb87 100644 --- a/src/udev/udevd.c +++ b/src/udev/udevd.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2004-2012 Kay Sievers <kay@vrfy.org>   * Copyright (C) 2004 Chris Friesen <chris_friesen@sympatico.ca> diff --git a/src/udev/v4l_id/v4l_id.c b/src/udev/v4l_id/v4l_id.c index aec6676a33..377eb7a72c 100644 --- a/src/udev/v4l_id/v4l_id.c +++ b/src/udev/v4l_id/v4l_id.c @@ -1,3 +1,5 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ +  /*   * Copyright (C) 2009 Kay Sievers <kay@vrfy.org>   * Copyright (c) 2009 Filippo Argiolas <filippo.argiolas@gmail.com> diff --git a/src/user-sessions/user-sessions.c b/src/user-sessions/user-sessions.c index 252cbdb26c..d28b196c4e 100644 --- a/src/user-sessions/user-sessions.c +++ b/src/user-sessions/user-sessions.c @@ -23,7 +23,9 @@  #include <unistd.h>  #include "fileio.h" +#include "fileio-label.h"  #include "log.h" +#include "selinux-util.h"  #include "string-util.h"  #include "util.h" @@ -40,6 +42,8 @@ int main(int argc, char*argv[]) {          umask(0022); +        mac_selinux_init(NULL); +          if (streq(argv[1], "start")) {                  int r = 0; @@ -65,7 +69,7 @@ int main(int argc, char*argv[]) {          } else if (streq(argv[1], "stop")) {                  int r; -                r = write_string_file("/run/nologin", "System is going down.", WRITE_STRING_FILE_CREATE|WRITE_STRING_FILE_ATOMIC); +                r = write_string_file_atomic_label("/run/nologin", "System is going down.");                  if (r < 0) {                          log_error_errno(r, "Failed to create /run/nologin: %m");                          return EXIT_FAILURE; @@ -76,5 +80,7 @@ int main(int argc, char*argv[]) {                  return EXIT_FAILURE;          } +        mac_selinux_finish(); +          return EXIT_SUCCESS;  } diff --git a/test/networkd-test.py b/test/networkd-test.py new file mode 100755 index 0000000000..d76ab507d2 --- /dev/null +++ b/test/networkd-test.py @@ -0,0 +1,371 @@ +#!/usr/bin/env python3 +# +# networkd integration test +# This uses temporary configuration in /run and temporary veth devices, and +# does not write anything on disk or change any system configuration; +# but it assumes (and checks at the beginning) that networkd is not currently +# running. +# This can be run on a normal installation, in QEMU, nspawn, or LXC. +# ATTENTION: This uses the *installed* networkd, not the one from the built +# source tree. +# +# (C) 2015 Canonical Ltd. +# Author: Martin Pitt <martin.pitt@ubuntu.com> +# +# 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/>. + +import os +import sys +import time +import unittest +import tempfile +import subprocess +import shutil + +networkd_active = subprocess.call(['systemctl', 'is-active', '--quiet', +                                   'systemd-networkd']) == 0 +have_dnsmasq = shutil.which('dnsmasq') + + +@unittest.skipIf(networkd_active, +                 'networkd is already active') +class ClientTestBase: +    def setUp(self): +        self.iface = 'test_eth42' +        self.if_router = 'router_eth42' +        self.workdir_obj = tempfile.TemporaryDirectory() +        self.workdir = self.workdir_obj.name +        self.config = '/run/systemd/network/test_eth42.network' +        os.makedirs(os.path.dirname(self.config), exist_ok=True) + +        # avoid "Failed to open /dev/tty" errors in containers +        os.environ['SYSTEMD_LOG_TARGET'] = 'journal' + +        # determine path to systemd-networkd-wait-online +        for p in ['/usr/lib/systemd/systemd-networkd-wait-online', +                  '/lib/systemd/systemd-networkd-wait-online']: +            if os.path.exists(p): +                self.networkd_wait_online = p +                break +        else: +            self.fail('systemd-networkd-wait-online not found') + +        # get current journal cursor +        out = subprocess.check_output(['journalctl', '-b', '--quiet', +                                       '--no-pager', '-n0', '--show-cursor'], +                                      universal_newlines=True) +        self.assertTrue(out.startswith('-- cursor:')) +        self.journal_cursor = out.split()[-1] + +    def tearDown(self): +        self.shutdown_iface() +        if os.path.exists(self.config): +            os.unlink(self.config) +        subprocess.call(['systemctl', 'stop', 'systemd-networkd']) + +    def show_journal(self, unit): +        '''Show journal of given unit since start of the test''' + +        print('---- %s ----' % unit) +        sys.stdout.flush() +        subprocess.call(['journalctl', '-b', '--no-pager', '--quiet', +                         '--cursor', self.journal_cursor, '-u', unit]) + +    def create_iface(self, ipv6=False): +        '''Create test interface with DHCP server behind it''' + +        raise NotImplementedError('must be implemented by a subclass') + +    def shutdown_iface(self): +        '''Remove test interface and stop DHCP server''' + +        raise NotImplementedError('must be implemented by a subclass') + +    def print_server_log(self): +        '''Print DHCP server log for debugging failures''' + +        raise NotImplementedError('must be implemented by a subclass') + +    def do_test(self, coldplug=True, ipv6=False, extra_opts='', +                online_timeout=10, dhcp_mode='yes'): +        with open(self.config, 'w') as f: +            f.write('''[Match] +Name=%s +[Network] +DHCP=%s +%s''' % (self.iface, dhcp_mode, extra_opts)) + +        if coldplug: +            # create interface first, then start networkd +            self.create_iface(ipv6=ipv6) +            subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) +        else: +            # start networkd first, then create interface +            subprocess.check_call(['systemctl', 'start', 'systemd-networkd']) +            self.create_iface(ipv6=ipv6) + +        try: +            subprocess.check_call([self.networkd_wait_online, '--interface', +                                   self.iface, '--timeout=%i' % online_timeout]) + +            if ipv6: +                # check iface state and IP 6 address; FIXME: we need to wait a bit +                # longer, as the iface is "configured" already with IPv4 *or* +                # IPv6, but we want to wait for both +                for timeout in range(10): +                    out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.iface]) +                    if b'state UP' in out and b'inet6 2600' in out and b'inet 192.168' in out: +                        break +                    time.sleep(1) +                else: +                    self.fail('timed out waiting for IPv6 configuration') + +                self.assertRegex(out, b'inet6 2600::.* scope global .*dynamic') +                self.assertRegex(out, b'inet6 fe80::.* scope link') +            else: +                # should have link-local address on IPv6 only +                out = subprocess.check_output(['ip', '-6', 'a', 'show', 'dev', self.iface]) +                self.assertRegex(out, b'inet6 fe80::.* scope link') +                self.assertNotIn(b'scope global', out) + +            # should have IPv4 address +            out = subprocess.check_output(['ip', '-4', 'a', 'show', 'dev', self.iface]) +            self.assertIn(b'state UP', out) +            self.assertRegex(out, b'inet 192.168.5.\d+/.* scope global dynamic') + +            # check networkctl state +            out = subprocess.check_output(['networkctl']) +            self.assertRegex(out, ('%s\s+ether\s+routable\s+unmanaged' % self.if_router).encode()) +            self.assertRegex(out, ('%s\s+ether\s+routable\s+configured' % self.iface).encode()) + +            out = subprocess.check_output(['networkctl', 'status', self.iface]) +            self.assertRegex(out, b'Type:\s+ether') +            self.assertRegex(out, b'State:\s+routable.*configured') +            self.assertRegex(out, b'Address:\s+192.168.5.\d+') +            if ipv6: +                self.assertRegex(out, b'2600::') +            else: +                self.assertNotIn(b'2600::', out) +            self.assertRegex(out, b'fe80::') +            self.assertRegex(out, b'Gateway:\s+192.168.5.1') +            self.assertRegex(out, b'DNS:\s+192.168.5.1') +        except (AssertionError, subprocess.CalledProcessError): +            # show networkd status, journal, and DHCP server log on failure +            with open(self.config) as f: +                print('\n---- %s ----\n%s' % (self.config, f.read())) +            print('---- interface status ----') +            sys.stdout.flush() +            subprocess.call(['ip', 'a', 'show', 'dev', self.iface]) +            print('---- networkctl status %s ----' % self.iface) +            sys.stdout.flush() +            subprocess.call(['networkctl', 'status', self.iface]) +            self.show_journal('systemd-networkd.service') +            self.print_server_log() +            raise + +        # verify resolv.conf if it gets dynamically managed +        if os.path.islink('/etc/resolv.conf'): +            for timeout in range(50): +                with open('/etc/resolv.conf') as f: +                    contents = f.read() +                if 'nameserver 192.168.5.1\n' in contents: +                    break +                # resolv.conf can have at most three nameservers; if we already +                # have three different ones, that's also okay +                if contents.count('nameserver ') >= 3: +                    break +                time.sleep(0.1) +            else: +                self.fail('nameserver 192.168.5.1 not found in /etc/resolv.conf') + +        if not coldplug: +            # check post-down.d hook +            self.shutdown_iface() + +    def test_coldplug_dhcp_yes_ip4(self): +        # we have a 12s timeout on RA, so we need to wait longer +        self.do_test(coldplug=True, ipv6=False, online_timeout=15) + +    def test_coldplug_dhcp_yes_ip4_no_ra(self): +        # with disabling RA explicitly things should be fast +        self.do_test(coldplug=True, ipv6=False, +                     extra_opts='IPv6AcceptRouterAdvertisements=False') + +    def test_coldplug_dhcp_ip4_only(self): +        # we have a 12s timeout on RA, so we need to wait longer +        self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4', +                     online_timeout=15) + +    def test_coldplug_dhcp_ip4_only_no_ra(self): +        # with disabling RA explicitly things should be fast +        self.do_test(coldplug=True, ipv6=False, dhcp_mode='ipv4', +                     extra_opts='IPv6AcceptRouterAdvertisements=False') + +    def test_coldplug_dhcp_ip6(self): +        self.do_test(coldplug=True, ipv6=True) + +    def test_hotplug_dhcp_ip4(self): +        # With IPv4 only we have a 12s timeout on RA, so we need to wait longer +        self.do_test(coldplug=False, ipv6=False, online_timeout=15) + +    def test_hotplug_dhcp_ip6(self): +        self.do_test(coldplug=False, ipv6=True) + + +@unittest.skipUnless(have_dnsmasq, 'dnsmasq not installed') +class DnsmasqClientTest(ClientTestBase, unittest.TestCase): +    '''Test networkd client against dnsmasq''' + +    def setUp(self): +        super().setUp() +        self.dnsmasq = None + +    def create_iface(self, ipv6=False): +        '''Create test interface with DHCP server behind it''' + +        # add veth pair +        subprocess.check_call(['ip', 'link', 'add', 'name', self.iface, 'type', +                               'veth', 'peer', 'name', self.if_router]) + +        # give our router an IP +        subprocess.check_call(['ip', 'a', 'flush', 'dev', self.if_router]) +        subprocess.check_call(['ip', 'a', 'add', '192.168.5.1/24', 'dev', self.if_router]) +        if ipv6: +            subprocess.check_call(['ip', 'a', 'add', '2600::1/64', 'dev', self.if_router]) +        subprocess.check_call(['ip', 'link', 'set', self.if_router, 'up']) + +        # add DHCP server +        self.dnsmasq_log = os.path.join(self.workdir, 'dnsmasq.log') +        lease_file = os.path.join(self.workdir, 'dnsmasq.leases') +        if ipv6: +            extra_opts = ['--enable-ra', '--dhcp-range=2600::10,2600::20'] +        else: +            extra_opts = [] +        self.dnsmasq = subprocess.Popen( +            ['dnsmasq', '--keep-in-foreground', '--log-queries', +             '--log-facility=' + self.dnsmasq_log, '--conf-file=/dev/null', +             '--dhcp-leasefile=' + lease_file, '--bind-interfaces', +             '--interface=' + self.if_router, '--except-interface=lo', +             '--dhcp-range=192.168.5.10,192.168.5.200'] + extra_opts) + +    def shutdown_iface(self): +        '''Remove test interface and stop DHCP server''' + +        if self.if_router: +            subprocess.check_call(['ip', 'link', 'del', 'dev', self.if_router]) +            self.if_router = None +        if self.dnsmasq: +            self.dnsmasq.kill() +            self.dnsmasq.wait() +            self.dnsmasq = None + +    def print_server_log(self): +        '''Print DHCP server log for debugging failures''' + +        with open(self.dnsmasq_log) as f: +            sys.stdout.write('\n\n---- dnsmasq log ----\n%s\n------\n\n' % f.read()) + + +class NetworkdClientTest(ClientTestBase, unittest.TestCase): +    '''Test networkd client against networkd server''' + +    def setUp(self): +        super().setUp() +        self.dnsmasq = None + +    def create_iface(self, ipv6=False): +        '''Create test interface with DHCP server behind it''' + +        # run "router-side" networkd in own mount namespace to shield it from +        # "client-side" configuration and networkd +        (fd, script) = tempfile.mkstemp(prefix='networkd-router.sh') +        self.addCleanup(os.remove, script) +        with os.fdopen(fd, 'w+') as f: +            f.write('''#!/bin/sh -eu +mkdir -p /run/systemd/network +mkdir -p /run/systemd/netif +mount -t tmpfs none /run/systemd/network +mount -t tmpfs none /run/systemd/netif +[ ! -e /run/dbus ] || mount -t tmpfs none /run/dbus +# create router/client veth pair +cat << EOF > /run/systemd/network/test.netdev +[NetDev] +Name=%(ifr)s +Kind=veth + +[Peer] +Name=%(ifc)s +EOF + +cat << EOF > /run/systemd/network/test.network +[Match] +Name=%(ifr)s + +[Network] +Address=192.168.5.1/24 +%(addr6)s +DHCPServer=yes + +[DHCPServer] +PoolOffset=10 +PoolSize=50 +DNS=192.168.5.1 +EOF + +# run networkd as in systemd-networkd.service +exec $(systemctl cat systemd-networkd.service | sed -n '/^ExecStart=/ { s/^.*=//; p}') +''' % {'ifr': self.if_router, 'ifc': self.iface, 'addr6': ipv6 and 'Address=2600::1/64' or ''}) + +            os.fchmod(fd, 0o755) + +        subprocess.check_call(['systemd-run', '--unit=networkd-test-router.service', +                               '-p', 'InaccessibleDirectories=-/etc/systemd/network', +                               '-p', 'InaccessibleDirectories=-/run/systemd/network', +                               '-p', 'InaccessibleDirectories=-/run/systemd/netif', +                               '--service-type=notify', script]) + +        # wait until devices got created +        for timeout in range(50): +            out = subprocess.check_output(['ip', 'a', 'show', 'dev', self.if_router]) +            if b'state UP' in out and b'scope global' in out: +                break +            time.sleep(0.1) + +    def shutdown_iface(self): +        '''Remove test interface and stop DHCP server''' + +        if self.if_router: +            subprocess.check_call(['systemctl', 'stop', 'networkd-test-router.service']) +            # ensure failed transient unit does not stay around +            subprocess.call(['systemctl', 'reset-failed', 'networkd-test-router.service']) +            subprocess.call(['ip', 'link', 'del', 'dev', self.if_router]) +            self.if_router = None + +    def print_server_log(self): +        '''Print DHCP server log for debugging failures''' + +        self.show_journal('networkd-test-router.service') + +    @unittest.skip('networkd does not have DHCPv6 server support') +    def test_hotplug_dhcp_ip6(self): +        pass + +    @unittest.skip('networkd does not have DHCPv6 server support') +    def test_coldplug_dhcp_ip6(self): +        pass + + +if __name__ == '__main__': +    unittest.main(testRunner=unittest.TextTestRunner(stream=sys.stdout, +                                                     verbosity=2)) diff --git a/tmpfiles.d/systemd.conf.m4 b/tmpfiles.d/systemd.conf.m4 index d9d51af929..0575408dbe 100644 --- a/tmpfiles.d/systemd.conf.m4 +++ b/tmpfiles.d/systemd.conf.m4 @@ -33,9 +33,13 @@ A+ /run/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x  z /var/log/journal 2755 root systemd-journal - -  z /var/log/journal/%m 2755 root systemd-journal - - +z /var/log/journal/%m/system.journal 0640 root systemd-journal - -  m4_ifdef(`HAVE_ACL',`` +a+ /var/log/journal    - - - - d:group:adm:r-x,d:group:wheel:r-x +a+ /var/log/journal    - - - - group:adm:r-x,group:wheel:r-x  a+ /var/log/journal/%m - - - - d:group:adm:r-x,d:group:wheel:r-x  a+ /var/log/journal/%m - - - - group:adm:r-x,group:wheel:r-x +a+ /var/log/journal/%m/system.journal - - - - group:adm:r--,group:wheel:r--  '')m4_dnl  d /var/lib/systemd 0755 root root - | 
