From 3a603c87647c36c9f7d24dc727c81618ad06fca3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 5 Jul 2022 14:53:45 +0200 Subject: [PATCH] systemd: update code from upstream (2022-07-05) This is a direct dump from systemd git. $ git clean -fdx && \ git cat-file -p HEAD | sed '1,/^======$/ d' | bash - && \ git add . ====== SYSTEMD_DIR=../systemd COMMIT=87a3a4a802b9fcfd92299e2984741835ed50fef4 ( cd "$SYSTEMD_DIR" git checkout "$COMMIT" git reset --hard git clean -fdx ) git ls-files -z :/src/libnm-systemd-core/src/ \ :/src/libnm-systemd-shared/src/ \ :/src/libnm-std-aux/unaligned.h | \ xargs -0 rm -f nm_copy_sd_shared() { mkdir -p "./src/libnm-systemd-shared/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-shared/$1" } nm_copy_sd_core() { mkdir -p "./src/libnm-systemd-core/$(dirname "$1")" cp "$SYSTEMD_DIR/$1" "./src/libnm-systemd-core/$1" } nm_copy_sd_stdaux() { mkdir -p "./src/libnm-std-aux/" cp "$SYSTEMD_DIR/$1" "./src/libnm-std-aux/${1##*/}" } nm_copy_sd_core "src/libsystemd-network/arp-util.c" nm_copy_sd_core "src/libsystemd-network/arp-util.h" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.c" nm_copy_sd_core "src/libsystemd-network/dhcp-identifier.h" nm_copy_sd_core "src/libsystemd-network/dhcp-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp-protocol.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-lease-internal.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-network.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-option.h" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.c" nm_copy_sd_core "src/libsystemd-network/dhcp6-protocol.h" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.c" nm_copy_sd_core "src/libsystemd-network/lldp-neighbor.h" nm_copy_sd_core "src/libsystemd-network/lldp-network.c" nm_copy_sd_core "src/libsystemd-network/lldp-network.h" nm_copy_sd_core "src/libsystemd-network/lldp-rx-internal.h" nm_copy_sd_core "src/libsystemd-network/network-common.c" nm_copy_sd_core "src/libsystemd-network/network-common.h" nm_copy_sd_core "src/libsystemd-network/network-internal.h" nm_copy_sd_core "src/libsystemd-network/sd-dhcp-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-client.c" nm_copy_sd_core "src/libsystemd-network/sd-dhcp6-lease.c" nm_copy_sd_core "src/libsystemd-network/sd-lldp-rx.c" nm_copy_sd_core "src/libsystemd/sd-event/event-source.h" nm_copy_sd_core "src/libsystemd/sd-event/event-util.c" nm_copy_sd_core "src/libsystemd/sd-event/event-util.h" nm_copy_sd_core "src/libsystemd/sd-event/sd-event.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.c" nm_copy_sd_core "src/libsystemd/sd-id128/id128-util.h" nm_copy_sd_core "src/libsystemd/sd-id128/sd-id128.c" nm_copy_sd_core "src/systemd/_sd-common.h" nm_copy_sd_core "src/systemd/sd-dhcp6-client.h" nm_copy_sd_core "src/systemd/sd-dhcp6-lease.h" nm_copy_sd_core "src/systemd/sd-dhcp6-option.h" nm_copy_sd_core "src/systemd/sd-event.h" nm_copy_sd_core "src/systemd/sd-id128.h" nm_copy_sd_core "src/systemd/sd-lldp-rx.h" nm_copy_sd_core "src/systemd/sd-lldp.h" nm_copy_sd_core "src/systemd/sd-ndisc.h" nm_copy_sd_shared "src/basic/alloc-util.c" nm_copy_sd_shared "src/basic/alloc-util.h" nm_copy_sd_shared "src/basic/async.h" nm_copy_sd_shared "src/basic/cgroup-util.h" nm_copy_sd_shared "src/basic/dns-def.h" nm_copy_sd_shared "src/basic/env-file.c" nm_copy_sd_shared "src/basic/env-file.h" nm_copy_sd_shared "src/basic/env-util.c" nm_copy_sd_shared "src/basic/env-util.h" nm_copy_sd_shared "src/basic/errno-util.h" nm_copy_sd_shared "src/basic/escape.c" nm_copy_sd_shared "src/basic/escape.h" nm_copy_sd_shared "src/basic/ether-addr-util.c" nm_copy_sd_shared "src/basic/ether-addr-util.h" nm_copy_sd_shared "src/basic/extract-word.c" nm_copy_sd_shared "src/basic/extract-word.h" nm_copy_sd_shared "src/basic/fd-util.c" nm_copy_sd_shared "src/basic/fd-util.h" nm_copy_sd_shared "src/basic/fileio.c" nm_copy_sd_shared "src/basic/fileio.h" nm_copy_sd_shared "src/basic/format-util.c" nm_copy_sd_shared "src/basic/format-util.h" nm_copy_sd_shared "src/basic/fs-util.c" nm_copy_sd_shared "src/basic/fs-util.h" nm_copy_sd_shared "src/basic/glyph-util.c" nm_copy_sd_shared "src/basic/glyph-util.h" nm_copy_sd_shared "src/basic/hash-funcs.c" nm_copy_sd_shared "src/basic/hash-funcs.h" nm_copy_sd_shared "src/basic/hashmap.c" nm_copy_sd_shared "src/basic/hashmap.h" nm_copy_sd_shared "src/basic/hexdecoct.c" nm_copy_sd_shared "src/basic/hexdecoct.h" nm_copy_sd_shared "src/basic/hostname-util.c" nm_copy_sd_shared "src/basic/hostname-util.h" nm_copy_sd_shared "src/basic/in-addr-util.c" nm_copy_sd_shared "src/basic/in-addr-util.h" nm_copy_sd_shared "src/basic/inotify-util.c" nm_copy_sd_shared "src/basic/inotify-util.h" nm_copy_sd_shared "src/basic/io-util.c" nm_copy_sd_shared "src/basic/io-util.h" nm_copy_sd_shared "src/basic/list.h" nm_copy_sd_shared "src/basic/locale-util.c" nm_copy_sd_shared "src/basic/locale-util.h" nm_copy_sd_shared "src/basic/log.h" nm_copy_sd_shared "src/basic/macro.h" nm_copy_sd_shared "src/basic/memory-util.c" nm_copy_sd_shared "src/basic/memory-util.h" nm_copy_sd_shared "src/basic/mempool.c" nm_copy_sd_shared "src/basic/mempool.h" nm_copy_sd_shared "src/basic/missing_fcntl.h" nm_copy_sd_shared "src/basic/missing_random.h" nm_copy_sd_shared "src/basic/missing_socket.h" nm_copy_sd_shared "src/basic/missing_stat.h" nm_copy_sd_shared "src/basic/missing_syscall.h" nm_copy_sd_shared "src/basic/missing_type.h" nm_copy_sd_shared "src/basic/ordered-set.c" nm_copy_sd_shared "src/basic/ordered-set.h" nm_copy_sd_shared "src/basic/parse-util.c" nm_copy_sd_shared "src/basic/parse-util.h" nm_copy_sd_shared "src/basic/path-util.c" nm_copy_sd_shared "src/basic/path-util.h" nm_copy_sd_shared "src/basic/prioq.c" nm_copy_sd_shared "src/basic/prioq.h" nm_copy_sd_shared "src/basic/process-util.c" nm_copy_sd_shared "src/basic/process-util.h" nm_copy_sd_shared "src/basic/random-util.c" nm_copy_sd_shared "src/basic/random-util.h" nm_copy_sd_shared "src/basic/ratelimit.c" nm_copy_sd_shared "src/basic/ratelimit.h" nm_copy_sd_shared "src/basic/set.h" nm_copy_sd_shared "src/basic/signal-util.c" nm_copy_sd_shared "src/basic/signal-util.h" nm_copy_sd_shared "src/basic/siphash24.h" nm_copy_sd_shared "src/basic/socket-util.c" nm_copy_sd_shared "src/basic/socket-util.h" nm_copy_sd_shared "src/basic/sort-util.h" nm_copy_sd_shared "src/basic/sparse-endian.h" nm_copy_sd_shared "src/basic/stat-util.c" nm_copy_sd_shared "src/basic/stat-util.h" nm_copy_sd_shared "src/basic/stdio-util.h" nm_copy_sd_shared "src/basic/string-table.c" nm_copy_sd_shared "src/basic/string-table.h" nm_copy_sd_shared "src/basic/string-util.c" nm_copy_sd_shared "src/basic/string-util.h" nm_copy_sd_shared "src/basic/strv.c" nm_copy_sd_shared "src/basic/strv.h" nm_copy_sd_shared "src/basic/strxcpyx.c" nm_copy_sd_shared "src/basic/strxcpyx.h" nm_copy_sd_shared "src/basic/time-util.c" nm_copy_sd_shared "src/basic/time-util.h" nm_copy_sd_shared "src/basic/tmpfile-util.c" nm_copy_sd_shared "src/basic/tmpfile-util.h" nm_copy_sd_shared "src/basic/umask-util.h" nm_copy_sd_shared "src/basic/user-util.h" nm_copy_sd_shared "src/basic/utf8.c" nm_copy_sd_shared "src/basic/utf8.h" nm_copy_sd_shared "src/basic/util.c" nm_copy_sd_shared "src/basic/util.h" nm_copy_sd_shared "src/fundamental/macro-fundamental.h" nm_copy_sd_shared "src/fundamental/sha256.c" nm_copy_sd_shared "src/fundamental/sha256.h" nm_copy_sd_shared "src/fundamental/string-util-fundamental.c" nm_copy_sd_shared "src/fundamental/string-util-fundamental.h" nm_copy_sd_shared "src/shared/dns-domain.c" nm_copy_sd_shared "src/shared/dns-domain.h" nm_copy_sd_shared "src/shared/log-link.h" nm_copy_sd_shared "src/shared/web-util.c" nm_copy_sd_shared "src/shared/web-util.h" nm_copy_sd_stdaux "src/basic/unaligned.h" --- .../src/libsystemd-network/dhcp-identifier.c | 3 +- .../src/libsystemd-network/dhcp-option.c | 438 ----- .../src/libsystemd-network/dhcp-packet.c | 194 --- .../src/libsystemd-network/dhcp6-internal.h | 2 +- .../src/libsystemd-network/dhcp6-option.c | 16 +- .../src/libsystemd-network/lldp-neighbor.c | 6 +- .../src/libsystemd-network/network-internal.c | 241 --- .../src/libsystemd-network/sd-dhcp-lease.c | 1506 ----------------- .../src/libsystemd-network/sd-dhcp6-client.c | 97 +- .../src/libsystemd-network/sd-dhcp6-lease.c | 6 +- .../src/libsystemd-network/sd-ipv4ll.c | 380 ----- .../src/libsystemd/sd-event/event-util.c | 14 - .../src/libsystemd/sd-event/event-util.h | 5 +- .../src/libsystemd/sd-event/sd-event.c | 100 +- .../src/libsystemd/sd-id128/id128-util.c | 28 +- .../src/libsystemd/sd-id128/id128-util.h | 2 - .../src/libsystemd/sd-id128/sd-id128.c | 26 +- .../src/systemd/_sd-common.h | 2 +- .../src/systemd/sd-dhcp-client.h | 345 ---- .../src/systemd/sd-dhcp-lease.h | 91 - .../src/systemd/sd-dhcp-option.h | 38 - .../src/systemd/sd-dhcp6-client.h | 16 +- .../src/systemd/sd-dhcp6-lease.h | 2 +- .../src/systemd/sd-dhcp6-option.h | 2 +- src/libnm-systemd-core/src/systemd/sd-event.h | 2 +- src/libnm-systemd-core/src/systemd/sd-id128.h | 6 +- .../src/systemd/sd-ipv4acd.h | 63 - .../src/systemd/sd-ipv4ll.h | 65 - .../src/systemd/sd-lldp-rx.h | 6 +- src/libnm-systemd-core/src/systemd/sd-lldp.h | 14 +- src/libnm-systemd-core/src/systemd/sd-ndisc.h | 11 +- .../src/basic/alloc-util.h | 20 +- src/libnm-systemd-shared/src/basic/env-util.c | 2 +- src/libnm-systemd-shared/src/basic/fileio.c | 31 +- src/libnm-systemd-shared/src/basic/fs-util.c | 21 +- .../src/basic/glyph-util.c | 137 ++ .../src/basic/glyph-util.h | 60 + .../src/basic/hash-funcs.c | 10 +- .../src/basic/hash-funcs.h | 7 +- src/libnm-systemd-shared/src/basic/hashmap.c | 45 +- .../src/basic/hostname-util.c | 6 +- .../src/basic/in-addr-util.c | 40 +- .../src/basic/in-addr-util.h | 55 +- .../src/basic/locale-util.c | 370 ++++ .../src/basic/locale-util.h | 56 + src/libnm-systemd-shared/src/basic/log.h | 12 +- src/libnm-systemd-shared/src/basic/macro.h | 56 +- src/libnm-systemd-shared/src/basic/mempool.c | 17 - src/libnm-systemd-shared/src/basic/mempool.h | 3 +- .../src/basic/ordered-set.h | 4 + .../src/basic/parse-util.c | 32 +- .../src/basic/parse-util.h | 1 - .../src/basic/path-util.c | 118 -- .../src/basic/path-util.h | 10 - .../src/basic/process-util.c | 4 +- .../src/basic/random-util.c | 289 ++-- .../src/basic/random-util.h | 11 +- src/libnm-systemd-shared/src/basic/set.h | 11 +- .../src/basic/socket-util.c | 99 +- .../src/basic/socket-util.h | 8 +- .../src/basic/stat-util.c | 133 +- .../src/basic/stat-util.h | 43 +- .../src/basic/string-util.c | 27 + .../src/basic/string-util.h | 38 +- src/libnm-systemd-shared/src/basic/strv.c | 40 +- src/libnm-systemd-shared/src/basic/strv.h | 34 +- .../src/basic/time-util.c | 42 +- .../src/fundamental/macro-fundamental.h | 94 +- .../src/fundamental/sha256.c | 291 ++++ .../src/fundamental/sha256.h | 29 + .../src/fundamental/string-util-fundamental.c | 80 +- .../src/fundamental/string-util-fundamental.h | 70 +- .../src/fundamental/types-fundamental.h | 39 - .../src/shared/dns-domain.c | 124 +- .../src/shared/dns-domain.h | 6 +- 75 files changed, 1868 insertions(+), 4484 deletions(-) delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/network-internal.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c delete mode 100644 src/libnm-systemd-core/src/libsystemd-network/sd-ipv4ll.c delete mode 100644 src/libnm-systemd-core/src/systemd/sd-dhcp-client.h delete mode 100644 src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h delete mode 100644 src/libnm-systemd-core/src/systemd/sd-dhcp-option.h delete mode 100644 src/libnm-systemd-core/src/systemd/sd-ipv4acd.h delete mode 100644 src/libnm-systemd-core/src/systemd/sd-ipv4ll.h create mode 100644 src/libnm-systemd-shared/src/basic/glyph-util.c create mode 100644 src/libnm-systemd-shared/src/basic/glyph-util.h create mode 100644 src/libnm-systemd-shared/src/basic/locale-util.c create mode 100644 src/libnm-systemd-shared/src/basic/locale-util.h create mode 100644 src/libnm-systemd-shared/src/fundamental/sha256.c create mode 100644 src/libnm-systemd-shared/src/fundamental/sha256.h delete mode 100644 src/libnm-systemd-shared/src/fundamental/types-fundamental.h diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c index d2b190244f..326b09ac5e 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp-identifier.c @@ -11,7 +11,6 @@ #include "netif-util.h" #include "siphash24.h" #include "sparse-endian.h" -#include "stat-util.h" #include "string-table.h" #include "udev-util.h" @@ -213,7 +212,7 @@ int dhcp_identifier_set_iaid( uint64_t id; int r; - if (path_is_read_only_fs("/sys") <= 0 && !use_mac) { + if (udev_available() && !use_mac) { /* udev should be around */ r = sd_device_new_from_ifindex(&device, ifindex); diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c deleted file mode 100644 index efb676e60b..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-option.c +++ /dev/null @@ -1,438 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include -#include -#include - -#include "alloc-util.h" -#include "dhcp-internal.h" -#include "dhcp-server-internal.h" -#include "memory-util.h" -#include "strv.h" -#include "utf8.h" - -/* Append type-length value structure to the options buffer */ -static int dhcp_option_append_tlv(uint8_t options[], size_t size, size_t *offset, uint8_t code, size_t optlen, const void *optval) { - assert(options); - assert(size > 0); - assert(offset); - assert(optlen <= UINT8_MAX); - assert(*offset < size); - - if (*offset + 2 + optlen > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = optlen; - - memcpy_safe(&options[*offset + 2], optval, optlen); - *offset += 2 + optlen; - return 0; -} - -static int option_append(uint8_t options[], size_t size, size_t *offset, - uint8_t code, size_t optlen, const void *optval) { - assert(options); - assert(size > 0); - assert(offset); - - int r; - - if (code != SD_DHCP_OPTION_END) - /* always make sure there is space for an END option */ - size--; - - switch (code) { - - case SD_DHCP_OPTION_PAD: - case SD_DHCP_OPTION_END: - if (*offset + 1 > size) - return -ENOBUFS; - - options[*offset] = code; - *offset += 1; - break; - - case SD_DHCP_OPTION_USER_CLASS: { - size_t total = 0; - - if (strv_isempty((char **) optval)) - return -EINVAL; - - STRV_FOREACH(s, (char **) optval) { - size_t len = strlen(*s); - - if (len > 255 || len == 0) - return -EINVAL; - - total += 1 + len; - } - - if (*offset + 2 + total > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = total; - *offset += 2; - - STRV_FOREACH(s, (char **) optval) { - size_t len = strlen(*s); - - options[*offset] = len; - memcpy(&options[*offset + 1], *s, len); - *offset += 1 + len; - } - - break; - } - case SD_DHCP_OPTION_SIP_SERVER: - if (*offset + 3 + optlen > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = optlen + 1; - options[*offset + 2] = 1; - - memcpy_safe(&options[*offset + 3], optval, optlen); - *offset += 3 + optlen; - - break; - case SD_DHCP_OPTION_VENDOR_SPECIFIC: { - OrderedSet *s = (OrderedSet *) optval; - struct sd_dhcp_option *p; - size_t l = 0; - - ORDERED_SET_FOREACH(p, s) - l += p->length + 2; - - if (*offset + l + 2 > size) - return -ENOBUFS; - - options[*offset] = code; - options[*offset + 1] = l; - *offset += 2; - - ORDERED_SET_FOREACH(p, s) { - r = dhcp_option_append_tlv(options, size, offset, p->option, p->length, p->data); - if (r < 0) - return r; - } - break; - } - case SD_DHCP_OPTION_RELAY_AGENT_INFORMATION: { - sd_dhcp_server *server = (sd_dhcp_server *) optval; - size_t current_offset = *offset + 2; - - if (server->agent_circuit_id) { - r = dhcp_option_append_tlv(options, size, ¤t_offset, SD_DHCP_RELAY_AGENT_CIRCUIT_ID, - strlen(server->agent_circuit_id), server->agent_circuit_id); - if (r < 0) - return r; - } - if (server->agent_remote_id) { - r = dhcp_option_append_tlv(options, size, ¤t_offset, SD_DHCP_RELAY_AGENT_REMOTE_ID, - strlen(server->agent_remote_id), server->agent_remote_id); - if (r < 0) - return r; - } - - options[*offset] = code; - options[*offset + 1] = current_offset - *offset - 2; - assert(current_offset - *offset - 2 <= UINT8_MAX); - *offset = current_offset; - break; - } - default: - return dhcp_option_append_tlv(options, size, offset, code, optlen, optval); - } - return 0; -} - -static int option_length(uint8_t *options, size_t length, size_t offset) { - assert(options); - assert(offset < length); - - if (IN_SET(options[offset], SD_DHCP_OPTION_PAD, SD_DHCP_OPTION_END)) - return 1; - if (length < offset + 2) - return -ENOBUFS; - - /* validating that buffer is long enough */ - if (length < offset + 2 + options[offset + 1]) - return -ENOBUFS; - - return options[offset + 1] + 2; -} - -int dhcp_option_find_option(uint8_t *options, size_t length, uint8_t code, size_t *ret_offset) { - int r; - - assert(options); - assert(ret_offset); - - for (size_t offset = 0; offset < length; offset += r) { - r = option_length(options, length, offset); - if (r < 0) - return r; - - if (code == options[offset]) { - *ret_offset = offset; - return r; - } - } - return -ENOENT; -} - -int dhcp_option_remove_option(uint8_t *options, size_t length, uint8_t option_code) { - int r; - size_t offset; - - assert(options); - - r = dhcp_option_find_option(options, length, option_code, &offset); - if (r < 0) - return r; - - memmove(options + offset, options + offset + r, length - offset - r); - return length - r; -} - -int dhcp_option_append(DHCPMessage *message, size_t size, size_t *offset, - uint8_t overload, - uint8_t code, size_t optlen, const void *optval) { - const bool use_file = overload & DHCP_OVERLOAD_FILE; - const bool use_sname = overload & DHCP_OVERLOAD_SNAME; - int r; - - assert(message); - assert(offset); - - /* If *offset is in range [0, size), we are writing to ->options, - * if *offset is in range [size, size + sizeof(message->file)) and use_file, we are writing to ->file, - * if *offset is in range [size + use_file*sizeof(message->file), size + use_file*sizeof(message->file) + sizeof(message->sname)) - * and use_sname, we are writing to ->sname. - */ - - if (*offset < size) { - /* still space in the options array */ - r = option_append(message->options, size, offset, code, optlen, optval); - if (r >= 0) - return 0; - else if (r == -ENOBUFS && (use_file || use_sname)) { - /* did not fit, but we have more buffers to try - close the options array and move the offset to its end */ - r = option_append(message->options, size, offset, SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - *offset = size; - } else - return r; - } - - if (use_file) { - size_t file_offset = *offset - size; - - if (file_offset < sizeof(message->file)) { - /* still space in the 'file' array */ - r = option_append(message->file, sizeof(message->file), &file_offset, code, optlen, optval); - if (r >= 0) { - *offset = size + file_offset; - return 0; - } else if (r == -ENOBUFS && use_sname) { - /* did not fit, but we have more buffers to try - close the file array and move the offset to its end */ - r = option_append(message->file, sizeof(message->file), &file_offset, SD_DHCP_OPTION_END, 0, NULL); - if (r < 0) - return r; - - *offset = size + sizeof(message->file); - } else - return r; - } - } - - if (use_sname) { - size_t sname_offset = *offset - size - use_file*sizeof(message->file); - - if (sname_offset < sizeof(message->sname)) { - /* still space in the 'sname' array */ - r = option_append(message->sname, sizeof(message->sname), &sname_offset, code, optlen, optval); - if (r >= 0) { - *offset = size + use_file*sizeof(message->file) + sname_offset; - return 0; - } else - /* no space, or other error, give up */ - return r; - } - } - - return -ENOBUFS; -} - -static int parse_options(const uint8_t options[], size_t buflen, uint8_t *overload, - uint8_t *message_type, char **error_message, dhcp_option_callback_t cb, - void *userdata) { - uint8_t code, len; - const uint8_t *option; - size_t offset = 0; - - while (offset < buflen) { - code = options[offset ++]; - - switch (code) { - case SD_DHCP_OPTION_PAD: - continue; - - case SD_DHCP_OPTION_END: - return 0; - } - - if (buflen < offset + 1) - return -ENOBUFS; - - len = options[offset ++]; - - if (buflen < offset + len) - return -EINVAL; - - option = &options[offset]; - - switch (code) { - case SD_DHCP_OPTION_MESSAGE_TYPE: - if (len != 1) - return -EINVAL; - - if (message_type) - *message_type = *option; - - break; - - case SD_DHCP_OPTION_ERROR_MESSAGE: - if (len == 0) - return -EINVAL; - - if (error_message) { - _cleanup_free_ char *string = NULL; - - /* Accept a trailing NUL byte */ - if (memchr(option, 0, len - 1)) - return -EINVAL; - - string = memdup_suffix0((const char *) option, len); - if (!string) - return -ENOMEM; - - if (!ascii_is_valid(string)) - return -EINVAL; - - free_and_replace(*error_message, string); - } - - break; - case SD_DHCP_OPTION_OVERLOAD: - if (len != 1) - return -EINVAL; - - if (overload) - *overload = *option; - - break; - - default: - if (cb) - cb(code, len, option, userdata); - - break; - } - - offset += len; - } - - if (offset < buflen) - return -EINVAL; - - return 0; -} - -int dhcp_option_parse(DHCPMessage *message, size_t len, dhcp_option_callback_t cb, void *userdata, char **_error_message) { - _cleanup_free_ char *error_message = NULL; - uint8_t overload = 0; - uint8_t message_type = 0; - int r; - - if (!message) - return -EINVAL; - - if (len < sizeof(DHCPMessage)) - return -EINVAL; - - len -= sizeof(DHCPMessage); - - r = parse_options(message->options, len, &overload, &message_type, &error_message, cb, userdata); - if (r < 0) - return r; - - if (overload & DHCP_OVERLOAD_FILE) { - r = parse_options(message->file, sizeof(message->file), NULL, &message_type, &error_message, cb, userdata); - if (r < 0) - return r; - } - - if (overload & DHCP_OVERLOAD_SNAME) { - r = parse_options(message->sname, sizeof(message->sname), NULL, &message_type, &error_message, cb, userdata); - if (r < 0) - return r; - } - - if (message_type == 0) - return -ENOMSG; - - if (_error_message && IN_SET(message_type, DHCP_NAK, DHCP_DECLINE)) - *_error_message = TAKE_PTR(error_message); - - return message_type; -} - -static sd_dhcp_option* dhcp_option_free(sd_dhcp_option *i) { - if (!i) - return NULL; - - free(i->data); - return mfree(i); -} - -int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret) { - assert_return(ret, -EINVAL); - assert_return(length == 0 || data, -EINVAL); - - _cleanup_free_ void *q = memdup(data, length); - if (!q) - return -ENOMEM; - - sd_dhcp_option *p = new(sd_dhcp_option, 1); - if (!p) - return -ENOMEM; - - *p = (sd_dhcp_option) { - .n_ref = 1, - .option = option, - .length = length, - .data = TAKE_PTR(q), - }; - - *ret = TAKE_PTR(p); - return 0; -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_option, sd_dhcp_option, dhcp_option_free); -DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR( - dhcp_option_hash_ops, - void, - trivial_hash_func, - trivial_compare_func, - sd_dhcp_option, - sd_dhcp_option_unref); diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c deleted file mode 100644 index d1a1cf57f3..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp-packet.c +++ /dev/null @@ -1,194 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include -#include -#include -#include - -#include "dhcp-internal.h" -#include "dhcp-protocol.h" -#include "memory-util.h" - -#define DHCP_CLIENT_MIN_OPTIONS_SIZE 312 - -int dhcp_message_init( - DHCPMessage *message, - uint8_t op, - uint32_t xid, - uint8_t type, - uint16_t arp_type, - uint8_t hlen, - const uint8_t *chaddr, - size_t optlen, - size_t *optoffset) { - - size_t offset = 0; - int r; - - assert(IN_SET(op, BOOTREQUEST, BOOTREPLY)); - assert(chaddr || hlen == 0); - - message->op = op; - message->htype = arp_type; - - /* RFC2131 section 4.1.1: - The client MUST include its hardware address in the ’chaddr’ field, if - necessary for delivery of DHCP reply messages. - - RFC 4390 section 2.1: - A DHCP client, when working over an IPoIB interface, MUST follow the - following rules: - "htype" (hardware address type) MUST be 32 [ARPPARAM]. - "hlen" (hardware address length) MUST be 0. - "chaddr" (client hardware address) field MUST be zeroed. - */ - message->hlen = (arp_type == ARPHRD_INFINIBAND) ? 0 : hlen; - memcpy_safe(message->chaddr, chaddr, message->hlen); - - message->xid = htobe32(xid); - message->magic = htobe32(DHCP_MAGIC_COOKIE); - - r = dhcp_option_append(message, optlen, &offset, 0, - SD_DHCP_OPTION_MESSAGE_TYPE, 1, &type); - if (r < 0) - return r; - - *optoffset = offset; - - return 0; -} - -uint16_t dhcp_packet_checksum(uint8_t *buf, size_t len) { - uint64_t *buf_64 = (uint64_t*)buf; - uint64_t *end_64 = buf_64 + (len / sizeof(uint64_t)); - uint64_t sum = 0; - - /* See RFC1071 */ - - while (buf_64 < end_64) { - sum += *buf_64; - if (sum < *buf_64) - /* wrap around in one's complement */ - sum++; - - buf_64++; - } - - if (len % sizeof(uint64_t)) { - /* If the buffer is not aligned to 64-bit, we need - to zero-pad the last few bytes and add them in */ - uint64_t buf_tail = 0; - - memcpy(&buf_tail, buf_64, len % sizeof(uint64_t)); - - sum += buf_tail; - if (sum < buf_tail) - /* wrap around */ - sum++; - } - - while (sum >> 16) - sum = (sum & 0xffff) + (sum >> 16); - - return ~sum; -} - -void dhcp_packet_append_ip_headers(DHCPPacket *packet, be32_t source_addr, - uint16_t source_port, be32_t destination_addr, - uint16_t destination_port, uint16_t len, int ip_service_type) { - packet->ip.version = IPVERSION; - packet->ip.ihl = DHCP_IP_SIZE / 4; - packet->ip.tot_len = htobe16(len); - - if (ip_service_type >= 0) - packet->ip.tos = ip_service_type; - else - packet->ip.tos = IPTOS_CLASS_CS6; - - packet->ip.protocol = IPPROTO_UDP; - packet->ip.saddr = source_addr; - packet->ip.daddr = destination_addr; - - packet->udp.source = htobe16(source_port); - packet->udp.dest = htobe16(destination_port); - - packet->udp.len = htobe16(len - DHCP_IP_SIZE); - - packet->ip.check = packet->udp.len; - packet->udp.check = dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, len - 8); - - packet->ip.ttl = IPDEFTTL; - packet->ip.check = 0; - packet->ip.check = dhcp_packet_checksum((uint8_t*)&packet->ip, DHCP_IP_SIZE); -} - -int dhcp_packet_verify_headers(DHCPPacket *packet, size_t len, bool checksum, uint16_t port) { - size_t hdrlen; - - assert(packet); - - /* IP */ - - if (packet->ip.version != IPVERSION) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: not IPv4"); - - if (packet->ip.ihl < 5) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: IPv4 IHL (%u words) invalid", - packet->ip.ihl); - - hdrlen = packet->ip.ihl * 4; - if (hdrlen < 20) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: IPv4 IHL (%zu bytes) " - "smaller than minimum (20 bytes)", - hdrlen); - - if (len < hdrlen) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by IP header", - len, hdrlen); - - /* UDP */ - - if (packet->ip.protocol != IPPROTO_UDP) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: not UDP"); - - if (len < hdrlen + be16toh(packet->udp.len)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: packet (%zu bytes) " - "smaller than expected (%zu) by UDP header", - len, hdrlen + be16toh(packet->udp.len)); - - if (be16toh(packet->udp.dest) != port) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: to port %u, which " - "is not the DHCP client port (%u)", - be16toh(packet->udp.dest), port); - - /* checksums - computing these is relatively expensive, so only do it - if all the other checks have passed - */ - - if (dhcp_packet_checksum((uint8_t*)&packet->ip, hdrlen)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: invalid IP checksum"); - - if (checksum && packet->udp.check) { - packet->ip.check = packet->udp.len; - packet->ip.ttl = 0; - - if (dhcp_packet_checksum((uint8_t*)&packet->ip.ttl, - be16toh(packet->udp.len) + 12)) - return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), - "ignoring packet: invalid UDP checksum"); - } - - return 0; -} diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h index 0d7813f613..176391ebec 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-internal.h @@ -64,7 +64,7 @@ struct sd_dhcp6_client { struct duid duid; size_t duid_len; be16_t *req_opts; - size_t req_opts_len; + size_t n_req_opts; char *fqdn; char *mudurl; char **user_class; diff --git a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c index eccfbe8b65..63d3f60513 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c +++ b/src/libnm-systemd-core/src/libsystemd-network/dhcp6-option.c @@ -51,18 +51,20 @@ bool dhcp6_option_can_request(uint16_t option) { return false; case SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME: case SD_DHCP6_OPTION_SIP_SERVER_ADDRESS: - case SD_DHCP6_OPTION_DNS_SERVERS: - case SD_DHCP6_OPTION_DOMAIN_LIST: + case SD_DHCP6_OPTION_DNS_SERVER: + case SD_DHCP6_OPTION_DOMAIN: return true; case SD_DHCP6_OPTION_IA_PD: case SD_DHCP6_OPTION_IA_PD_PREFIX: return false; - case SD_DHCP6_OPTION_NIS_SERVERS: - case SD_DHCP6_OPTION_NISP_SERVERS: + case SD_DHCP6_OPTION_NIS_SERVER: + case SD_DHCP6_OPTION_NISP_SERVER: case SD_DHCP6_OPTION_NIS_DOMAIN_NAME: case SD_DHCP6_OPTION_NISP_DOMAIN_NAME: - case SD_DHCP6_OPTION_SNTP_SERVERS: + case SD_DHCP6_OPTION_SNTP_SERVER: + return true; case SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME: + return false; /* This is automatically set when sending INFORMATION_REQUEST message. */ case SD_DHCP6_OPTION_BCMCS_SERVER_D: case SD_DHCP6_OPTION_BCMCS_SERVER_A: case SD_DHCP6_OPTION_GEOCONF_CIVIC: @@ -124,9 +126,9 @@ bool dhcp6_option_can_request(uint16_t option) { case SD_DHCP6_OPTION_CLIENT_LINKLAYER_ADDR: case SD_DHCP6_OPTION_LINK_ADDRESS: case SD_DHCP6_OPTION_RADIUS: + case SD_DHCP6_OPTION_SOL_MAX_RT: /* Automatically set when sending SOLICIT message. */ + case SD_DHCP6_OPTION_INF_MAX_RT: /* Automatically set when sending INFORMATION_REQUEST message. */ return false; - case SD_DHCP6_OPTION_SOL_MAX_RT: - case SD_DHCP6_OPTION_INF_MAX_RT: case SD_DHCP6_OPTION_ADDRSEL: case SD_DHCP6_OPTION_ADDRSEL_TABLE: case SD_DHCP6_OPTION_V6_PCP_SERVER: diff --git a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c index b056019989..6672409d75 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c +++ b/src/libnm-systemd-core/src/libsystemd-network/lldp-neighbor.c @@ -116,6 +116,9 @@ sd_lldp_neighbor *lldp_neighbor_unlink(sd_lldp_neighbor *n) { sd_lldp_neighbor *lldp_neighbor_new(size_t raw_size) { sd_lldp_neighbor *n; + if (raw_size > SIZE_MAX - ALIGN(sizeof(sd_lldp_neighbor))) + return NULL; + n = malloc0(ALIGN(sizeof(sd_lldp_neighbor)) + raw_size); if (!n) return NULL; @@ -649,7 +652,8 @@ int sd_lldp_neighbor_from_raw(sd_lldp_neighbor **ret, const void *raw, size_t ra if (!n) return -ENOMEM; - memcpy(LLDP_NEIGHBOR_RAW(n), raw, raw_size); + memcpy_safe(LLDP_NEIGHBOR_RAW(n), raw, raw_size); + r = lldp_neighbor_parse(n); if (r < 0) return r; diff --git a/src/libnm-systemd-core/src/libsystemd-network/network-internal.c b/src/libnm-systemd-core/src/libsystemd-network/network-internal.c deleted file mode 100644 index bc7aec2f9d..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/network-internal.c +++ /dev/null @@ -1,241 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ - -#include -#include -#include - -#include "sd-ndisc.h" - -#include "alloc-util.h" -#include "dhcp-lease-internal.h" -#include "extract-word.h" -#include "hexdecoct.h" -#include "log.h" -#include "network-internal.h" -#include "parse-util.h" - -size_t serialize_in_addrs(FILE *f, - const struct in_addr *addresses, - size_t size, - bool *with_leading_space, - bool (*predicate)(const struct in_addr *addr)) { - assert(f); - assert(addresses); - - size_t count = 0; - bool _space = false; - if (!with_leading_space) - with_leading_space = &_space; - - for (size_t i = 0; i < size; i++) { - char sbuf[INET_ADDRSTRLEN]; - - if (predicate && !predicate(&addresses[i])) - continue; - - if (*with_leading_space) - fputc(' ', f); - fputs(inet_ntop(AF_INET, &addresses[i], sbuf, sizeof(sbuf)), f); - count++; - *with_leading_space = true; - } - - return count; -} - -int deserialize_in_addrs(struct in_addr **ret, const char *string) { - _cleanup_free_ struct in_addr *addresses = NULL; - int size = 0; - - assert(ret); - assert(string); - - for (;;) { - _cleanup_free_ char *word = NULL; - struct in_addr *new_addresses; - int r; - - r = extract_first_word(&string, &word, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - new_addresses = reallocarray(addresses, size + 1, sizeof(struct in_addr)); - if (!new_addresses) - return -ENOMEM; - else - addresses = new_addresses; - - r = inet_pton(AF_INET, word, &(addresses[size])); - if (r <= 0) - continue; - - size++; - } - - *ret = size > 0 ? TAKE_PTR(addresses) : NULL; - - return size; -} - -void serialize_in6_addrs(FILE *f, const struct in6_addr *addresses, size_t size, bool *with_leading_space) { - assert(f); - assert(addresses); - assert(size); - - bool _space = false; - if (!with_leading_space) - with_leading_space = &_space; - - for (size_t i = 0; i < size; i++) { - char buffer[INET6_ADDRSTRLEN]; - - if (*with_leading_space) - fputc(' ', f); - fputs(inet_ntop(AF_INET6, addresses+i, buffer, sizeof(buffer)), f); - *with_leading_space = true; - } -} - -int deserialize_in6_addrs(struct in6_addr **ret, const char *string) { - _cleanup_free_ struct in6_addr *addresses = NULL; - int size = 0; - - assert(ret); - assert(string); - - for (;;) { - _cleanup_free_ char *word = NULL; - struct in6_addr *new_addresses; - int r; - - r = extract_first_word(&string, &word, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - new_addresses = reallocarray(addresses, size + 1, sizeof(struct in6_addr)); - if (!new_addresses) - return -ENOMEM; - else - addresses = new_addresses; - - r = inet_pton(AF_INET6, word, &(addresses[size])); - if (r <= 0) - continue; - - size++; - } - - *ret = TAKE_PTR(addresses); - - return size; -} - -void serialize_dhcp_routes(FILE *f, const char *key, sd_dhcp_route **routes, size_t size) { - assert(f); - assert(key); - assert(routes); - assert(size); - - fprintf(f, "%s=", key); - - for (size_t i = 0; i < size; i++) { - char sbuf[INET_ADDRSTRLEN]; - struct in_addr dest, gw; - uint8_t length; - - assert_se(sd_dhcp_route_get_destination(routes[i], &dest) >= 0); - assert_se(sd_dhcp_route_get_gateway(routes[i], &gw) >= 0); - assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &length) >= 0); - - fprintf(f, "%s/%" PRIu8, inet_ntop(AF_INET, &dest, sbuf, sizeof sbuf), length); - fprintf(f, ",%s%s", inet_ntop(AF_INET, &gw, sbuf, sizeof sbuf), i < size - 1 ? " ": ""); - } - - fputs("\n", f); -} - -int deserialize_dhcp_routes(struct sd_dhcp_route **ret, size_t *ret_size, const char *string) { - _cleanup_free_ struct sd_dhcp_route *routes = NULL; - size_t size = 0; - - assert(ret); - assert(ret_size); - assert(string); - - /* WORD FORMAT: dst_ip/dst_prefixlen,gw_ip */ - for (;;) { - _cleanup_free_ char *word = NULL; - char *tok, *tok_end; - unsigned n; - int r; - - r = extract_first_word(&string, &word, NULL, 0); - if (r < 0) - return r; - if (r == 0) - break; - - if (!GREEDY_REALLOC(routes, size + 1)) - return -ENOMEM; - - tok = word; - - /* get the subnet */ - tok_end = strchr(tok, '/'); - if (!tok_end) - continue; - *tok_end = '\0'; - - r = inet_aton(tok, &routes[size].dst_addr); - if (r == 0) - continue; - - tok = tok_end + 1; - - /* get the prefixlen */ - tok_end = strchr(tok, ','); - if (!tok_end) - continue; - - *tok_end = '\0'; - - r = safe_atou(tok, &n); - if (r < 0 || n > 32) - continue; - - routes[size].dst_prefixlen = (uint8_t) n; - tok = tok_end + 1; - - /* get the gateway */ - r = inet_aton(tok, &routes[size].gw_addr); - if (r == 0) - continue; - - size++; - } - - *ret_size = size; - *ret = TAKE_PTR(routes); - - return 0; -} - -int serialize_dhcp_option(FILE *f, const char *key, const void *data, size_t size) { - _cleanup_free_ char *hex_buf = NULL; - - assert(f); - assert(key); - assert(data); - - hex_buf = hexmem(data, size); - if (!hex_buf) - return -ENOMEM; - - fprintf(f, "%s=%s\n", key, hex_buf); - - return 0; -} diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c deleted file mode 100644 index 8de7c671df..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp-lease.c +++ /dev/null @@ -1,1506 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2013 Intel Corporation. All rights reserved. -***/ - -#include -#include -#include -#include -#include -#include - -#include "sd-dhcp-lease.h" - -#include "alloc-util.h" -#include "dhcp-lease-internal.h" -#include "dhcp-protocol.h" -#include "dns-domain.h" -#include "env-file.h" -#include "fd-util.h" -#include "fileio.h" -#include "fs-util.h" -#include "hexdecoct.h" -#include "hostname-util.h" -#include "in-addr-util.h" -#include "network-internal.h" -#include "parse-util.h" -#include "stdio-util.h" -#include "string-util.h" -#include "strv.h" -#include "tmpfile-util.h" -#include "unaligned.h" - -int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->address == 0) - return -ENODATA; - - addr->s_addr = lease->address; - return 0; -} - -int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (!lease->have_broadcast) - return -ENODATA; - - addr->s_addr = lease->broadcast; - return 0; -} - -int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime) { - assert_return(lease, -EINVAL); - assert_return(lifetime, -EINVAL); - - if (lease->lifetime <= 0) - return -ENODATA; - - *lifetime = lease->lifetime; - return 0; -} - -int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1) { - assert_return(lease, -EINVAL); - assert_return(t1, -EINVAL); - - if (lease->t1 <= 0) - return -ENODATA; - - *t1 = lease->t1; - return 0; -} - -int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2) { - assert_return(lease, -EINVAL); - assert_return(t2, -EINVAL); - - if (lease->t2 <= 0) - return -ENODATA; - - *t2 = lease->t2; - return 0; -} - -int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu) { - assert_return(lease, -EINVAL); - assert_return(mtu, -EINVAL); - - if (lease->mtu <= 0) - return -ENODATA; - - *mtu = lease->mtu; - return 0; -} - -int sd_dhcp_lease_get_servers( - sd_dhcp_lease *lease, - sd_dhcp_lease_server_type_t what, - const struct in_addr **addr) { - - assert_return(lease, -EINVAL); - assert_return(what >= 0, -EINVAL); - assert_return(what < _SD_DHCP_LEASE_SERVER_TYPE_MAX, -EINVAL); - - if (lease->servers[what].size <= 0) - return -ENODATA; - - if (addr) - *addr = lease->servers[what].addr; - - return (int) lease->servers[what].size; -} - -int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_DNS, addr); -} -int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_NTP, addr); -} -int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SIP, addr); -} -int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_POP3, addr); -} -int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_SMTP, addr); -} -int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr) { - return sd_dhcp_lease_get_servers(lease, SD_DHCP_LEASE_LPR, addr); -} - -int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname) { - assert_return(lease, -EINVAL); - assert_return(domainname, -EINVAL); - - if (!lease->domainname) - return -ENODATA; - - *domainname = lease->domainname; - return 0; -} - -int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname) { - assert_return(lease, -EINVAL); - assert_return(hostname, -EINVAL); - - if (!lease->hostname) - return -ENODATA; - - *hostname = lease->hostname; - return 0; -} - -int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path) { - assert_return(lease, -EINVAL); - assert_return(root_path, -EINVAL); - - if (!lease->root_path) - return -ENODATA; - - *root_path = lease->root_path; - return 0; -} - -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->router_size <= 0) - return -ENODATA; - - *addr = lease->router; - return (int) lease->router_size; -} - -int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (!lease->have_subnet_mask) - return -ENODATA; - - addr->s_addr = lease->subnet_mask; - return 0; -} - -int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->server_address == 0) - return -ENODATA; - - addr->s_addr = lease->server_address; - return 0; -} - -int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr) { - assert_return(lease, -EINVAL); - assert_return(addr, -EINVAL); - - if (lease->next_server == 0) - return -ENODATA; - - addr->s_addr = lease->next_server; - return 0; -} - -/* - * The returned routes array must be freed by the caller. - * Route objects have the same lifetime of the lease and must not be freed. - */ -static int dhcp_lease_get_routes(sd_dhcp_route *routes, size_t n_routes, sd_dhcp_route ***ret) { - assert(routes || n_routes == 0); - - if (n_routes <= 0) - return -ENODATA; - - if (ret) { - sd_dhcp_route **buf; - - buf = new(sd_dhcp_route*, n_routes); - if (!buf) - return -ENOMEM; - - for (size_t i = 0; i < n_routes; i++) - buf[i] = &routes[i]; - - *ret = buf; - } - - return (int) n_routes; -} - -int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret) { - assert_return(lease, -EINVAL); - - return dhcp_lease_get_routes(lease->static_routes, lease->n_static_routes, ret); -} - -int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret) { - assert_return(lease, -EINVAL); - - return dhcp_lease_get_routes(lease->classless_routes, lease->n_classless_routes, ret); -} - -int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains) { - size_t r; - - assert_return(lease, -EINVAL); - assert_return(domains, -EINVAL); - - r = strv_length(lease->search_domains); - if (r > 0) { - *domains = lease->search_domains; - return (int) r; - } - - return -ENODATA; -} - -int sd_dhcp_lease_get_6rd( - sd_dhcp_lease *lease, - uint8_t *ret_ipv4masklen, - uint8_t *ret_prefixlen, - struct in6_addr *ret_prefix, - const struct in_addr **ret_br_addresses, - size_t *ret_n_br_addresses) { - - assert_return(lease, -EINVAL); - - if (lease->sixrd_n_br_addresses <= 0) - return -ENODATA; - - if (ret_ipv4masklen) - *ret_ipv4masklen = lease->sixrd_ipv4masklen; - if (ret_prefixlen) - *ret_prefixlen = lease->sixrd_prefixlen; - if (ret_prefix) - *ret_prefix = lease->sixrd_prefix; - if (ret_br_addresses) - *ret_br_addresses = lease->sixrd_br_addresses; - if (ret_n_br_addresses) - *ret_n_br_addresses = lease->sixrd_n_br_addresses; - - return 0; -} - -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len) { - assert_return(lease, -EINVAL); - assert_return(data, -EINVAL); - assert_return(data_len, -EINVAL); - - if (lease->vendor_specific_len <= 0) - return -ENODATA; - - *data = lease->vendor_specific; - *data_len = lease->vendor_specific_len; - return 0; -} - -static sd_dhcp_lease *dhcp_lease_free(sd_dhcp_lease *lease) { - assert(lease); - - while (lease->private_options) { - struct sd_dhcp_raw_option *option = lease->private_options; - - LIST_REMOVE(options, lease->private_options, option); - - free(option->data); - free(option); - } - - free(lease->root_path); - free(lease->router); - free(lease->timezone); - free(lease->hostname); - free(lease->domainname); - - for (sd_dhcp_lease_server_type_t i = 0; i < _SD_DHCP_LEASE_SERVER_TYPE_MAX; i++) - free(lease->servers[i].addr); - - free(lease->static_routes); - free(lease->classless_routes); - free(lease->client_id); - free(lease->vendor_specific); - strv_free(lease->search_domains); - free(lease->sixrd_br_addresses); - return mfree(lease); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp_lease, sd_dhcp_lease, dhcp_lease_free); - -static int lease_parse_u32(const uint8_t *option, size_t len, uint32_t *ret, uint32_t min) { - assert(option); - assert(ret); - - if (len != 4) - return -EINVAL; - - *ret = unaligned_read_be32((be32_t*) option); - if (*ret < min) - *ret = min; - - return 0; -} - -static int lease_parse_u16(const uint8_t *option, size_t len, uint16_t *ret, uint16_t min) { - assert(option); - assert(ret); - - if (len != 2) - return -EINVAL; - - *ret = unaligned_read_be16((be16_t*) option); - if (*ret < min) - *ret = min; - - return 0; -} - -static int lease_parse_be32(const uint8_t *option, size_t len, be32_t *ret) { - assert(option); - assert(ret); - - if (len != 4) - return -EINVAL; - - memcpy(ret, option, 4); - return 0; -} - -static int lease_parse_string(const uint8_t *option, size_t len, char **ret) { - assert(option); - assert(ret); - - if (len <= 0) - *ret = mfree(*ret); - else { - char *string; - - /* - * One trailing NUL byte is OK, we don't mind. See: - * https://github.com/systemd/systemd/issues/1337 - */ - if (memchr(option, 0, len - 1)) - return -EINVAL; - - string = memdup_suffix0((const char *) option, len); - if (!string) - return -ENOMEM; - - free_and_replace(*ret, string); - } - - return 0; -} - -static int lease_parse_domain(const uint8_t *option, size_t len, char **ret) { - _cleanup_free_ char *name = NULL, *normalized = NULL; - int r; - - assert(option); - assert(ret); - - r = lease_parse_string(option, len, &name); - if (r < 0) - return r; - if (!name) { - *ret = mfree(*ret); - return 0; - } - - r = dns_name_normalize(name, 0, &normalized); - if (r < 0) - return r; - - if (is_localhost(normalized)) - return -EINVAL; - - if (dns_name_is_root(normalized)) - return -EINVAL; - - free_and_replace(*ret, normalized); - - return 0; -} - -static int lease_parse_in_addrs(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { - assert(option || len == 0); - assert(ret); - assert(n_ret); - - if (len <= 0) { - *ret = mfree(*ret); - *n_ret = 0; - } else { - size_t n_addresses; - struct in_addr *addresses; - - if (len % 4 != 0) - return -EINVAL; - - n_addresses = len / 4; - - addresses = newdup(struct in_addr, option, n_addresses); - if (!addresses) - return -ENOMEM; - - free(*ret); - *ret = addresses; - *n_ret = n_addresses; - } - - return 0; -} - -static int lease_parse_sip_server(const uint8_t *option, size_t len, struct in_addr **ret, size_t *n_ret) { - assert(option || len == 0); - assert(ret); - assert(n_ret); - - if (len <= 0) - return -EINVAL; - - /* The SIP record is like the other, regular server records, but prefixed with a single "encoding" - * byte that is either 0 or 1. We only support it to be 1 for now. Let's drop it and parse it like - * the other fields */ - - if (option[0] != 1) { /* We only support IP address encoding for now */ - *ret = mfree(*ret); - *n_ret = 0; - return 0; - } - - return lease_parse_in_addrs(option + 1, len - 1, ret, n_ret); -} - -static int lease_parse_static_routes(sd_dhcp_lease *lease, const uint8_t *option, size_t len) { - int r; - - assert(lease); - assert(option || len <= 0); - - if (len % 8 != 0) - return -EINVAL; - - while (len >= 8) { - struct in_addr dst, gw; - uint8_t prefixlen; - - assert_se(lease_parse_be32(option, 4, &dst.s_addr) >= 0); - option += 4; - - assert_se(lease_parse_be32(option, 4, &gw.s_addr) >= 0); - option += 4; - - len -= 8; - - r = in4_addr_default_prefixlen(&dst, &prefixlen); - if (r < 0) { - log_debug("sd-dhcp-lease: cannot determine class of received static route, ignoring."); - continue; - } - - (void) in4_addr_mask(&dst, prefixlen); - - if (!GREEDY_REALLOC(lease->static_routes, lease->n_static_routes + 1)) - return -ENOMEM; - - lease->static_routes[lease->n_static_routes++] = (struct sd_dhcp_route) { - .dst_addr = dst, - .gw_addr = gw, - .dst_prefixlen = prefixlen, - }; - } - - return 0; -} - -/* parses RFC3442 Classless Static Route Option */ -static int lease_parse_classless_routes(sd_dhcp_lease *lease, const uint8_t *option, size_t len) { - assert(lease); - assert(option || len <= 0); - - /* option format: (subnet-mask-width significant-subnet-octets gateway-ip) */ - - while (len > 0) { - uint8_t prefixlen, dst_octets; - struct in_addr dst = {}, gw; - - prefixlen = *option; - option++; - len--; - - dst_octets = DIV_ROUND_UP(prefixlen, 8); - - /* can't have more than 4 octets in IPv4 */ - if (dst_octets > 4 || len < dst_octets) - return -EINVAL; - - memcpy(&dst, option, dst_octets); - option += dst_octets; - len -= dst_octets; - - if (len < 4) - return -EINVAL; - - assert_se(lease_parse_be32(option, 4, &gw.s_addr) >= 0); - option += 4; - len -= 4; - - if (!GREEDY_REALLOC(lease->classless_routes, lease->n_classless_routes + 1)) - return -ENOMEM; - - lease->classless_routes[lease->n_classless_routes++] = (struct sd_dhcp_route) { - .dst_addr = dst, - .gw_addr = gw, - .dst_prefixlen = prefixlen, - }; - } - - return 0; -} - -static int lease_parse_6rd(sd_dhcp_lease *lease, const uint8_t *option, size_t len) { - uint8_t ipv4masklen, prefixlen; - struct in6_addr prefix; - _cleanup_free_ struct in_addr *br_addresses = NULL; - size_t n_br_addresses; - - assert(lease); - assert(option); - - /* See RFC 5969 Section 7.1.1 */ - - if (lease->sixrd_n_br_addresses > 0) - /* Multiple 6rd option?? */ - return -EINVAL; - - /* option-length: The length of the DHCP option in octets (22 octets with one BR IPv4 address). */ - if (len < 2 + sizeof(struct in6_addr) + sizeof(struct in_addr) || - (len - 2 - sizeof(struct in6_addr)) % sizeof(struct in_addr) != 0) - return -EINVAL; - - /* IPv4MaskLen: The number of high-order bits that are identical across all CE IPv4 addresses - * within a given 6rd domain. This may be any value between 0 and 32. Any value - * greater than 32 is invalid. */ - ipv4masklen = option[0]; - if (ipv4masklen > 32) - return -EINVAL; - - /* 6rdPrefixLen: The IPv6 prefix length of the SP's 6rd IPv6 prefix in number of bits. For the - * purpose of bounds checking by DHCP option processing, the sum of - * (32 - IPv4MaskLen) + 6rdPrefixLen MUST be less than or equal to 128. */ - prefixlen = option[1]; - if (32 - ipv4masklen + prefixlen > 128) - return -EINVAL; - - /* 6rdPrefix: The service provider's 6rd IPv6 prefix represented as a 16-octet IPv6 address. - * The bits in the prefix after the 6rdPrefixlen number of bits are reserved and - * MUST be initialized to zero by the sender and ignored by the receiver. */ - memcpy(&prefix, option + 2, sizeof(struct in6_addr)); - (void) in6_addr_mask(&prefix, prefixlen); - - /* 6rdBRIPv4Address: One or more IPv4 addresses of the 6rd Border Relay(s) for a given 6rd domain. */ - n_br_addresses = (len - 2 - sizeof(struct in6_addr)) / sizeof(struct in_addr); - br_addresses = newdup(struct in_addr, option + 2 + sizeof(struct in6_addr), n_br_addresses); - if (!br_addresses) - return -ENOMEM; - - lease->sixrd_ipv4masklen = ipv4masklen; - lease->sixrd_prefixlen = prefixlen; - lease->sixrd_prefix = prefix; - lease->sixrd_br_addresses = TAKE_PTR(br_addresses); - lease->sixrd_n_br_addresses = n_br_addresses; - - return 0; -} - -int dhcp_lease_parse_options(uint8_t code, uint8_t len, const void *option, void *userdata) { - sd_dhcp_lease *lease = userdata; - int r; - - assert(lease); - - switch (code) { - - case SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME: - r = lease_parse_u32(option, len, &lease->lifetime, 1); - if (r < 0) - log_debug_errno(r, "Failed to parse lease time, ignoring: %m"); - - break; - - case SD_DHCP_OPTION_SERVER_IDENTIFIER: - r = lease_parse_be32(option, len, &lease->server_address); - if (r < 0) - log_debug_errno(r, "Failed to parse server identifier, ignoring: %m"); - - break; - - case SD_DHCP_OPTION_SUBNET_MASK: - r = lease_parse_be32(option, len, &lease->subnet_mask); - if (r < 0) - log_debug_errno(r, "Failed to parse subnet mask, ignoring: %m"); - else - lease->have_subnet_mask = true; - break; - - case SD_DHCP_OPTION_BROADCAST: - r = lease_parse_be32(option, len, &lease->broadcast); - if (r < 0) - log_debug_errno(r, "Failed to parse broadcast address, ignoring: %m"); - else - lease->have_broadcast = true; - break; - - case SD_DHCP_OPTION_ROUTER: - r = lease_parse_in_addrs(option, len, &lease->router, &lease->router_size); - if (r < 0) - log_debug_errno(r, "Failed to parse router addresses, ignoring: %m"); - break; - - case SD_DHCP_OPTION_DOMAIN_NAME_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_DNS].addr, &lease->servers[SD_DHCP_LEASE_DNS].size); - if (r < 0) - log_debug_errno(r, "Failed to parse DNS server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_NTP_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_NTP].addr, &lease->servers[SD_DHCP_LEASE_NTP].size); - if (r < 0) - log_debug_errno(r, "Failed to parse NTP server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_SIP_SERVER: - r = lease_parse_sip_server(option, len, &lease->servers[SD_DHCP_LEASE_SIP].addr, &lease->servers[SD_DHCP_LEASE_SIP].size); - if (r < 0) - log_debug_errno(r, "Failed to parse SIP server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_POP3_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_POP3].addr, &lease->servers[SD_DHCP_LEASE_POP3].size); - if (r < 0) - log_debug_errno(r, "Failed to parse POP3 server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_SMTP_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_SMTP].addr, &lease->servers[SD_DHCP_LEASE_SMTP].size); - if (r < 0) - log_debug_errno(r, "Failed to parse SMTP server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_LPR_SERVER: - r = lease_parse_in_addrs(option, len, &lease->servers[SD_DHCP_LEASE_LPR].addr, &lease->servers[SD_DHCP_LEASE_LPR].size); - if (r < 0) - log_debug_errno(r, "Failed to parse LPR server, ignoring: %m"); - break; - - case SD_DHCP_OPTION_STATIC_ROUTE: - r = lease_parse_static_routes(lease, option, len); - if (r < 0) - log_debug_errno(r, "Failed to parse static routes, ignoring: %m"); - break; - - case SD_DHCP_OPTION_MTU_INTERFACE: - r = lease_parse_u16(option, len, &lease->mtu, 68); - if (r < 0) - log_debug_errno(r, "Failed to parse MTU, ignoring: %m"); - if (lease->mtu < DHCP_DEFAULT_MIN_SIZE) { - log_debug("MTU value of %" PRIu16 " too small. Using default MTU value of %d instead.", lease->mtu, DHCP_DEFAULT_MIN_SIZE); - lease->mtu = DHCP_DEFAULT_MIN_SIZE; - } - - break; - - case SD_DHCP_OPTION_DOMAIN_NAME: - r = lease_parse_domain(option, len, &lease->domainname); - if (r < 0) { - log_debug_errno(r, "Failed to parse domain name, ignoring: %m"); - return 0; - } - - break; - - case SD_DHCP_OPTION_DOMAIN_SEARCH: - r = dhcp_lease_parse_search_domains(option, len, &lease->search_domains); - if (r < 0) - log_debug_errno(r, "Failed to parse Domain Search List, ignoring: %m"); - break; - - case SD_DHCP_OPTION_HOST_NAME: - r = lease_parse_domain(option, len, &lease->hostname); - if (r < 0) { - log_debug_errno(r, "Failed to parse hostname, ignoring: %m"); - return 0; - } - - break; - - case SD_DHCP_OPTION_ROOT_PATH: - r = lease_parse_string(option, len, &lease->root_path); - if (r < 0) - log_debug_errno(r, "Failed to parse root path, ignoring: %m"); - break; - - case SD_DHCP_OPTION_RENEWAL_TIME: - r = lease_parse_u32(option, len, &lease->t1, 1); - if (r < 0) - log_debug_errno(r, "Failed to parse T1 time, ignoring: %m"); - break; - - case SD_DHCP_OPTION_REBINDING_TIME: - r = lease_parse_u32(option, len, &lease->t2, 1); - if (r < 0) - log_debug_errno(r, "Failed to parse T2 time, ignoring: %m"); - break; - - case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE: - r = lease_parse_classless_routes(lease, option, len); - if (r < 0) - log_debug_errno(r, "Failed to parse classless routes, ignoring: %m"); - break; - - case SD_DHCP_OPTION_TZDB_TIMEZONE: { - _cleanup_free_ char *tz = NULL; - - r = lease_parse_string(option, len, &tz); - if (r < 0) { - log_debug_errno(r, "Failed to parse timezone option, ignoring: %m"); - return 0; - } - - if (!timezone_is_valid(tz, LOG_DEBUG)) { - log_debug("Timezone is not valid, ignoring."); - return 0; - } - - free_and_replace(lease->timezone, tz); - - break; - } - - case SD_DHCP_OPTION_VENDOR_SPECIFIC: - - if (len <= 0) - lease->vendor_specific = mfree(lease->vendor_specific); - else { - void *p; - - p = memdup(option, len); - if (!p) - return -ENOMEM; - - free(lease->vendor_specific); - lease->vendor_specific = p; - } - - lease->vendor_specific_len = len; - break; - - case SD_DHCP_OPTION_6RD: - r = lease_parse_6rd(lease, option, len); - if (r < 0) - log_debug_errno(r, "Failed to parse 6rd option, ignoring: %m"); - break; - - case SD_DHCP_OPTION_PRIVATE_BASE ... SD_DHCP_OPTION_PRIVATE_LAST: - r = dhcp_lease_insert_private_option(lease, code, option, len); - if (r < 0) - return r; - - break; - - default: - log_debug("Ignoring option DHCP option %"PRIu8" while parsing.", code); - break; - } - - return 0; -} - -/* Parses compressed domain names. */ -int dhcp_lease_parse_search_domains(const uint8_t *option, size_t len, char ***domains) { - _cleanup_strv_free_ char **names = NULL; - size_t pos = 0, cnt = 0; - int r; - - assert(domains); - assert_return(option && len > 0, -ENODATA); - - while (pos < len) { - _cleanup_free_ char *name = NULL; - size_t n = 0; - size_t jump_barrier = pos, next_chunk = 0; - bool first = true; - - for (;;) { - uint8_t c; - c = option[pos++]; - - if (c == 0) { - /* End of name */ - break; - } else if (c <= 63) { - const char *label; - - /* Literal label */ - label = (const char*) (option + pos); - pos += c; - if (pos >= len) - return -EBADMSG; - - if (!GREEDY_REALLOC(name, n + !first + DNS_LABEL_ESCAPED_MAX)) - return -ENOMEM; - - if (first) - first = false; - else - name[n++] = '.'; - - r = dns_label_escape(label, c, name + n, DNS_LABEL_ESCAPED_MAX); - if (r < 0) - return r; - - n += r; - } else if (FLAGS_SET(c, 0xc0)) { - /* Pointer */ - - uint8_t d; - uint16_t ptr; - - if (pos >= len) - return -EBADMSG; - - d = option[pos++]; - ptr = (uint16_t) (c & ~0xc0) << 8 | (uint16_t) d; - - /* Jumps are limited to a "prior occurrence" (RFC-1035 4.1.4) */ - if (ptr >= jump_barrier) - return -EBADMSG; - jump_barrier = ptr; - - /* Save current location so we don't end up re-parsing what's parsed so far. */ - if (next_chunk == 0) - next_chunk = pos; - - pos = ptr; - } else - return -EBADMSG; - } - - if (!GREEDY_REALLOC(name, n + 1)) - return -ENOMEM; - name[n] = 0; - - r = strv_extend(&names, name); - if (r < 0) - return r; - - cnt++; - - if (next_chunk != 0) - pos = next_chunk; - } - - strv_free_and_replace(*domains, names); - - return cnt; -} - -int dhcp_lease_insert_private_option(sd_dhcp_lease *lease, uint8_t tag, const void *data, uint8_t len) { - struct sd_dhcp_raw_option *option, *before = NULL; - - assert(lease); - - LIST_FOREACH(options, cur, lease->private_options) { - if (tag < cur->tag) { - before = cur; - break; - } - if (tag == cur->tag) { - log_debug("Ignoring duplicate option, tagged %i.", tag); - return 0; - } - } - - option = new(struct sd_dhcp_raw_option, 1); - if (!option) - return -ENOMEM; - - option->tag = tag; - option->length = len; - option->data = memdup(data, len); - if (!option->data) { - free(option); - return -ENOMEM; - } - - LIST_INSERT_BEFORE(options, lease->private_options, before, option); - return 0; -} - -int dhcp_lease_new(sd_dhcp_lease **ret) { - sd_dhcp_lease *lease; - - lease = new0(sd_dhcp_lease, 1); - if (!lease) - return -ENOMEM; - - lease->n_ref = 1; - - *ret = lease; - return 0; -} - -int dhcp_lease_save(sd_dhcp_lease *lease, const char *lease_file) { - _cleanup_(unlink_and_freep) char *temp_path = NULL; - _cleanup_fclose_ FILE *f = NULL; - struct in_addr address; - const struct in_addr *addresses; - const void *client_id, *data; - size_t client_id_len, data_len; - char sbuf[INET_ADDRSTRLEN]; - const char *string; - uint16_t mtu; - _cleanup_free_ sd_dhcp_route **routes = NULL; - char **search_domains; - uint32_t t1, t2, lifetime; - int r; - - assert(lease); - assert(lease_file); - - r = fopen_temporary(lease_file, &f, &temp_path); - if (r < 0) - return r; - - (void) fchmod(fileno(f), 0644); - - fprintf(f, - "# This is private data. Do not parse.\n"); - - r = sd_dhcp_lease_get_address(lease, &address); - if (r >= 0) - fprintf(f, "ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_netmask(lease, &address); - if (r >= 0) - fprintf(f, "NETMASK=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_router(lease, &addresses); - if (r > 0) { - fputs("ROUTER=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_server_identifier(lease, &address); - if (r >= 0) - fprintf(f, "SERVER_ADDRESS=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_next_server(lease, &address); - if (r >= 0) - fprintf(f, "NEXT_SERVER=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_broadcast(lease, &address); - if (r >= 0) - fprintf(f, "BROADCAST=%s\n", inet_ntop(AF_INET, &address, sbuf, sizeof(sbuf))); - - r = sd_dhcp_lease_get_mtu(lease, &mtu); - if (r >= 0) - fprintf(f, "MTU=%" PRIu16 "\n", mtu); - - r = sd_dhcp_lease_get_t1(lease, &t1); - if (r >= 0) - fprintf(f, "T1=%" PRIu32 "\n", t1); - - r = sd_dhcp_lease_get_t2(lease, &t2); - if (r >= 0) - fprintf(f, "T2=%" PRIu32 "\n", t2); - - r = sd_dhcp_lease_get_lifetime(lease, &lifetime); - if (r >= 0) - fprintf(f, "LIFETIME=%" PRIu32 "\n", lifetime); - - r = sd_dhcp_lease_get_dns(lease, &addresses); - if (r > 0) { - fputs("DNS=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_ntp(lease, &addresses); - if (r > 0) { - fputs("NTP=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_sip(lease, &addresses); - if (r > 0) { - fputs("SIP=", f); - serialize_in_addrs(f, addresses, r, false, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_domainname(lease, &string); - if (r >= 0) - fprintf(f, "DOMAINNAME=%s\n", string); - - r = sd_dhcp_lease_get_search_domains(lease, &search_domains); - if (r > 0) { - fputs("DOMAIN_SEARCH_LIST=", f); - fputstrv(f, search_domains, NULL, NULL); - fputc('\n', f); - } - - r = sd_dhcp_lease_get_hostname(lease, &string); - if (r >= 0) - fprintf(f, "HOSTNAME=%s\n", string); - - r = sd_dhcp_lease_get_root_path(lease, &string); - if (r >= 0) - fprintf(f, "ROOT_PATH=%s\n", string); - - r = sd_dhcp_lease_get_static_routes(lease, &routes); - if (r > 0) - serialize_dhcp_routes(f, "STATIC_ROUTES", routes, r); - - routes = mfree(routes); - r = sd_dhcp_lease_get_classless_routes(lease, &routes); - if (r > 0) - serialize_dhcp_routes(f, "CLASSLESS_ROUTES", routes, r); - - r = sd_dhcp_lease_get_timezone(lease, &string); - if (r >= 0) - fprintf(f, "TIMEZONE=%s\n", string); - - r = sd_dhcp_lease_get_client_id(lease, &client_id, &client_id_len); - if (r >= 0) { - _cleanup_free_ char *client_id_hex = NULL; - - client_id_hex = hexmem(client_id, client_id_len); - if (!client_id_hex) - return -ENOMEM; - fprintf(f, "CLIENTID=%s\n", client_id_hex); - } - - r = sd_dhcp_lease_get_vendor_specific(lease, &data, &data_len); - if (r >= 0) { - _cleanup_free_ char *option_hex = NULL; - - option_hex = hexmem(data, data_len); - if (!option_hex) - return -ENOMEM; - fprintf(f, "VENDOR_SPECIFIC=%s\n", option_hex); - } - - LIST_FOREACH(options, option, lease->private_options) { - char key[STRLEN("OPTION_000")+1]; - - xsprintf(key, "OPTION_%" PRIu8, option->tag); - r = serialize_dhcp_option(f, key, option->data, option->length); - if (r < 0) - return r; - } - - r = fflush_and_check(f); - if (r < 0) - return r; - - r = conservative_rename(temp_path, lease_file); - if (r < 0) - return r; - - temp_path = mfree(temp_path); - - return 0; -} - -static char **private_options_free(char **options) { - if (!options) - return NULL; - - for (unsigned i = 0; i < SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1; i++) - free(options[i]); - - return mfree(options); -} - -DEFINE_TRIVIAL_CLEANUP_FUNC(char**, private_options_free); - -int dhcp_lease_load(sd_dhcp_lease **ret, const char *lease_file) { - _cleanup_(sd_dhcp_lease_unrefp) sd_dhcp_lease *lease = NULL; - _cleanup_free_ char - *address = NULL, - *router = NULL, - *netmask = NULL, - *server_address = NULL, - *next_server = NULL, - *broadcast = NULL, - *dns = NULL, - *ntp = NULL, - *sip = NULL, - *pop3 = NULL, - *smtp = NULL, - *lpr = NULL, - *mtu = NULL, - *static_routes = NULL, - *classless_routes = NULL, - *domains = NULL, - *client_id_hex = NULL, - *vendor_specific_hex = NULL, - *lifetime = NULL, - *t1 = NULL, - *t2 = NULL; - _cleanup_(private_options_freep) char **options = NULL; - - int r, i; - - assert(lease_file); - assert(ret); - - r = dhcp_lease_new(&lease); - if (r < 0) - return r; - - options = new0(char*, SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE + 1); - if (!options) - return -ENOMEM; - - r = parse_env_file(NULL, lease_file, - "ADDRESS", &address, - "ROUTER", &router, - "NETMASK", &netmask, - "SERVER_ADDRESS", &server_address, - "NEXT_SERVER", &next_server, - "BROADCAST", &broadcast, - "DNS", &dns, - "NTP", &ntp, - "SIP", &sip, - "POP3", &pop3, - "SMTP", &smtp, - "LPR", &lpr, - "MTU", &mtu, - "DOMAINNAME", &lease->domainname, - "HOSTNAME", &lease->hostname, - "DOMAIN_SEARCH_LIST", &domains, - "ROOT_PATH", &lease->root_path, - "STATIC_ROUTES", &static_routes, - "CLASSLESS_ROUTES", &classless_routes, - "CLIENTID", &client_id_hex, - "TIMEZONE", &lease->timezone, - "VENDOR_SPECIFIC", &vendor_specific_hex, - "LIFETIME", &lifetime, - "T1", &t1, - "T2", &t2, - "OPTION_224", &options[0], - "OPTION_225", &options[1], - "OPTION_226", &options[2], - "OPTION_227", &options[3], - "OPTION_228", &options[4], - "OPTION_229", &options[5], - "OPTION_230", &options[6], - "OPTION_231", &options[7], - "OPTION_232", &options[8], - "OPTION_233", &options[9], - "OPTION_234", &options[10], - "OPTION_235", &options[11], - "OPTION_236", &options[12], - "OPTION_237", &options[13], - "OPTION_238", &options[14], - "OPTION_239", &options[15], - "OPTION_240", &options[16], - "OPTION_241", &options[17], - "OPTION_242", &options[18], - "OPTION_243", &options[19], - "OPTION_244", &options[20], - "OPTION_245", &options[21], - "OPTION_246", &options[22], - "OPTION_247", &options[23], - "OPTION_248", &options[24], - "OPTION_249", &options[25], - "OPTION_250", &options[26], - "OPTION_251", &options[27], - "OPTION_252", &options[28], - "OPTION_253", &options[29], - "OPTION_254", &options[30]); - if (r < 0) - return r; - - if (address) { - r = inet_pton(AF_INET, address, &lease->address); - if (r <= 0) - log_debug("Failed to parse address %s, ignoring.", address); - } - - if (router) { - r = deserialize_in_addrs(&lease->router, router); - if (r < 0) - log_debug_errno(r, "Failed to deserialize router addresses %s, ignoring: %m", router); - else - lease->router_size = r; - } - - if (netmask) { - r = inet_pton(AF_INET, netmask, &lease->subnet_mask); - if (r <= 0) - log_debug("Failed to parse netmask %s, ignoring.", netmask); - else - lease->have_subnet_mask = true; - } - - if (server_address) { - r = inet_pton(AF_INET, server_address, &lease->server_address); - if (r <= 0) - log_debug("Failed to parse server address %s, ignoring.", server_address); - } - - if (next_server) { - r = inet_pton(AF_INET, next_server, &lease->next_server); - if (r <= 0) - log_debug("Failed to parse next server %s, ignoring.", next_server); - } - - if (broadcast) { - r = inet_pton(AF_INET, broadcast, &lease->broadcast); - if (r <= 0) - log_debug("Failed to parse broadcast address %s, ignoring.", broadcast); - else - lease->have_broadcast = true; - } - - if (dns) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_DNS].addr, dns); - if (r < 0) - log_debug_errno(r, "Failed to deserialize DNS servers %s, ignoring: %m", dns); - else - lease->servers[SD_DHCP_LEASE_DNS].size = r; - } - - if (ntp) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_NTP].addr, ntp); - if (r < 0) - log_debug_errno(r, "Failed to deserialize NTP servers %s, ignoring: %m", ntp); - else - lease->servers[SD_DHCP_LEASE_NTP].size = r; - } - - if (sip) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_SIP].addr, sip); - if (r < 0) - log_debug_errno(r, "Failed to deserialize SIP servers %s, ignoring: %m", sip); - else - lease->servers[SD_DHCP_LEASE_SIP].size = r; - } - - if (pop3) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_POP3].addr, pop3); - if (r < 0) - log_debug_errno(r, "Failed to deserialize POP3 server %s, ignoring: %m", pop3); - else - lease->servers[SD_DHCP_LEASE_POP3].size = r; - } - - if (smtp) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_SMTP].addr, smtp); - if (r < 0) - log_debug_errno(r, "Failed to deserialize SMTP server %s, ignoring: %m", smtp); - else - lease->servers[SD_DHCP_LEASE_SMTP].size = r; - } - - if (lpr) { - r = deserialize_in_addrs(&lease->servers[SD_DHCP_LEASE_LPR].addr, lpr); - if (r < 0) - log_debug_errno(r, "Failed to deserialize LPR server %s, ignoring: %m", lpr); - else - lease->servers[SD_DHCP_LEASE_LPR].size = r; - } - - if (mtu) { - r = safe_atou16(mtu, &lease->mtu); - if (r < 0) - log_debug_errno(r, "Failed to parse MTU %s, ignoring: %m", mtu); - } - - if (domains) { - _cleanup_strv_free_ char **a = NULL; - a = strv_split(domains, " "); - if (!a) - return -ENOMEM; - - if (!strv_isempty(a)) - lease->search_domains = TAKE_PTR(a); - } - - if (static_routes) { - r = deserialize_dhcp_routes( - &lease->static_routes, - &lease->n_static_routes, - static_routes); - if (r < 0) - log_debug_errno(r, "Failed to parse DHCP static routes %s, ignoring: %m", static_routes); - } - - if (classless_routes) { - r = deserialize_dhcp_routes( - &lease->classless_routes, - &lease->n_classless_routes, - classless_routes); - if (r < 0) - log_debug_errno(r, "Failed to parse DHCP classless routes %s, ignoring: %m", classless_routes); - } - - if (lifetime) { - r = safe_atou32(lifetime, &lease->lifetime); - if (r < 0) - log_debug_errno(r, "Failed to parse lifetime %s, ignoring: %m", lifetime); - } - - if (t1) { - r = safe_atou32(t1, &lease->t1); - if (r < 0) - log_debug_errno(r, "Failed to parse T1 %s, ignoring: %m", t1); - } - - if (t2) { - r = safe_atou32(t2, &lease->t2); - if (r < 0) - log_debug_errno(r, "Failed to parse T2 %s, ignoring: %m", t2); - } - - if (client_id_hex) { - r = unhexmem(client_id_hex, SIZE_MAX, &lease->client_id, &lease->client_id_len); - if (r < 0) - log_debug_errno(r, "Failed to parse client ID %s, ignoring: %m", client_id_hex); - } - - if (vendor_specific_hex) { - r = unhexmem(vendor_specific_hex, SIZE_MAX, &lease->vendor_specific, &lease->vendor_specific_len); - if (r < 0) - log_debug_errno(r, "Failed to parse vendor specific data %s, ignoring: %m", vendor_specific_hex); - } - - for (i = 0; i <= SD_DHCP_OPTION_PRIVATE_LAST - SD_DHCP_OPTION_PRIVATE_BASE; i++) { - _cleanup_free_ void *data = NULL; - size_t len; - - if (!options[i]) - continue; - - r = unhexmem(options[i], SIZE_MAX, &data, &len); - if (r < 0) { - log_debug_errno(r, "Failed to parse private DHCP option %s, ignoring: %m", options[i]); - continue; - } - - r = dhcp_lease_insert_private_option(lease, SD_DHCP_OPTION_PRIVATE_BASE + i, data, len); - if (r < 0) - return r; - } - - *ret = TAKE_PTR(lease); - - return 0; -} - -int dhcp_lease_set_default_subnet_mask(sd_dhcp_lease *lease) { - struct in_addr address, mask; - int r; - - assert(lease); - - if (lease->address == 0) - return -ENODATA; - - address.s_addr = lease->address; - - /* fall back to the default subnet masks based on address class */ - r = in4_addr_default_subnet_mask(&address, &mask); - if (r < 0) - return r; - - lease->subnet_mask = mask.s_addr; - lease->have_subnet_mask = true; - - return 0; -} - -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len) { - assert_return(lease, -EINVAL); - assert_return(client_id, -EINVAL); - assert_return(client_id_len, -EINVAL); - - if (!lease->client_id) - return -ENODATA; - - *client_id = lease->client_id; - *client_id_len = lease->client_id_len; - - return 0; -} - -int dhcp_lease_set_client_id(sd_dhcp_lease *lease, const void *client_id, size_t client_id_len) { - assert_return(lease, -EINVAL); - assert_return(client_id || client_id_len <= 0, -EINVAL); - - if (client_id_len <= 0) - lease->client_id = mfree(lease->client_id); - else { - void *p; - - p = memdup(client_id, client_id_len); - if (!p) - return -ENOMEM; - - free(lease->client_id); - lease->client_id = p; - lease->client_id_len = client_id_len; - } - - return 0; -} - -int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **tz) { - assert_return(lease, -EINVAL); - assert_return(tz, -EINVAL); - - if (!lease->timezone) - return -ENODATA; - - *tz = lease->timezone; - return 0; -} - -int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination) { - assert_return(route, -EINVAL); - assert_return(destination, -EINVAL); - - *destination = route->dst_addr; - return 0; -} - -int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length) { - assert_return(route, -EINVAL); - assert_return(length, -EINVAL); - - *length = route->dst_prefixlen; - return 0; -} - -int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway) { - assert_return(route, -EINVAL); - assert_return(gateway, -EINVAL); - - *gateway = route->gw_addr; - return 0; -} diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c index 27864a0a49..4ca5159106 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-client.c @@ -23,16 +23,10 @@ #include "io-util.h" #include "random-util.h" #include "socket-util.h" +#include "sort-util.h" #include "strv.h" #include "web-util.h" -static const uint16_t default_req_opts[] = { - SD_DHCP6_OPTION_DNS_SERVERS, - SD_DHCP6_OPTION_DOMAIN_LIST, - SD_DHCP6_OPTION_NTP_SERVER, - SD_DHCP6_OPTION_SNTP_SERVERS, -}; - #define DHCP6_CLIENT_DONT_DESTROY(client) \ _cleanup_(sd_dhcp6_client_unrefp) _unused_ sd_dhcp6_client *_dont_destroy_##client = sd_dhcp6_client_ref(client) @@ -371,8 +365,12 @@ int sd_dhcp6_client_get_information_request(sd_dhcp6_client *client, int *enable return 0; } +static int be16_compare_func(const be16_t *a, const be16_t *b) { + return CMP(be16toh(*a), be16toh(*b)); +} + int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) { - size_t t; + be16_t opt; assert_return(client, -EINVAL); assert_return(!sd_dhcp6_client_is_running(client), -EBUSY); @@ -380,15 +378,17 @@ int sd_dhcp6_client_set_request_option(sd_dhcp6_client *client, uint16_t option) if (!dhcp6_option_can_request(option)) return -EINVAL; - for (t = 0; t < client->req_opts_len; t++) - if (client->req_opts[t] == htobe16(option)) - return -EEXIST; + opt = htobe16(option); + if (typesafe_bsearch(&opt, client->req_opts, client->n_req_opts, be16_compare_func)) + return -EEXIST; - if (!GREEDY_REALLOC(client->req_opts, client->req_opts_len + 1)) + if (!GREEDY_REALLOC(client->req_opts, client->n_req_opts + 1)) return -ENOMEM; - client->req_opts[client->req_opts_len++] = htobe16(option); + client->req_opts[client->n_req_opts++] = opt; + /* Sort immediately to make the above binary search will work for the next time. */ + typesafe_qsort(client->req_opts, client->n_req_opts, be16_compare_func); return 0; } @@ -635,6 +635,51 @@ static DHCP6MessageType client_message_type_from_state(sd_dhcp6_client *client) } } +static int client_append_oro(sd_dhcp6_client *client, uint8_t **opt, size_t *optlen) { + _cleanup_free_ be16_t *buf = NULL; + be16_t *req_opts; + size_t n; + + assert(client); + assert(opt); + assert(optlen); + + switch (client->state) { + case DHCP6_STATE_INFORMATION_REQUEST: + n = client->n_req_opts; + buf = new(be16_t, n + 2); + if (!buf) + return -ENOMEM; + + memcpy_safe(buf, client->req_opts, n * sizeof(be16_t)); + buf[n++] = htobe16(SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME); /* RFC 8415 section 21.23 */ + buf[n++] = htobe16(SD_DHCP6_OPTION_INF_MAX_RT); /* RFC 8415 section 21.25 */ + + typesafe_qsort(buf, n, be16_compare_func); + req_opts = buf; + break; + + case DHCP6_STATE_SOLICITATION: + n = client->n_req_opts; + buf = new(be16_t, n + 1); + if (!buf) + return -ENOMEM; + + memcpy_safe(buf, client->req_opts, n * sizeof(be16_t)); + buf[n++] = htobe16(SD_DHCP6_OPTION_SOL_MAX_RT); /* RFC 8415 section 21.24 */ + + typesafe_qsort(buf, n, be16_compare_func); + req_opts = buf; + break; + + default: + n = client->n_req_opts; + req_opts = client->req_opts; + } + + return dhcp6_option_append(opt, optlen, SD_DHCP6_OPTION_ORO, n * sizeof(be16_t), req_opts); +} + int dhcp6_client_send_message(sd_dhcp6_client *client) { _cleanup_free_ DHCP6Message *message = NULL; struct in6_addr all_servers = @@ -712,9 +757,7 @@ int dhcp6_client_send_message(sd_dhcp6_client *client) { return r; } - r = dhcp6_option_append(&opt, &optlen, SD_DHCP6_OPTION_ORO, - client->req_opts_len * sizeof(be16_t), - client->req_opts); + r = client_append_oro(client, &opt, &optlen); if (r < 0) return r; @@ -1301,13 +1344,10 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { if (client->fd < 0) { r = dhcp6_network_bind_udp_socket(client->ifindex, &client->local_address); - if (r < 0) { - _cleanup_free_ char *p = NULL; - - (void) in6_addr_to_string(&client->local_address, &p); + if (r < 0) return log_dhcp6_client_errno(client, r, - "Failed to bind to UDP socket at address %s: %m", strna(p)); - } + "Failed to bind to UDP socket at address %s: %m", + IN6_ADDR_TO_STRING(&client->local_address)); client->fd = r; } @@ -1341,7 +1381,7 @@ int sd_dhcp6_client_start(sd_dhcp6_client *client) { } log_dhcp6_client(client, "Starting in %s mode", - client->information_request ? "Information request" : "Managed"); + client->information_request ? "Information request" : "Solicit"); return client_start_transaction(client, state); } @@ -1413,18 +1453,9 @@ DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_dhcp6_client, sd_dhcp6_client, dhcp6_client_fre int sd_dhcp6_client_new(sd_dhcp6_client **ret) { _cleanup_(sd_dhcp6_client_unrefp) sd_dhcp6_client *client = NULL; - _cleanup_free_ be16_t *req_opts = NULL; - size_t t; assert_return(ret, -EINVAL); - req_opts = new(be16_t, ELEMENTSOF(default_req_opts)); - if (!req_opts) - return -ENOMEM; - - for (t = 0; t < ELEMENTSOF(default_req_opts); t++) - req_opts[t] = htobe16(default_req_opts[t]); - client = new(sd_dhcp6_client, 1); if (!client) return -ENOMEM; @@ -1436,8 +1467,6 @@ int sd_dhcp6_client_new(sd_dhcp6_client **ret) { .ifindex = -1, .request_ia = DHCP6_REQUEST_IA_NA | DHCP6_REQUEST_IA_PD, .fd = -1, - .req_opts_len = ELEMENTSOF(default_req_opts), - .req_opts = TAKE_PTR(req_opts), }; *ret = TAKE_PTR(client); diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c index a4cc2c920c..2475cdb7ed 100644 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c +++ b/src/libnm-systemd-core/src/libsystemd-network/sd-dhcp6-lease.c @@ -570,14 +570,14 @@ static int dhcp6_lease_parse_message( break; - case SD_DHCP6_OPTION_DNS_SERVERS: + case SD_DHCP6_OPTION_DNS_SERVER: r = dhcp6_lease_add_dns(lease, optval, optlen); if (r < 0) log_dhcp6_client_errno(client, r, "Failed to parse DNS server option, ignoring: %m"); break; - case SD_DHCP6_OPTION_DOMAIN_LIST: + case SD_DHCP6_OPTION_DOMAIN: r = dhcp6_lease_add_domains(lease, optval, optlen); if (r < 0) log_dhcp6_client_errno(client, r, "Failed to parse domain list option, ignoring: %m"); @@ -591,7 +591,7 @@ static int dhcp6_lease_parse_message( break; - case SD_DHCP6_OPTION_SNTP_SERVERS: + case SD_DHCP6_OPTION_SNTP_SERVER: r = dhcp6_lease_add_sntp(lease, optval, optlen); if (r < 0) log_dhcp6_client_errno(client, r, "Failed to parse SNTP server option, ignoring: %m"); diff --git a/src/libnm-systemd-core/src/libsystemd-network/sd-ipv4ll.c b/src/libnm-systemd-core/src/libsystemd-network/sd-ipv4ll.c deleted file mode 100644 index ff065fd1b6..0000000000 --- a/src/libnm-systemd-core/src/libsystemd-network/sd-ipv4ll.c +++ /dev/null @@ -1,380 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. -***/ - -#include -#include -#include -#include - -#include "sd-id128.h" -#include "sd-ipv4acd.h" -#include "sd-ipv4ll.h" - -#include "alloc-util.h" -#include "ether-addr-util.h" -#include "in-addr-util.h" -#include "network-common.h" -#include "random-util.h" -#include "siphash24.h" -#include "sparse-endian.h" -#include "string-util.h" -#include "util.h" - -#define IPV4LL_NETWORK UINT32_C(0xA9FE0000) -#define IPV4LL_NETMASK UINT32_C(0xFFFF0000) - -#define IPV4LL_DONT_DESTROY(ll) \ - _cleanup_(sd_ipv4ll_unrefp) _unused_ sd_ipv4ll *_dont_destroy_##ll = sd_ipv4ll_ref(ll) - -struct sd_ipv4ll { - unsigned n_ref; - - sd_ipv4acd *acd; - - be32_t address; /* the address pushed to ACD */ - struct ether_addr mac; - - struct { - le64_t value; - le64_t generation; - } seed; - bool seed_set; - - /* External */ - be32_t claimed_address; - - sd_ipv4ll_callback_t callback; - void *userdata; - - sd_ipv4ll_check_mac_callback_t check_mac_callback; - void *check_mac_userdata; -}; - -#define log_ipv4ll_errno(ll, error, fmt, ...) \ - log_interface_prefix_full_errno( \ - "IPv4LL: ", \ - sd_ipv4ll, ll, \ - error, fmt, ##__VA_ARGS__) -#define log_ipv4ll(ll, fmt, ...) \ - log_interface_prefix_full_errno_zerook( \ - "IPv4LL: ", \ - sd_ipv4ll, ll, \ - 0, fmt, ##__VA_ARGS__) - -static void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata); -static int ipv4ll_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata); - -static sd_ipv4ll *ipv4ll_free(sd_ipv4ll *ll) { - assert(ll); - - sd_ipv4acd_unref(ll->acd); - return mfree(ll); -} - -DEFINE_TRIVIAL_REF_UNREF_FUNC(sd_ipv4ll, sd_ipv4ll, ipv4ll_free); - -int sd_ipv4ll_new(sd_ipv4ll **ret) { - _cleanup_(sd_ipv4ll_unrefp) sd_ipv4ll *ll = NULL; - int r; - - assert_return(ret, -EINVAL); - - ll = new0(sd_ipv4ll, 1); - if (!ll) - return -ENOMEM; - - ll->n_ref = 1; - - r = sd_ipv4acd_new(&ll->acd); - if (r < 0) - return r; - - r = sd_ipv4acd_set_callback(ll->acd, ipv4ll_on_acd, ll); - if (r < 0) - return r; - - r = sd_ipv4acd_set_check_mac_callback(ll->acd, ipv4ll_check_mac, ll); - if (r < 0) - return r; - - *ret = TAKE_PTR(ll); - - return 0; -} - -int sd_ipv4ll_stop(sd_ipv4ll *ll) { - if (!ll) - return 0; - - return sd_ipv4acd_stop(ll->acd); -} - -int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int ifindex) { - assert_return(ll, -EINVAL); - assert_return(ifindex > 0, -EINVAL); - assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - - return sd_ipv4acd_set_ifindex(ll->acd, ifindex); -} - -int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll) { - if (!ll) - return -EINVAL; - - return sd_ipv4acd_get_ifindex(ll->acd); -} - -int sd_ipv4ll_set_ifname(sd_ipv4ll *ll, const char *ifname) { - assert_return(ll, -EINVAL); - assert_return(ifname, -EINVAL); - - return sd_ipv4acd_set_ifname(ll->acd, ifname); -} - -int sd_ipv4ll_get_ifname(sd_ipv4ll *ll, const char **ret) { - assert_return(ll, -EINVAL); - - return sd_ipv4acd_get_ifname(ll->acd, ret); -} - -int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr) { - int r; - - assert_return(ll, -EINVAL); - assert_return(addr, -EINVAL); - assert_return(!ether_addr_is_null(addr), -EINVAL); - - r = sd_ipv4acd_set_mac(ll->acd, addr); - if (r < 0) - return r; - - ll->mac = *addr; - return 0; -} - -int sd_ipv4ll_detach_event(sd_ipv4ll *ll) { - assert_return(ll, -EINVAL); - - return sd_ipv4acd_detach_event(ll->acd); -} - -int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority) { - assert_return(ll, -EINVAL); - - return sd_ipv4acd_attach_event(ll->acd, event, priority); -} - -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata) { - assert_return(ll, -EINVAL); - - ll->callback = cb; - ll->userdata = userdata; - - return 0; -} - -int sd_ipv4ll_set_check_mac_callback(sd_ipv4ll *ll, sd_ipv4ll_check_mac_callback_t cb, void *userdata) { - assert_return(ll, -EINVAL); - - ll->check_mac_callback = cb; - ll->check_mac_userdata = userdata; - - return 0; -} - -int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address) { - assert_return(ll, -EINVAL); - assert_return(address, -EINVAL); - - if (ll->claimed_address == 0) - return -ENOENT; - - address->s_addr = ll->claimed_address; - - return 0; -} - -int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed) { - assert_return(ll, -EINVAL); - assert_return(sd_ipv4ll_is_running(ll) == 0, -EBUSY); - - ll->seed.value = htole64(seed); - ll->seed_set = true; - - return 0; -} - -int sd_ipv4ll_is_running(sd_ipv4ll *ll) { - assert_return(ll, false); - - return sd_ipv4acd_is_running(ll->acd); -} - -static bool ipv4ll_address_is_valid(const struct in_addr *address) { - assert(address); - - if (!in4_addr_is_link_local(address)) - return false; - - return !IN_SET(be32toh(address->s_addr) & 0x0000FF00U, 0x0000U, 0xFF00U); -} - -int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address) { - int r; - - assert_return(ll, -EINVAL); - assert_return(address, -EINVAL); - assert_return(ipv4ll_address_is_valid(address), -EINVAL); - - r = sd_ipv4acd_set_address(ll->acd, address); - if (r < 0) - return r; - - ll->address = address->s_addr; - - return 0; -} - -#define PICK_HASH_KEY SD_ID128_MAKE(15,ac,82,a6,d6,3f,49,78,98,77,5d,0c,69,02,94,0b) - -static int ipv4ll_pick_address(sd_ipv4ll *ll) { - _cleanup_free_ char *address = NULL; - be32_t addr; - - assert(ll); - - do { - uint64_t h; - - h = siphash24(&ll->seed, sizeof(ll->seed), PICK_HASH_KEY.bytes); - - /* Increase the generation counter by one */ - ll->seed.generation = htole64(le64toh(ll->seed.generation) + 1); - - addr = htobe32((h & UINT32_C(0x0000FFFF)) | IPV4LL_NETWORK); - } while (addr == ll->address || - IN_SET(be32toh(addr) & 0x0000FF00U, 0x0000U, 0xFF00U)); - - (void) in_addr_to_string(AF_INET, &(union in_addr_union) { .in.s_addr = addr }, &address); - log_ipv4ll(ll, "Picked new IP address %s.", strna(address)); - - return sd_ipv4ll_set_address(ll, &(struct in_addr) { addr }); -} - -#define MAC_HASH_KEY SD_ID128_MAKE(df,04,22,98,3f,ad,14,52,f9,87,2e,d1,9c,70,e2,f2) - -static int ipv4ll_start_internal(sd_ipv4ll *ll, bool reset_generation) { - int r; - bool picked_address = false; - - assert_return(ll, -EINVAL); - assert_return(!ether_addr_is_null(&ll->mac), -EINVAL); - - /* If no random seed is set, generate some from the MAC address */ - if (!ll->seed_set) - ll->seed.value = htole64(siphash24(ll->mac.ether_addr_octet, ETH_ALEN, MAC_HASH_KEY.bytes)); - - if (reset_generation) - ll->seed.generation = 0; - - if (ll->address == 0) { - r = ipv4ll_pick_address(ll); - if (r < 0) - return r; - - picked_address = true; - } - - r = sd_ipv4acd_start(ll->acd, reset_generation); - if (r < 0) { - - /* We couldn't start? If so, let's forget the picked address again, the user might make a change and - * retry, and we want the new data to take effect when picking an address. */ - if (picked_address) - ll->address = 0; - - return r; - } - - return 1; -} - -int sd_ipv4ll_start(sd_ipv4ll *ll) { - assert_return(ll, -EINVAL); - - if (sd_ipv4ll_is_running(ll)) - return 0; - - return ipv4ll_start_internal(ll, true); -} - -int sd_ipv4ll_restart(sd_ipv4ll *ll) { - ll->address = 0; - - return ipv4ll_start_internal(ll, false); -} - -static void ipv4ll_client_notify(sd_ipv4ll *ll, int event) { - assert(ll); - - if (ll->callback) - ll->callback(ll, event, ll->userdata); -} - -void ipv4ll_on_acd(sd_ipv4acd *acd, int event, void *userdata) { - sd_ipv4ll *ll = userdata; - IPV4LL_DONT_DESTROY(ll); - int r; - - assert(acd); - assert(ll); - - switch (event) { - - case SD_IPV4ACD_EVENT_STOP: - ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP); - ll->claimed_address = 0; - break; - - case SD_IPV4ACD_EVENT_BIND: - ll->claimed_address = ll->address; - ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_BIND); - break; - - case SD_IPV4ACD_EVENT_CONFLICT: - /* if an address was already bound we must call up to the - user to handle this, otherwise we just try again */ - if (ll->claimed_address != 0) { - ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_CONFLICT); - - ll->claimed_address = 0; - } else { - r = sd_ipv4ll_restart(ll); - if (r < 0) - goto error; - } - - break; - - default: - assert_not_reached(); - } - - return; - -error: - ipv4ll_client_notify(ll, SD_IPV4LL_EVENT_STOP); -} - -static int ipv4ll_check_mac(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata) { - sd_ipv4ll *ll = userdata; - - assert(ll); - - if (ll->check_mac_callback) - return ll->check_mac_callback(ll, mac, ll->check_mac_userdata); - - return 0; -} diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c index 8c24e7db63..a36eba9029 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.c @@ -109,20 +109,6 @@ int event_reset_time_relative( return event_reset_time(e, s, clock, usec_add(usec_now, usec), accuracy, callback, userdata, priority, description, force_reset); } -int event_source_disable(sd_event_source *s) { - if (!s) - return 0; - - return sd_event_source_set_enabled(s, SD_EVENT_OFF); -} - -int event_source_is_enabled(sd_event_source *s) { - if (!s) - return false; - - return sd_event_source_get_enabled(s, NULL); -} - int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata) { _cleanup_(sd_event_source_unrefp) sd_event_source *s = NULL; _cleanup_close_ int fd = -1; diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h index abd043bdcc..c185584412 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/event-util.h @@ -27,7 +27,8 @@ int event_reset_time_relative( int64_t priority, const char *description, bool force_reset); -int event_source_disable(sd_event_source *s); -int event_source_is_enabled(sd_event_source *s); +static inline int event_source_disable(sd_event_source *s) { + return sd_event_source_set_enabled(s, SD_EVENT_OFF); +} int event_add_time_change(sd_event *e, sd_event_source **ret, sd_event_io_handler_t callback, void *userdata); diff --git a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c index 4dbdf19872..cea1c009d6 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-event/sd-event.c @@ -13,6 +13,7 @@ #include "event-source.h" #include "fd-util.h" #include "fs-util.h" +#include "glyph-util.h" #include "hashmap.h" #include "list.h" #include "macro.h" @@ -405,7 +406,8 @@ _public_ int sd_event_new(sd_event** ret) { e->epoll_fd = fd_move_above_stdio(e->epoll_fd); if (secure_getenv("SD_EVENT_PROFILE_DELAYS")) { - log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 … 2^63 us will be logged every 5s."); + log_debug("Event loop profiling enabled. Logarithmic histogram of event loop iterations in the range 2^0 %s 2^63 us will be logged every 5s.", + special_glyph(SPECIAL_GLYPH_ELLIPSIS)); e->profile_delays = true; } @@ -706,6 +708,9 @@ static void event_unmask_signal_data(sd_event *e, struct signal_data *d, int sig return; } + if (event_pid_changed(e)) + return; + assert(d->fd >= 0); if (signalfd(d->fd, &d->sigset, SFD_NONBLOCK|SFD_CLOEXEC) < 0) @@ -851,6 +856,9 @@ static void source_disconnect(sd_event_source *s) { break; case SOURCE_CHILD: + if (event_pid_changed(s->event)) + s->child.process_owned = false; + if (s->child.pid > 0) { if (event_source_is_online(s)) { assert(s->event->n_online_child_sources > 0); @@ -1426,7 +1434,6 @@ _public_ int sd_event_add_child( return -ENOMEM; s->wakeup = WAKEUP_EVENT_SOURCE; - s->child.pid = pid; s->child.options = options; s->child.callback = callback; s->userdata = userdata; @@ -1436,7 +1443,7 @@ _public_ int sd_event_add_child( * pin the PID, and make regular waitid() handling race-free. */ if (shall_use_pidfd()) { - s->child.pidfd = pidfd_open(s->child.pid, 0); + s->child.pidfd = pidfd_open(pid, 0); if (s->child.pidfd < 0) { /* Propagate errors unless the syscall is not supported or blocked */ if (!ERRNO_IS_NOT_SUPPORTED(errno) && !ERRNO_IS_PRIVILEGE(errno)) @@ -1446,10 +1453,6 @@ _public_ int sd_event_add_child( } else s->child.pidfd = -1; - r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); - if (r < 0) - return r; - if (EVENT_SOURCE_WATCH_PIDFD(s)) { /* We have a pidfd and we only want to watch for exit */ r = source_child_pidfd_register(s, s->enabled); @@ -1465,6 +1468,12 @@ _public_ int sd_event_add_child( e->need_process_child = true; } + r = hashmap_put(e->child_sources, PID_TO_PTR(pid), s); + if (r < 0) + return r; + + /* These must be done after everything succeeds. */ + s->child.pid = pid; e->n_online_child_sources++; if (ret) @@ -1691,7 +1700,8 @@ static void event_free_inotify_data(sd_event *e, struct inotify_data *d) { assert_se(hashmap_remove(e->inotify_data, &d->priority) == d); if (d->fd >= 0) { - if (epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0) + if (!event_pid_changed(e) && + epoll_ctl(e->epoll_fd, EPOLL_CTL_DEL, d->fd, NULL) < 0) log_debug_errno(errno, "Failed to remove inotify fd from epoll, ignoring: %m"); safe_close(d->fd); @@ -1791,7 +1801,7 @@ static void event_free_inode_data( if (!d) return; - assert(!d->event_sources); + assert(LIST_IS_EMPTY(d->event_sources)); if (d->fd >= 0) { LIST_REMOVE(to_close, e->inode_data_to_close, d); @@ -1801,7 +1811,7 @@ static void event_free_inode_data( if (d->inotify_data) { if (d->wd >= 0) { - if (d->inotify_data->fd >= 0) { + if (d->inotify_data->fd >= 0 && !event_pid_changed(e)) { /* So here's a problem. At the time this runs the watch descriptor might already be * invalidated, because an IN_IGNORED event might be queued right the moment we enter * the syscall. Hence, whenever we get EINVAL, ignore it entirely, since it's a very @@ -1854,7 +1864,7 @@ static void event_gc_inode_data( if (!d) return; - if (d->event_sources) + if (!LIST_IS_EMPTY(d->event_sources)) return; inotify_data = d->inotify_data; @@ -2403,6 +2413,10 @@ fail: } _public_ int sd_event_source_get_enabled(sd_event_source *s, int *ret) { + /* Quick mode: the event source doesn't exist and we only want to query boolean enablement state. */ + if (!s && !ret) + return false; + assert_return(s, -EINVAL); assert_return(!event_pid_changed(s->event), -ECHILD); @@ -2580,8 +2594,13 @@ static int event_source_online( _public_ int sd_event_source_set_enabled(sd_event_source *s, int m) { int r; - assert_return(s, -EINVAL); assert_return(IN_SET(m, SD_EVENT_OFF, SD_EVENT_ON, SD_EVENT_ONESHOT), -EINVAL); + + /* Quick mode: if the source doesn't exist, SD_EVENT_OFF is a noop. */ + if (m == SD_EVENT_OFF && !s) + return 0; + + assert_return(s, -EINVAL); assert_return(!event_pid_changed(s->event), -ECHILD); /* If we are dead anyway, we are fine with turning off sources, but everything else needs to fail. */ @@ -3218,23 +3237,16 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori e->need_process_child = false; - /* - So, this is ugly. We iteratively invoke waitid() with P_PID - + WNOHANG for each PID we wait for, instead of using - P_ALL. This is because we only want to get child - information of very specific child processes, and not all - of them. We might not have processed the SIGCHLD even of a - previous invocation and we don't want to maintain a - unbounded *per-child* event queue, hence we really don't - want anything flushed out of the kernel's queue that we - don't care about. Since this is O(n) this means that if you - have a lot of processes you probably want to handle SIGCHLD - yourself. - - We do not reap the children here (by using WNOWAIT), this - is only done after the event source is dispatched so that - the callback still sees the process as a zombie. - */ + /* So, this is ugly. We iteratively invoke waitid() with P_PID + WNOHANG for each PID we wait + * for, instead of using P_ALL. This is because we only want to get child information of very + * specific child processes, and not all of them. We might not have processed the SIGCHLD event + * of a previous invocation and we don't want to maintain a unbounded *per-child* event queue, + * hence we really don't want anything flushed out of the kernel's queue that we don't care + * about. Since this is O(n) this means that if you have a lot of processes you probably want + * to handle SIGCHLD yourself. + * + * We do not reap the children here (by using WNOWAIT), this is only done after the event + * source is dispatched so that the callback still sees the process as a zombie. */ HASHMAP_FOREACH(s, e->child_sources) { assert(s->type == SOURCE_CHILD); @@ -3251,7 +3263,9 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori if (s->child.exited) continue; - if (EVENT_SOURCE_WATCH_PIDFD(s)) /* There's a usable pidfd known for this event source? then don't waitid() for it here */ + if (EVENT_SOURCE_WATCH_PIDFD(s)) + /* There's a usable pidfd known for this event source? Then don't waitid() for + * it here */ continue; zero(s->child.siginfo); @@ -3266,10 +3280,9 @@ static int process_child(sd_event *e, int64_t threshold, int64_t *ret_min_priori s->child.exited = true; if (!zombie && (s->child.options & WEXITED)) { - /* If the child isn't dead then let's - * immediately remove the state change - * from the queue, since there's no - * benefit in leaving it queued */ + /* If the child isn't dead then let's immediately remove the state + * change from the queue, since there's no benefit in leaving it + * queued. */ assert(s->child.options & (WSTOPPED|WCONTINUED)); (void) waitid(P_PID, s->child.pid, &s->child.siginfo, WNOHANG|(s->child.options & (WSTOPPED|WCONTINUED))); @@ -3324,19 +3337,16 @@ static int process_signal(sd_event *e, struct signal_data *d, uint32_t events, i assert_return(events == EPOLLIN, -EIO); assert(min_priority); - /* If there's a signal queued on this priority and SIGCHLD is - on this priority too, then make sure to recheck the - children we watch. This is because we only ever dequeue - the first signal per priority, and if we dequeue one, and - SIGCHLD might be enqueued later we wouldn't know, but we - might have higher priority children we care about hence we - need to check that explicitly. */ + /* If there's a signal queued on this priority and SIGCHLD is on this priority too, then make + * sure to recheck the children we watch. This is because we only ever dequeue the first signal + * per priority, and if we dequeue one, and SIGCHLD might be enqueued later we wouldn't know, + * but we might have higher priority children we care about hence we need to check that + * explicitly. */ if (sigismember(&d->sigset, SIGCHLD)) e->need_process_child = true; - /* If there's already an event source pending for this - * priority we don't read another */ + /* If there's already an event source pending for this priority we don't read another */ if (d->current) return 0; @@ -3875,7 +3885,7 @@ _public_ int sd_event_prepare(sd_event *e) { event_close_inode_data_fds(e); - if (event_next_pending(e) || e->need_process_child) + if (event_next_pending(e) || e->need_process_child || !LIST_IS_EMPTY(e->inotify_data_buffered)) goto pending; e->state = SD_EVENT_ARMED; @@ -3955,7 +3965,7 @@ static int process_epoll(sd_event *e, usec_t timeout, int64_t threshold, int64_t n_event_max = MALLOC_ELEMENTSOF(e->event_queue); /* If we still have inotify data buffered, then query the other fds, but don't wait on it */ - if (e->inotify_data_buffered) + if (!LIST_IS_EMPTY(e->inotify_data_buffered)) timeout = 0; for (;;) { diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c index e4a3bbd3eb..4f52c14f64 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.c @@ -25,9 +25,9 @@ bool id128_is_valid(const char *s) { for (i = 0; i < l; i++) { char c = s[i]; - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) + if (!ascii_isdigit(c) && + !(c >= 'a' && c <= 'f') && + !(c >= 'A' && c <= 'F')) return false; } @@ -42,9 +42,9 @@ bool id128_is_valid(const char *s) { if (c != '-') return false; } else { - if (!(c >= '0' && c <= '9') && - !(c >= 'a' && c <= 'z') && - !(c >= 'A' && c <= 'Z')) + if (!ascii_isdigit(c) && + !(c >= 'a' && c <= 'f') && + !(c >= 'A' && c <= 'F')) return false; } } @@ -206,19 +206,3 @@ int id128_get_product(sd_id128_t *ret) { *ret = uuid; return 0; } - -int id128_equal_string(const char *s, sd_id128_t id) { - sd_id128_t parsed; - int r; - - if (!s) - return false; - - /* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */ - - r = sd_id128_from_string(s, &parsed); - if (r < 0) - return r; - - return sd_id128_equal(parsed, id); -} diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h index 65a278c8ee..17b180c10c 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h +++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/id128-util.h @@ -34,5 +34,3 @@ extern const struct hash_ops id128_hash_ops; sd_id128_t id128_make_v4_uuid(sd_id128_t id); int id128_get_product(sd_id128_t *ret); - -int id128_equal_string(const char *s, sd_id128_t id); diff --git a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c index 09c3401ca1..709c8ffb57 100644 --- a/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c +++ b/src/libnm-systemd-core/src/libsystemd/sd-id128/sd-id128.c @@ -101,6 +101,22 @@ _public_ int sd_id128_from_string(const char s[], sd_id128_t *ret) { return 0; } +_public_ int sd_id128_string_equal(const char *s, sd_id128_t id) { + sd_id128_t parsed; + int r; + + if (!s) + return false; + + /* Checks if the specified string matches a valid string representation of the specified 128 bit ID/uuid */ + + r = sd_id128_from_string(s, &parsed); + if (r < 0) + return r; + + return sd_id128_equal(parsed, id); +} + _public_ int sd_id128_get_machine(sd_id128_t *ret) { static thread_local sd_id128_t saved_machine_id = {}; int r; @@ -256,7 +272,10 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) { /* We first check the environment. The environment variable is primarily relevant for user * services, and sufficiently safe as long as no privilege boundary is involved. */ r = get_invocation_from_environment(&saved_invocation_id); - if (r < 0 && r != -ENXIO) + if (r >= 0) { + *ret = saved_invocation_id; + return 0; + } else if (r != -ENXIO) return r; /* The kernel keyring is relevant for system services (as for user services we don't store @@ -272,13 +291,10 @@ _public_ int sd_id128_get_invocation(sd_id128_t *ret) { _public_ int sd_id128_randomize(sd_id128_t *ret) { sd_id128_t t; - int r; assert_return(ret, -EINVAL); - r = genuine_random_bytes(&t, sizeof(t), 0); - if (r < 0) - return r; + random_bytes(&t, sizeof(t)); /* Turn this into a valid v4 UUID, to be nice. Note that we * only guarantee this for newly generated UUIDs, not for diff --git a/src/libnm-systemd-core/src/systemd/_sd-common.h b/src/libnm-systemd-core/src/systemd/_sd-common.h index e121429640..38449463e2 100644 --- a/src/libnm-systemd-core/src/systemd/_sd-common.h +++ b/src/libnm-systemd-core/src/systemd/_sd-common.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ /* This is a private header; never even think of including this directly! */ diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h deleted file mode 100644 index 834f80b421..0000000000 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp-client.h +++ /dev/null @@ -1,345 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcpclienthfoo -#define foosddhcpclienthfoo - -/*** - Copyright © 2013 Intel Corporation. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "sd-dhcp-lease.h" -#include "sd-dhcp-option.h" -#include "sd-event.h" - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -enum { - SD_DHCP_CLIENT_EVENT_STOP = 0, - SD_DHCP_CLIENT_EVENT_IP_ACQUIRE = 1, - SD_DHCP_CLIENT_EVENT_IP_CHANGE = 2, - SD_DHCP_CLIENT_EVENT_EXPIRED = 3, - SD_DHCP_CLIENT_EVENT_RENEW = 4, - SD_DHCP_CLIENT_EVENT_SELECTING = 5, - SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE = 6, /* Sent when we have not received a reply after the first few attempts. - * The client may want to start acquiring link-local addresses. */ -}; - -/* https://www.iana.org/assignments/bootp-dhcp-parameters/bootp-dhcp-parameters.xhtml#options */ -enum { - SD_DHCP_OPTION_PAD = 0, /* [RFC2132] */ - SD_DHCP_OPTION_SUBNET_MASK = 1, /* [RFC2132] */ - SD_DHCP_OPTION_TIME_OFFSET = 2, /* [RFC2132], deprecated by 100 and 101 */ - SD_DHCP_OPTION_ROUTER = 3, /* [RFC2132] */ - SD_DHCP_OPTION_TIME_SERVER = 4, /* [RFC2132] */ - SD_DHCP_OPTION_NAME_SERVER = 5, /* [RFC2132] */ - SD_DHCP_OPTION_DOMAIN_NAME_SERVER = 6, /* [RFC2132] */ - SD_DHCP_OPTION_LOG_SERVER = 7, /* [RFC2132] */ - SD_DHCP_OPTION_QUOTES_SERVER = 8, /* [RFC2132] */ - SD_DHCP_OPTION_LPR_SERVER = 9, /* [RFC2132] */ - SD_DHCP_OPTION_IMPRESS_SERVER = 10, /* [RFC2132] */ - SD_DHCP_OPTION_RLP_SERVER = 11, /* [RFC2132] */ - SD_DHCP_OPTION_HOST_NAME = 12, /* [RFC2132] */ - SD_DHCP_OPTION_BOOT_FILE_SIZE = 13, /* [RFC2132] */ - SD_DHCP_OPTION_MERIT_DUMP_FILE = 14, /* [RFC2132] */ - SD_DHCP_OPTION_DOMAIN_NAME = 15, /* [RFC2132] */ - SD_DHCP_OPTION_SWAP_SERVER = 16, /* [RFC2132] */ - SD_DHCP_OPTION_ROOT_PATH = 17, /* [RFC2132] */ - SD_DHCP_OPTION_EXTENSION_FILE = 18, /* [RFC2132] */ - SD_DHCP_OPTION_FORWARD = 19, /* [RFC2132] */ - SD_DHCP_OPTION_SOURCE_ROUTE = 20, /* [RFC2132] */ - SD_DHCP_OPTION_POLICY_FILTER = 21, /* [RFC2132] */ - SD_DHCP_OPTION_MAX_DATAGRAM_ASSEMBLY = 22, /* [RFC2132] */ - SD_DHCP_OPTION_DEFAULT_IP_TTL = 23, /* [RFC2132] */ - SD_DHCP_OPTION_MTU_TIMEOUT = 24, /* [RFC2132] */ - SD_DHCP_OPTION_MTU_PLATEAU = 25, /* [RFC2132] */ - SD_DHCP_OPTION_MTU_INTERFACE = 26, /* [RFC2132] */ - SD_DHCP_OPTION_MTU_SUBNET = 27, /* [RFC2132] */ - SD_DHCP_OPTION_BROADCAST = 28, /* [RFC2132] */ - SD_DHCP_OPTION_MASK_DISCOVERY = 29, /* [RFC2132] */ - SD_DHCP_OPTION_MASK_SUPPLIER = 30, /* [RFC2132] */ - SD_DHCP_OPTION_ROUTER_DISCOVERY = 31, /* [RFC2132] */ - SD_DHCP_OPTION_ROUTER_REQUEST = 32, /* [RFC2132] */ - SD_DHCP_OPTION_STATIC_ROUTE = 33, /* [RFC2132] */ - SD_DHCP_OPTION_TRAILERS = 34, /* [RFC2132] */ - SD_DHCP_OPTION_ARP_TIMEOUT = 35, /* [RFC2132] */ - SD_DHCP_OPTION_ETHERNET = 36, /* [RFC2132] */ - SD_DHCP_OPTION_DEFAULT_TCP_TTL = 37, /* [RFC2132] */ - SD_DHCP_OPTION_KEEPALIVE_TIME = 38, /* [RFC2132] */ - SD_DHCP_OPTION_KEEPALIVE_DATA = 39, /* [RFC2132] */ - SD_DHCP_OPTION_NIS_DOMAIN = 40, /* [RFC2132] */ - SD_DHCP_OPTION_NIS_SERVER = 41, /* [RFC2132] */ - SD_DHCP_OPTION_NTP_SERVER = 42, /* [RFC2132] */ - SD_DHCP_OPTION_VENDOR_SPECIFIC = 43, /* [RFC2132] */ - SD_DHCP_OPTION_NETBIOS_NAME_SERVER = 44, /* [RFC2132] */ - SD_DHCP_OPTION_NETBIOS_DIST_SERVER = 45, /* [RFC2132] */ - SD_DHCP_OPTION_NETBIOS_NODE_TYPE = 46, /* [RFC2132] */ - SD_DHCP_OPTION_NETBIOS_SCOPE = 47, /* [RFC2132] */ - SD_DHCP_OPTION_X_WINDOW_FONT = 48, /* [RFC2132] */ - SD_DHCP_OPTION_X_WINDOW_MANAGER = 49, /* [RFC2132] */ - SD_DHCP_OPTION_REQUESTED_IP_ADDRESS = 50, /* [RFC2132] */ - SD_DHCP_OPTION_IP_ADDRESS_LEASE_TIME = 51, /* [RFC2132] */ - SD_DHCP_OPTION_OVERLOAD = 52, /* [RFC2132] */ - SD_DHCP_OPTION_MESSAGE_TYPE = 53, /* [RFC2132] */ - SD_DHCP_OPTION_SERVER_IDENTIFIER = 54, /* [RFC2132] */ - SD_DHCP_OPTION_PARAMETER_REQUEST_LIST = 55, /* [RFC2132] */ - SD_DHCP_OPTION_ERROR_MESSAGE = 56, /* [RFC2132] */ - SD_DHCP_OPTION_MAXIMUM_MESSAGE_SIZE = 57, /* [RFC2132] */ - SD_DHCP_OPTION_RENEWAL_TIME = 58, /* [RFC2132] */ - SD_DHCP_OPTION_REBINDING_TIME = 59, /* [RFC2132] */ - SD_DHCP_OPTION_VENDOR_CLASS_IDENTIFIER = 60, /* [RFC2132] */ - SD_DHCP_OPTION_CLIENT_IDENTIFIER = 61, /* [RFC2132] */ - SD_DHCP_OPTION_NETWARE_IP_DOMAIN = 62, /* [RFC2242] */ - SD_DHCP_OPTION_NETWARE_IP_OPTION = 63, /* [RFC2242] */ - SD_DHCP_OPTION_NIS_DOMAIN_NAME = 64, /* [RFC2132] */ - SD_DHCP_OPTION_NIS_SERVER_ADDR = 65, /* [RFC2132] */ - SD_DHCP_OPTION_BOOT_SERVER_NAME = 66, /* [RFC2132] */ - SD_DHCP_OPTION_BOOT_FILENAME = 67, /* [RFC2132] */ - SD_DHCP_OPTION_HOME_AGENT_ADDRESSES = 68, /* [RFC2132] */ - SD_DHCP_OPTION_SMTP_SERVER = 69, /* [RFC2132] */ - SD_DHCP_OPTION_POP3_SERVER = 70, /* [RFC2132] */ - SD_DHCP_OPTION_NNTP_SERVER = 71, /* [RFC2132] */ - SD_DHCP_OPTION_WWW_SERVER = 72, /* [RFC2132] */ - SD_DHCP_OPTION_FINGER_SERVER = 73, /* [RFC2132] */ - SD_DHCP_OPTION_IRC_SERVER = 74, /* [RFC2132] */ - SD_DHCP_OPTION_STREETTALK_SERVER = 75, /* [RFC2132] */ - SD_DHCP_OPTION_STDA_SERVER = 76, /* [RFC2132] */ - SD_DHCP_OPTION_USER_CLASS = 77, /* [RFC3004] */ - SD_DHCP_OPTION_DIRECTORY_AGENT = 78, /* [RFC2610] */ - SD_DHCP_OPTION_SERVICE_SCOPE = 79, /* [RFC2610] */ - SD_DHCP_OPTION_RAPID_COMMIT = 80, /* [RFC4039] */ - SD_DHCP_OPTION_FQDN = 81, /* [RFC4702] */ - SD_DHCP_OPTION_RELAY_AGENT_INFORMATION = 82, /* [RFC3046] */ - SD_DHCP_OPTION_ISNS = 83, /* [RFC4174] */ - /* option code 84 is unassigned [RFC3679] */ - SD_DHCP_OPTION_NDS_SERVER = 85, /* [RFC2241] */ - SD_DHCP_OPTION_NDS_TREE_NAME = 86, /* [RFC2241] */ - SD_DHCP_OPTION_NDS_CONTEXT = 87, /* [RFC2241] */ - SD_DHCP_OPTION_BCMCS_CONTROLLER_DOMAIN_NAM = 88, /* [RFC4280] */ - SD_DHCP_OPTION_BCMCS_CONTROLLER_ADDRESS = 89, /* [RFC4280] */ - SD_DHCP_OPTION_AUTHENTICATION = 90, /* [RFC3118] */ - SD_DHCP_OPTION_CLIENT_LAST_TRANSACTION_TIME = 91, /* [RFC4388] */ - SD_DHCP_OPTION_ASSOCIATED_IP = 92, /* [RFC4388] */ - SD_DHCP_OPTION_CLIENT_SYSTEM = 93, /* [RFC4578] */ - SD_DHCP_OPTION_CLIENT_NDI = 94, /* [RFC4578] */ - SD_DHCP_OPTION_LDAP = 95, /* [RFC3679] */ - /* option code 96 is unassigned [RFC3679] */ - SD_DHCP_OPTION_UUID = 97, /* [RFC4578] */ - SD_DHCP_OPTION_USER_AUTHENTICATION = 98, /* [RFC2485] */ - SD_DHCP_OPTION_GEOCONF_CIVIC = 99, /* [RFC4776] */ - SD_DHCP_OPTION_POSIX_TIMEZONE = 100, /* [RFC4833] */ - SD_DHCP_OPTION_TZDB_TIMEZONE = 101, /* [RFC4833] */ - /* option codes 102-107 are unassigned [RFC3679] */ - SD_DHCP_OPTION_IPV6_ONLY_PREFERRED = 108, /* [RFC8925] */ - SD_DHCP_OPTION_DHCP4O6_SOURCE_ADDRESS = 109, /* [RFC8539] */ - /* option codes 110-111 are unassigned [RFC3679] */ - SD_DHCP_OPTION_NETINFO_ADDRESS = 112, /* [RFC3679] */ - SD_DHCP_OPTION_NETINFO_TAG = 113, /* [RFC3679] */ - SD_DHCP_OPTION_DHCP_CAPTIVE_PORTAL = 114, /* [RFC8910] */ - /* option code 115 is unassigned [RFC3679] */ - SD_DHCP_OPTION_AUTO_CONFIG = 116, /* [RFC2563] */ - SD_DHCP_OPTION_NAME_SERVICE_SEARCH = 117, /* [RFC2937] */ - SD_DHCP_OPTION_SUBNET_SELECTION = 118, /* [RFC3011] */ - SD_DHCP_OPTION_DOMAIN_SEARCH = 119, /* [RFC3397] */ - SD_DHCP_OPTION_SIP_SERVER = 120, /* [RFC3361] */ - SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE = 121, /* [RFC3442] */ - SD_DHCP_OPTION_CABLELABS_CLIENT_CONFIGURATION = 122, /* [RFC3495] */ - SD_DHCP_OPTION_GEOCONF = 123, /* [RFC6225] */ - SD_DHCP_OPTION_VENDOR_CLASS = 124, /* [RFC3925] */ - SD_DHCP_OPTION_VENDOR_SPECIFIC_INFORMATION = 125, /* [RFC3925] */ - /* option codes 126-127 are unassigned [RFC3679] */ - /* option codes 128-135 are assigned to use by PXE, but they are vendor specific [RFC4578] */ - SD_DHCP_OPTION_PANA_AGENT = 136, /* [RFC5192] */ - SD_DHCP_OPTION_LOST_SERVER_FQDN = 137, /* [RFC5223] */ - SD_DHCP_OPTION_CAPWAP_AC_ADDRESS = 138, /* [RFC5417] */ - SD_DHCP_OPTION_MOS_ADDRESS = 139, /* [RFC5678] */ - SD_DHCP_OPTION_MOS_FQDN = 140, /* [RFC5678] */ - SD_DHCP_OPTION_SIP_SERVICE_DOMAINS = 141, /* [RFC6011] */ - SD_DHCP_OPTION_ANDSF_ADDRESS = 142, /* [RFC6153] */ - SD_DHCP_OPTION_SZTP_REDIRECT = 143, /* [RFC8572] */ - SD_DHCP_OPTION_GEOLOC = 144, /* [RFC6225] */ - SD_DHCP_OPTION_FORCERENEW_NONCE_CAPABLE = 145, /* [RFC6704] */ - SD_DHCP_OPTION_RDNSS_SELECTION = 146, /* [RFC6731] */ - SD_DHCP_OPTION_DOTS_RI = 147, /* [RFC8973] */ - SD_DHCP_OPTION_DOTS_ADDRESS = 148, /* [RFC8973] */ - /* option code 149 is unassigned [RFC3942] */ - SD_DHCP_OPTION_TFTP_SERVER_ADDRESS = 150, /* [RFC5859] */ - SD_DHCP_OPTION_STATUS_CODE = 151, /* [RFC6926] */ - SD_DHCP_OPTION_BASE_TIME = 152, /* [RFC6926] */ - SD_DHCP_OPTION_START_TIME_OF_STATE = 153, /* [RFC6926] */ - SD_DHCP_OPTION_QUERY_START_TIME = 154, /* [RFC6926] */ - SD_DHCP_OPTION_QUERY_END_TIME = 155, /* [RFC6926] */ - SD_DHCP_OPTION_DHCP_STATE = 156, /* [RFC6926] */ - SD_DHCP_OPTION_DATA_SOURCE = 157, /* [RFC6926] */ - SD_DHCP_OPTION_PCP_SERVER = 158, /* [RFC7291] */ - SD_DHCP_OPTION_PORT_PARAMS = 159, /* [RFC7618] */ - /* option code 160 is unassigned [RFC7710][RFC8910] */ - SD_DHCP_OPTION_MUD_URL = 161, /* [RFC8520] */ - /* option codes 162-174 are unassigned [RFC3942] */ - /* option codes 175-177 are temporary assigned. */ - /* option codes 178-207 are unassigned [RFC3942] */ - SD_DHCP_OPTION_PXELINUX_MAGIC = 208, /* [RFC5071] Deprecated */ - SD_DHCP_OPTION_CONFIGURATION_FILE = 209, /* [RFC5071] */ - SD_DHCP_OPTION_PATH_PREFIX = 210, /* [RFC5071] */ - SD_DHCP_OPTION_REBOOT_TIME = 211, /* [RFC5071] */ - SD_DHCP_OPTION_6RD = 212, /* [RFC5969] */ - SD_DHCP_OPTION_ACCESS_DOMAIN = 213, /* [RFC5986] */ - /* option codes 214-219 are unassigned */ - SD_DHCP_OPTION_SUBNET_ALLOCATION = 220, /* [RFC6656] */ - SD_DHCP_OPTION_VIRTUAL_SUBNET_SELECTION = 221, /* [RFC6607] */ - /* option codes 222-223 are unassigned [RFC3942] */ - /* option codes 224-254 are reserved for private use */ - SD_DHCP_OPTION_PRIVATE_BASE = 224, - SD_DHCP_OPTION_PRIVATE_CLASSLESS_STATIC_ROUTE = 249, /* [RFC7844] */ - SD_DHCP_OPTION_PRIVATE_PROXY_AUTODISCOVERY = 252, /* [RFC7844] */ - SD_DHCP_OPTION_PRIVATE_LAST = 254, - SD_DHCP_OPTION_END = 255, /* [RFC2132] */ -}; - -/* Suboptions for SD_DHCP_OPTION_RELAY_AGENT_INFORMATION option */ -enum { - SD_DHCP_RELAY_AGENT_CIRCUIT_ID = 1, - SD_DHCP_RELAY_AGENT_REMOTE_ID = 2, -}; - -typedef struct sd_dhcp_client sd_dhcp_client; - -typedef int (*sd_dhcp_client_callback_t)(sd_dhcp_client *client, int event, void *userdata); -int sd_dhcp_client_set_callback( - sd_dhcp_client *client, - sd_dhcp_client_callback_t cb, - void *userdata); - -int sd_dhcp_client_set_request_option( - sd_dhcp_client *client, - uint8_t option); -int sd_dhcp_client_set_request_address( - sd_dhcp_client *client, - const struct in_addr *last_address); -int sd_dhcp_client_set_request_broadcast( - sd_dhcp_client *client, - int broadcast); -int sd_dhcp_client_set_ifindex( - sd_dhcp_client *client, - int interface_index); -int sd_dhcp_client_set_ifname( - sd_dhcp_client *client, - const char *interface_name); -int sd_dhcp_client_get_ifname(sd_dhcp_client *client, const char **ret); -int sd_dhcp_client_set_mac( - sd_dhcp_client *client, - const uint8_t *addr, - const uint8_t *bcast_addr, - size_t addr_len, - uint16_t arp_type); -int sd_dhcp_client_set_client_id( - sd_dhcp_client *client, - uint8_t type, - const uint8_t *data, - size_t data_len); -int sd_dhcp_client_set_iaid_duid( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint16_t duid_type, - const void *duid, - size_t duid_len); -int sd_dhcp_client_set_iaid_duid_llt( - sd_dhcp_client *client, - bool iaid_set, - uint32_t iaid, - uint64_t llt_time); -int sd_dhcp_client_set_duid( - sd_dhcp_client *client, - uint16_t duid_type, - const void *duid, - size_t duid_len); -int sd_dhcp_client_set_duid_llt( - sd_dhcp_client *client, - uint64_t llt_time); -int sd_dhcp_client_get_client_id( - sd_dhcp_client *client, - uint8_t *type, - const uint8_t **data, - size_t *data_len); -int sd_dhcp_client_set_mtu( - sd_dhcp_client *client, - uint32_t mtu); -int sd_dhcp_client_set_max_attempts( - sd_dhcp_client *client, - uint64_t attempt); -int sd_dhcp_client_set_client_port( - sd_dhcp_client *client, - uint16_t port); -int sd_dhcp_client_set_hostname( - sd_dhcp_client *client, - const char *hostname); -int sd_dhcp_client_set_vendor_class_identifier( - sd_dhcp_client *client, - const char *vci); -int sd_dhcp_client_set_mud_url( - sd_dhcp_client *client, - const char *mudurl); -int sd_dhcp_client_set_user_class( - sd_dhcp_client *client, - char * const *user_class); -int sd_dhcp_client_get_lease( - sd_dhcp_client *client, - sd_dhcp_lease **ret); -int sd_dhcp_client_set_service_type( - sd_dhcp_client *client, - int type); -int sd_dhcp_client_set_fallback_lease_lifetime( - sd_dhcp_client *client, - uint32_t fallback_lease_lifetime); - -int sd_dhcp_client_add_option(sd_dhcp_client *client, sd_dhcp_option *v); -int sd_dhcp_client_add_vendor_option(sd_dhcp_client *client, sd_dhcp_option *v); - -int sd_dhcp_client_is_running(sd_dhcp_client *client); -int sd_dhcp_client_stop(sd_dhcp_client *client); -int sd_dhcp_client_start(sd_dhcp_client *client); -int sd_dhcp_client_send_release(sd_dhcp_client *client); -int sd_dhcp_client_send_decline(sd_dhcp_client *client); -int sd_dhcp_client_send_renew(sd_dhcp_client *client); - -sd_dhcp_client *sd_dhcp_client_ref(sd_dhcp_client *client); -sd_dhcp_client *sd_dhcp_client_unref(sd_dhcp_client *client); - -/* NOTE: anonymize parameter is used to initialize PRL memory with different - * options when using RFC7844 Anonymity Profiles */ -int sd_dhcp_client_new(sd_dhcp_client **ret, int anonymize); - -int sd_dhcp_client_id_to_string(const void *data, size_t len, char **ret); - -int sd_dhcp_client_attach_event( - sd_dhcp_client *client, - sd_event *event, - int64_t priority); -int sd_dhcp_client_detach_event(sd_dhcp_client *client); -sd_event *sd_dhcp_client_get_event(sd_dhcp_client *client); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_client, sd_dhcp_client_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h deleted file mode 100644 index 578ac6d4db..0000000000 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp-lease.h +++ /dev/null @@ -1,91 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcpleasehfoo -#define foosddhcpleasehfoo - -/*** - Copyright © 2013 Intel Corporation. All rights reserved. - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include -#include -#include - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -typedef struct sd_dhcp_lease sd_dhcp_lease; -typedef struct sd_dhcp_route sd_dhcp_route; - -sd_dhcp_lease *sd_dhcp_lease_ref(sd_dhcp_lease *lease); -sd_dhcp_lease *sd_dhcp_lease_unref(sd_dhcp_lease *lease); - -typedef enum sd_dhcp_lease_server_type_t { - SD_DHCP_LEASE_DNS, - SD_DHCP_LEASE_NTP, - SD_DHCP_LEASE_SIP, - SD_DHCP_LEASE_POP3, - SD_DHCP_LEASE_SMTP, - SD_DHCP_LEASE_LPR, - _SD_DHCP_LEASE_SERVER_TYPE_MAX, - _SD_DHCP_LEASE_SERVER_TYPE_INVALID = -EINVAL, - _SD_ENUM_FORCE_S64(DHCP_LEASE_SERVER_TYPE), -} sd_dhcp_lease_server_type_t; - -int sd_dhcp_lease_get_address(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_lifetime(sd_dhcp_lease *lease, uint32_t *lifetime); -int sd_dhcp_lease_get_t1(sd_dhcp_lease *lease, uint32_t *t1); -int sd_dhcp_lease_get_t2(sd_dhcp_lease *lease, uint32_t *t2); -int sd_dhcp_lease_get_broadcast(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_netmask(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_router(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_next_server(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_server_identifier(sd_dhcp_lease *lease, struct in_addr *addr); -int sd_dhcp_lease_get_servers(sd_dhcp_lease *lease, sd_dhcp_lease_server_type_t what, const struct in_addr **addr); -int sd_dhcp_lease_get_dns(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_ntp(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_sip(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_pop3(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_smtp(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_lpr(sd_dhcp_lease *lease, const struct in_addr **addr); -int sd_dhcp_lease_get_mtu(sd_dhcp_lease *lease, uint16_t *mtu); -int sd_dhcp_lease_get_domainname(sd_dhcp_lease *lease, const char **domainname); -int sd_dhcp_lease_get_search_domains(sd_dhcp_lease *lease, char ***domains); -int sd_dhcp_lease_get_hostname(sd_dhcp_lease *lease, const char **hostname); -int sd_dhcp_lease_get_root_path(sd_dhcp_lease *lease, const char **root_path); -int sd_dhcp_lease_get_static_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret); -int sd_dhcp_lease_get_classless_routes(sd_dhcp_lease *lease, sd_dhcp_route ***ret); -int sd_dhcp_lease_get_vendor_specific(sd_dhcp_lease *lease, const void **data, size_t *data_len); -int sd_dhcp_lease_get_client_id(sd_dhcp_lease *lease, const void **client_id, size_t *client_id_len); -int sd_dhcp_lease_get_timezone(sd_dhcp_lease *lease, const char **timezone); -int sd_dhcp_lease_get_6rd( - sd_dhcp_lease *lease, - uint8_t *ret_ipv4masklen, - uint8_t *ret_prefixlen, - struct in6_addr *ret_prefix, - const struct in_addr **ret_br_addresses, - size_t *ret_n_br_addresses); - -int sd_dhcp_route_get_destination(sd_dhcp_route *route, struct in_addr *destination); -int sd_dhcp_route_get_destination_prefix_length(sd_dhcp_route *route, uint8_t *length); -int sd_dhcp_route_get_gateway(sd_dhcp_route *route, struct in_addr *gateway); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_lease, sd_dhcp_lease_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp-option.h b/src/libnm-systemd-core/src/systemd/sd-dhcp-option.h deleted file mode 100644 index 71aa479b5e..0000000000 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp-option.h +++ /dev/null @@ -1,38 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosddhcpoptionhfoo -#define foosddhcpoptionhfoo - -/*** - Copyright © 2013 Intel Corporation. All rights reserved. - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -typedef struct sd_dhcp_option sd_dhcp_option; - -int sd_dhcp_option_new(uint8_t option, const void *data, size_t length, sd_dhcp_option **ret); -sd_dhcp_option *sd_dhcp_option_ref(sd_dhcp_option *ra); -sd_dhcp_option *sd_dhcp_option_unref(sd_dhcp_option *ra); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_dhcp_option, sd_dhcp_option_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h index d89b7d1c83..7fe60c356c 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-client.h @@ -16,7 +16,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -36,7 +36,7 @@ enum { SD_DHCP6_CLIENT_EVENT_RESEND_EXPIRE = 10, SD_DHCP6_CLIENT_EVENT_RETRANS_MAX = 11, SD_DHCP6_CLIENT_EVENT_IP_ACQUIRE = 12, - SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13, + SD_DHCP6_CLIENT_EVENT_INFORMATION_REQUEST = 13 }; /* https://www.iana.org/assignments/dhcpv6-parameters/dhcpv6-parameters.xhtml#dhcpv6-parameters-2 */ @@ -63,15 +63,15 @@ enum { SD_DHCP6_OPTION_RECONF_ACCEPT = 20, /* RFC 8415 */ SD_DHCP6_OPTION_SIP_SERVER_DOMAIN_NAME = 21, /* RFC 3319 */ SD_DHCP6_OPTION_SIP_SERVER_ADDRESS = 22, /* RFC 3319 */ - SD_DHCP6_OPTION_DNS_SERVERS = 23, /* RFC 3646 */ - SD_DHCP6_OPTION_DOMAIN_LIST = 24, /* RFC 3646 */ + SD_DHCP6_OPTION_DNS_SERVER = 23, /* RFC 3646 */ + SD_DHCP6_OPTION_DOMAIN = 24, /* RFC 3646 */ SD_DHCP6_OPTION_IA_PD = 25, /* RFC 3633, RFC 8415 */ SD_DHCP6_OPTION_IA_PD_PREFIX = 26, /* RFC 3633, RFC 8415 */ - SD_DHCP6_OPTION_NIS_SERVERS = 27, /* RFC 3898 */ - SD_DHCP6_OPTION_NISP_SERVERS = 28, /* RFC 3898 */ + SD_DHCP6_OPTION_NIS_SERVER = 27, /* RFC 3898 */ + SD_DHCP6_OPTION_NISP_SERVER = 28, /* RFC 3898 */ SD_DHCP6_OPTION_NIS_DOMAIN_NAME = 29, /* RFC 3898 */ SD_DHCP6_OPTION_NISP_DOMAIN_NAME = 30, /* RFC 3898 */ - SD_DHCP6_OPTION_SNTP_SERVERS = 31, /* RFC 4075, deprecated */ + SD_DHCP6_OPTION_SNTP_SERVER = 31, /* RFC 4075, deprecated */ SD_DHCP6_OPTION_INFORMATION_REFRESH_TIME = 32, /* RFC 4242, 8415, sec. 21.23 */ SD_DHCP6_OPTION_BCMCS_SERVER_D = 33, /* RFC 4280 */ SD_DHCP6_OPTION_BCMCS_SERVER_A = 34, /* RFC 4280 */ @@ -183,7 +183,7 @@ enum { SD_DHCP6_OPTION_SLAP_QUAD = 140, /* RFC 8948 */ SD_DHCP6_OPTION_V6_DOTS_RI = 141, /* RFC 8973 */ SD_DHCP6_OPTION_V6_DOTS_ADDRESS = 142, /* RFC 8973 */ - SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143, /* RFC 6153 */ + SD_DHCP6_OPTION_IPV6_ADDRESS_ANDSF = 143 /* RFC 6153 */ /* option codes 144-65535 are unassigned */ }; diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h index 472276def1..716f6fc17c 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-lease.h @@ -16,7 +16,7 @@ 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 . + along with systemd; If not, see . ***/ #include diff --git a/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h b/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h index ddb2c7cecd..b4b4671e4a 100644 --- a/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h +++ b/src/libnm-systemd-core/src/systemd/sd-dhcp6-option.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include diff --git a/src/libnm-systemd-core/src/systemd/sd-event.h b/src/libnm-systemd-core/src/systemd/sd-event.h index 63984eef15..e782339c4a 100644 --- a/src/libnm-systemd-core/src/systemd/sd-event.h +++ b/src/libnm-systemd-core/src/systemd/sd-event.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include diff --git a/src/libnm-systemd-core/src/systemd/sd-id128.h b/src/libnm-systemd-core/src/systemd/sd-id128.h index f7d3244bb3..3303c374ce 100644 --- a/src/libnm-systemd-core/src/systemd/sd-id128.h +++ b/src/libnm-systemd-core/src/systemd/sd-id128.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -116,9 +116,11 @@ int sd_id128_get_boot_app_specific(sd_id128_t app_id, sd_id128_t *ret); #a #b #c #d "-" #e #f "-" #g #h "-" #i #j "-" #k #l #m #n #o #p _sd_pure_ static __inline__ int sd_id128_equal(sd_id128_t a, sd_id128_t b) { - return memcmp(&a, &b, 16) == 0; + return a.qwords[0] == b.qwords[0] && a.qwords[1] == b.qwords[1]; } +int sd_id128_string_equal(const char *s, sd_id128_t id); + _sd_pure_ static __inline__ int sd_id128_is_null(sd_id128_t a) { return a.qwords[0] == 0 && a.qwords[1] == 0; } diff --git a/src/libnm-systemd-core/src/systemd/sd-ipv4acd.h b/src/libnm-systemd-core/src/systemd/sd-ipv4acd.h deleted file mode 100644 index 90d3f0a0d1..0000000000 --- a/src/libnm-systemd-core/src/systemd/sd-ipv4acd.h +++ /dev/null @@ -1,63 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdipv4acdfoo -#define foosdipv4acdfoo - -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include -#include - -#include "sd-event.h" - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -enum { - SD_IPV4ACD_EVENT_STOP = 0, - SD_IPV4ACD_EVENT_BIND = 1, - SD_IPV4ACD_EVENT_CONFLICT = 2, -}; - -typedef struct sd_ipv4acd sd_ipv4acd; -typedef void (*sd_ipv4acd_callback_t)(sd_ipv4acd *acd, int event, void *userdata); -typedef int (*sd_ipv4acd_check_mac_callback_t)(sd_ipv4acd *acd, const struct ether_addr *mac, void *userdata); - -int sd_ipv4acd_detach_event(sd_ipv4acd *acd); -int sd_ipv4acd_attach_event(sd_ipv4acd *acd, sd_event *event, int64_t priority); -int sd_ipv4acd_get_address(sd_ipv4acd *acd, struct in_addr *address); -int sd_ipv4acd_set_callback(sd_ipv4acd *acd, sd_ipv4acd_callback_t cb, void *userdata); -int sd_ipv4acd_set_check_mac_callback(sd_ipv4acd *acd, sd_ipv4acd_check_mac_callback_t cb, void *userdata); -int sd_ipv4acd_set_mac(sd_ipv4acd *acd, const struct ether_addr *addr); -int sd_ipv4acd_set_ifindex(sd_ipv4acd *acd, int interface_index); -int sd_ipv4acd_get_ifindex(sd_ipv4acd *acd); -int sd_ipv4acd_set_ifname(sd_ipv4acd *acd, const char *interface_name); -int sd_ipv4acd_get_ifname(sd_ipv4acd *acd, const char **ret); -int sd_ipv4acd_set_address(sd_ipv4acd *acd, const struct in_addr *address); -int sd_ipv4acd_is_running(sd_ipv4acd *acd); -int sd_ipv4acd_start(sd_ipv4acd *acd, bool reset_conflicts); -int sd_ipv4acd_stop(sd_ipv4acd *acd); -sd_ipv4acd *sd_ipv4acd_ref(sd_ipv4acd *acd); -sd_ipv4acd *sd_ipv4acd_unref(sd_ipv4acd *acd); -int sd_ipv4acd_new(sd_ipv4acd **ret); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4acd, sd_ipv4acd_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/libnm-systemd-core/src/systemd/sd-ipv4ll.h b/src/libnm-systemd-core/src/systemd/sd-ipv4ll.h deleted file mode 100644 index ed014b53f2..0000000000 --- a/src/libnm-systemd-core/src/systemd/sd-ipv4ll.h +++ /dev/null @@ -1,65 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#ifndef foosdipv4llfoo -#define foosdipv4llfoo - -/*** - Copyright © 2014 Axis Communications AB. All rights reserved. - - systemd is free software; you can redistribute it and/or modify it - under the terms of the GNU Lesser General Public License as published by - the Free Software Foundation; either version 2.1 of the License, or - (at your option) any later version. - - systemd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public License - along with systemd; If not, see . -***/ - -#include -#include - -#include "sd-event.h" - -#include "_sd-common.h" - -_SD_BEGIN_DECLARATIONS; - -enum { - SD_IPV4LL_EVENT_STOP = 0, - SD_IPV4LL_EVENT_BIND = 1, - SD_IPV4LL_EVENT_CONFLICT = 2, -}; - -typedef struct sd_ipv4ll sd_ipv4ll; -typedef void (*sd_ipv4ll_callback_t)(sd_ipv4ll *ll, int event, void *userdata); -typedef int (*sd_ipv4ll_check_mac_callback_t)(sd_ipv4ll *ll, const struct ether_addr *mac, void *userdata); - -int sd_ipv4ll_detach_event(sd_ipv4ll *ll); -int sd_ipv4ll_attach_event(sd_ipv4ll *ll, sd_event *event, int64_t priority); -int sd_ipv4ll_get_address(sd_ipv4ll *ll, struct in_addr *address); -int sd_ipv4ll_set_callback(sd_ipv4ll *ll, sd_ipv4ll_callback_t cb, void *userdata); -int sd_ipv4ll_set_check_mac_callback(sd_ipv4ll *ll, sd_ipv4ll_check_mac_callback_t cb, void *userdata); -int sd_ipv4ll_set_mac(sd_ipv4ll *ll, const struct ether_addr *addr); -int sd_ipv4ll_set_ifindex(sd_ipv4ll *ll, int interface_index); -int sd_ipv4ll_get_ifindex(sd_ipv4ll *ll); -int sd_ipv4ll_set_ifname(sd_ipv4ll *ll, const char *interface_name); -int sd_ipv4ll_get_ifname(sd_ipv4ll *ll, const char **ret); -int sd_ipv4ll_set_address(sd_ipv4ll *ll, const struct in_addr *address); -int sd_ipv4ll_set_address_seed(sd_ipv4ll *ll, uint64_t seed); -int sd_ipv4ll_is_running(sd_ipv4ll *ll); -int sd_ipv4ll_restart(sd_ipv4ll *ll); -int sd_ipv4ll_start(sd_ipv4ll *ll); -int sd_ipv4ll_stop(sd_ipv4ll *ll); -sd_ipv4ll *sd_ipv4ll_ref(sd_ipv4ll *ll); -sd_ipv4ll *sd_ipv4ll_unref(sd_ipv4ll *ll); -int sd_ipv4ll_new(sd_ipv4ll **ret); - -_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_ipv4ll, sd_ipv4ll_unref); - -_SD_END_DECLARATIONS; - -#endif diff --git a/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h b/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h index bfeac14ce3..504d7f59c1 100644 --- a/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h +++ b/src/libnm-systemd-core/src/systemd/sd-lldp-rx.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -32,14 +32,14 @@ _SD_BEGIN_DECLARATIONS; typedef struct sd_lldp_rx sd_lldp_rx; typedef struct sd_lldp_neighbor sd_lldp_neighbor; -typedef enum sd_lldp_rx_event_t { +__extension__ typedef enum sd_lldp_rx_event_t { SD_LLDP_RX_EVENT_ADDED, SD_LLDP_RX_EVENT_REMOVED, SD_LLDP_RX_EVENT_UPDATED, SD_LLDP_RX_EVENT_REFRESHED, _SD_LLDP_RX_EVENT_MAX, _SD_LLDP_RX_EVENT_INVALID = -EINVAL, - _SD_ENUM_FORCE_S64(LLDP_RX_EVENT), + _SD_ENUM_FORCE_S64(LLDP_RX_EVENT) } sd_lldp_rx_event_t; typedef void (*sd_lldp_rx_callback_t)(sd_lldp_rx *lldp_rx, sd_lldp_rx_event_t event, sd_lldp_neighbor *n, void *userdata); diff --git a/src/libnm-systemd-core/src/systemd/sd-lldp.h b/src/libnm-systemd-core/src/systemd/sd-lldp.h index c32d789476..4069c5b299 100644 --- a/src/libnm-systemd-core/src/systemd/sd-lldp.h +++ b/src/libnm-systemd-core/src/systemd/sd-lldp.h @@ -14,7 +14,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -34,7 +34,7 @@ enum { SD_LLDP_TYPE_SYSTEM_DESCRIPTION = 6, SD_LLDP_TYPE_SYSTEM_CAPABILITIES = 7, SD_LLDP_TYPE_MGMT_ADDRESS = 8, - SD_LLDP_TYPE_PRIVATE = 127, + SD_LLDP_TYPE_PRIVATE = 127 }; /* IEEE 802.1AB-2009 Clause 8.5.2: Chassis subtypes */ @@ -46,7 +46,7 @@ enum { SD_LLDP_CHASSIS_SUBTYPE_MAC_ADDRESS = 4, SD_LLDP_CHASSIS_SUBTYPE_NETWORK_ADDRESS = 5, SD_LLDP_CHASSIS_SUBTYPE_INTERFACE_NAME = 6, - SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7, + SD_LLDP_CHASSIS_SUBTYPE_LOCALLY_ASSIGNED = 7 }; /* IEEE 802.1AB-2009 Clause 8.5.3: Port subtype */ @@ -58,7 +58,7 @@ enum { SD_LLDP_PORT_SUBTYPE_NETWORK_ADDRESS = 4, SD_LLDP_PORT_SUBTYPE_INTERFACE_NAME = 5, SD_LLDP_PORT_SUBTYPE_AGENT_CIRCUIT_ID = 6, - SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7, + SD_LLDP_PORT_SUBTYPE_LOCALLY_ASSIGNED = 7 }; /* IEEE 802.1AB-2009 Clause 8.5.8: System capabilities */ @@ -73,7 +73,7 @@ enum { SD_LLDP_SYSTEM_CAPABILITIES_STATION = 1 << 7, SD_LLDP_SYSTEM_CAPABILITIES_CVLAN = 1 << 8, SD_LLDP_SYSTEM_CAPABILITIES_SVLAN = 1 << 9, - SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10, + SD_LLDP_SYSTEM_CAPABILITIES_TPMR = 1 << 10 }; #define SD_LLDP_SYSTEM_CAPABILITIES_ALL UINT16_MAX @@ -107,7 +107,7 @@ enum { SD_LLDP_OUI_802_1_SUBTYPE_PROTOCOL_IDENTITY = 4, SD_LLDP_OUI_802_1_SUBTYPE_VID_USAGE_DIGEST = 5, SD_LLDP_OUI_802_1_SUBTYPE_MANAGEMENT_VID = 6, - SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7, + SD_LLDP_OUI_802_1_SUBTYPE_LINK_AGGREGATION = 7 }; /* IEEE 802.1AB-2009 Annex F */ @@ -115,7 +115,7 @@ enum { SD_LLDP_OUI_802_3_SUBTYPE_MAC_PHY_CONFIG_STATUS = 1, SD_LLDP_OUI_802_3_SUBTYPE_POWER_VIA_MDI = 2, SD_LLDP_OUI_802_3_SUBTYPE_LINK_AGGREGATION = 3, - SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4, + SD_LLDP_OUI_802_3_SUBTYPE_MAXIMUM_FRAME_SIZE = 4 }; _SD_END_DECLARATIONS; diff --git a/src/libnm-systemd-core/src/systemd/sd-ndisc.h b/src/libnm-systemd-core/src/systemd/sd-ndisc.h index ab9ff55ddb..ee309a4253 100644 --- a/src/libnm-systemd-core/src/systemd/sd-ndisc.h +++ b/src/libnm-systemd-core/src/systemd/sd-ndisc.h @@ -16,7 +16,7 @@ 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 . + along with systemd; If not, see . ***/ #include @@ -42,25 +42,25 @@ enum { SD_NDISC_OPTION_RDNSS = 25, SD_NDISC_OPTION_FLAGS_EXTENSION = 26, SD_NDISC_OPTION_DNSSL = 31, - SD_NDISC_OPTION_CAPTIVE_PORTAL = 37, + SD_NDISC_OPTION_CAPTIVE_PORTAL = 37 }; /* Route preference, RFC 4191, Section 2.1 */ enum { SD_NDISC_PREFERENCE_LOW = 3U, SD_NDISC_PREFERENCE_MEDIUM = 0U, - SD_NDISC_PREFERENCE_HIGH = 1U, + SD_NDISC_PREFERENCE_HIGH = 1U }; typedef struct sd_ndisc sd_ndisc; typedef struct sd_ndisc_router sd_ndisc_router; -typedef enum sd_ndisc_event_t { +__extension__ typedef enum sd_ndisc_event_t { SD_NDISC_EVENT_TIMEOUT, SD_NDISC_EVENT_ROUTER, _SD_NDISC_EVENT_MAX, _SD_NDISC_EVENT_INVALID = -EINVAL, - _SD_ENUM_FORCE_S64(NDISC_EVENT), + _SD_ENUM_FORCE_S64(NDISC_EVENT) } sd_ndisc_event_t; typedef void (*sd_ndisc_callback_t)(sd_ndisc *nd, sd_ndisc_event_t event, sd_ndisc_router *rt, void *userdata); @@ -82,7 +82,6 @@ int sd_ndisc_set_ifname(sd_ndisc *nd, const char *interface_name); int sd_ndisc_get_ifname(sd_ndisc *nd, const char **ret); int sd_ndisc_set_mac(sd_ndisc *nd, const struct ether_addr *mac_addr); -int sd_ndisc_router_from_raw(sd_ndisc_router **ret, const void *raw, size_t raw_size); sd_ndisc_router *sd_ndisc_router_ref(sd_ndisc_router *rt); sd_ndisc_router *sd_ndisc_router_unref(sd_ndisc_router *rt); diff --git a/src/libnm-systemd-shared/src/basic/alloc-util.h b/src/libnm-systemd-shared/src/basic/alloc-util.h index 9dde770dab..13dab0304f 100644 --- a/src/libnm-systemd-shared/src/basic/alloc-util.h +++ b/src/libnm-systemd-shared/src/basic/alloc-util.h @@ -55,8 +55,8 @@ typedef void* (*mfree_func_t)(void *p); typeof(a)* _a = &(a); \ typeof(b)* _b = &(b); \ free(*_a); \ - (*_a) = (*_b); \ - (*_b) = NULL; \ + *_a = *_b; \ + *_b = NULL; \ 0; \ }) @@ -174,23 +174,13 @@ void* greedy_realloc0(void **p, size_t need, size_t size); * is compatible with _FORTIFY_SOURCES. If _FORTIFY_SOURCES is used many memory operations will take the * object size as returned by __builtin_object_size() into account. Hence, let's return the smaller size of * malloc_usable_size() and __builtin_object_size() here, so that we definitely operate in safe territory by - * both the compiler's and libc's standards. Note that _FORTIFY_SOURCES=3 handles also dynamically allocated - * objects and thus it's safer using __builtin_dynamic_object_size if _FORTIFY_SOURCES=3 is used (#22801). - * Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and + * both the compiler's and libc's standards. Note that __builtin_object_size() evaluates to SIZE_MAX if the + * size cannot be determined, hence the MIN() expression should be safe with dynamically sized memory, + * too. Moreover, when NULL is passed malloc_usable_size() is documented to return zero, and * __builtin_object_size() returns SIZE_MAX too, hence we also return a sensible value of 0 in this corner * case. */ - -#if defined __has_builtin -# if __has_builtin(__builtin_dynamic_object_size) -# define MALLOC_SIZEOF_SAFE(x) \ - MIN(malloc_usable_size(x), __builtin_dynamic_object_size(x, 0)) -# endif -#endif - -#ifndef MALLOC_SIZEOF_SAFE #define MALLOC_SIZEOF_SAFE(x) \ MIN(malloc_usable_size(x), __builtin_object_size(x, 0)) -#endif /* Inspired by ELEMENTSOF() but operates on malloc()'ed memory areas: typesafely returns the number of items * that fit into the specified memory block */ diff --git a/src/libnm-systemd-shared/src/basic/env-util.c b/src/libnm-systemd-shared/src/basic/env-util.c index b60c9f9fdc..62914f1587 100644 --- a/src/libnm-systemd-shared/src/basic/env-util.c +++ b/src/libnm-systemd-shared/src/basic/env-util.c @@ -32,7 +32,7 @@ static bool env_name_is_valid_n(const char *e, size_t n) { if (n <= 0) return false; - if (e[0] >= '0' && e[0] <= '9') + if (ascii_isdigit(e[0])) return false; /* POSIX says the overall size of the environment block cannot diff --git a/src/libnm-systemd-shared/src/basic/fileio.c b/src/libnm-systemd-shared/src/basic/fileio.c index e7b670ab2e..2c4ba89a15 100644 --- a/src/libnm-systemd-shared/src/basic/fileio.c +++ b/src/libnm-systemd-shared/src/basic/fileio.c @@ -763,8 +763,7 @@ int read_full_file_full( r = xfopenat(dir_fd, filename, "re", 0, &f); if (r < 0) { - _cleanup_close_ int dfd = -1, sk = -1; - union sockaddr_union sa; + _cleanup_close_ int sk = -1; /* ENXIO is what Linux returns if we open a node that is an AF_UNIX socket */ if (r != -ENXIO) @@ -776,23 +775,7 @@ int read_full_file_full( /* Seeking is not supported on AF_UNIX sockets */ if (offset != UINT64_MAX) - return -ESPIPE; - - if (dir_fd == AT_FDCWD) - r = sockaddr_un_set_path(&sa.un, filename); - else { - /* If we shall operate relative to some directory, then let's use O_PATH first to - * open the socket inode, and then connect to it via /proc/self/fd/. We have to do - * this since there's not connectat() that takes a directory fd as first arg. */ - - dfd = openat(dir_fd, filename, O_PATH|O_CLOEXEC); - if (dfd < 0) - return -errno; - - r = sockaddr_un_set_path(&sa.un, FORMAT_PROC_FD_PATH(dfd)); - } - if (r < 0) - return r; + return -ENXIO; sk = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC, 0); if (sk < 0) @@ -809,12 +792,14 @@ int read_full_file_full( return r; if (bind(sk, &bsa.sa, r) < 0) - return r; + return -errno; } - if (connect(sk, &sa.sa, SOCKADDR_UN_LEN(sa.un)) < 0) - return errno == ENOTSOCK ? -ENXIO : -errno; /* propagate original error if this is - * not a socket after all */ + r = connect_unix_path(sk, dir_fd, filename); + if (IN_SET(r, -ENOTSOCK, -EINVAL)) /* propagate original error if this is not a socket after all */ + return -ENXIO; + if (r < 0) + return r; if (shutdown(sk, SHUT_WR) < 0) return -errno; diff --git a/src/libnm-systemd-shared/src/basic/fs-util.c b/src/libnm-systemd-shared/src/basic/fs-util.c index d67b30429c..cc25222c32 100644 --- a/src/libnm-systemd-shared/src/basic/fs-util.c +++ b/src/libnm-systemd-shared/src/basic/fs-util.c @@ -155,24 +155,23 @@ int readlink_malloc(const char *p, char **ret) { } int readlink_value(const char *p, char **ret) { - _cleanup_free_ char *link = NULL; - char *value; + _cleanup_free_ char *link = NULL, *name = NULL; int r; + assert(p); + assert(ret); + r = readlink_malloc(p, &link); if (r < 0) return r; - value = basename(link); - if (!value) - return -ENOENT; - - value = strdup(value); - if (!value) - return -ENOMEM; - - *ret = value; + r = path_extract_filename(link, &name); + if (r < 0) + return r; + if (r == O_DIRECTORY) + return -EINVAL; + *ret = TAKE_PTR(name); return 0; } diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.c b/src/libnm-systemd-shared/src/basic/glyph-util.c new file mode 100644 index 0000000000..1bba139bfc --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/glyph-util.c @@ -0,0 +1,137 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include "env-util.h" +#include "glyph-util.h" +#include "locale-util.h" +#include "strv.h" + +bool emoji_enabled(void) { + static int cached_emoji_enabled = -1; + + if (cached_emoji_enabled < 0) { + int val; + + val = getenv_bool("SYSTEMD_EMOJI"); + if (val < 0) + cached_emoji_enabled = + is_locale_utf8() && + !STRPTR_IN_SET(getenv("TERM"), "dumb", "linux"); + else + cached_emoji_enabled = val; + } + + return cached_emoji_enabled; +} + +const char *special_glyph(SpecialGlyph code) { + + /* A list of a number of interesting unicode glyphs we can use to decorate our output. It's probably wise to be + * conservative here, and primarily stick to the glyphs defined in the eurlatgr font, so that display still + * works reasonably well on the Linux console. For details see: + * + * http://git.altlinux.org/people/legion/packages/kbd.git?p=kbd.git;a=blob;f=data/consolefonts/README.eurlatgr + */ + + static const char* const draw_table[2][_SPECIAL_GLYPH_MAX] = { + /* ASCII fallback */ + [false] = { + [SPECIAL_GLYPH_TREE_VERTICAL] = "| ", + [SPECIAL_GLYPH_TREE_BRANCH] = "|-", + [SPECIAL_GLYPH_TREE_RIGHT] = "`-", + [SPECIAL_GLYPH_TREE_SPACE] = " ", + [SPECIAL_GLYPH_TREE_TOP] = ",-", + [SPECIAL_GLYPH_VERTICAL_DOTTED] = ":", + [SPECIAL_GLYPH_TRIANGULAR_BULLET] = ">", + [SPECIAL_GLYPH_BLACK_CIRCLE] = "*", + [SPECIAL_GLYPH_WHITE_CIRCLE] = "*", + [SPECIAL_GLYPH_MULTIPLICATION_SIGN] = "x", + [SPECIAL_GLYPH_CIRCLE_ARROW] = "*", + [SPECIAL_GLYPH_BULLET] = "*", + [SPECIAL_GLYPH_MU] = "u", + [SPECIAL_GLYPH_CHECK_MARK] = "+", + [SPECIAL_GLYPH_CROSS_MARK] = "-", + [SPECIAL_GLYPH_LIGHT_SHADE] = "-", + [SPECIAL_GLYPH_DARK_SHADE] = "X", + [SPECIAL_GLYPH_SIGMA] = "S", + [SPECIAL_GLYPH_ARROW_RIGHT] = "->", + [SPECIAL_GLYPH_ARROW_UP] = "^", + [SPECIAL_GLYPH_ARROW_DOWN] = "v", + [SPECIAL_GLYPH_ELLIPSIS] = "...", + [SPECIAL_GLYPH_EXTERNAL_LINK] = "[LNK]", + [SPECIAL_GLYPH_ECSTATIC_SMILEY] = ":-]", + [SPECIAL_GLYPH_HAPPY_SMILEY] = ":-}", + [SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = ":-)", + [SPECIAL_GLYPH_NEUTRAL_SMILEY] = ":-|", + [SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = ":-(", + [SPECIAL_GLYPH_UNHAPPY_SMILEY] = ":-{", + [SPECIAL_GLYPH_DEPRESSED_SMILEY] = ":-[", + [SPECIAL_GLYPH_LOCK_AND_KEY] = "o-,", + [SPECIAL_GLYPH_TOUCH] = "O=", /* Yeah, not very convincing, can you do it better? */ + [SPECIAL_GLYPH_RECYCLING] = "~", + [SPECIAL_GLYPH_DOWNLOAD] = "\\", + [SPECIAL_GLYPH_SPARKLES] = "*", + }, + + /* UTF-8 */ + [true] = { + /* The following are multiple glyphs in both ASCII and in UNICODE */ + [SPECIAL_GLYPH_TREE_VERTICAL] = u8"│ ", + [SPECIAL_GLYPH_TREE_BRANCH] = u8"├─", + [SPECIAL_GLYPH_TREE_RIGHT] = u8"└─", + [SPECIAL_GLYPH_TREE_SPACE] = u8" ", + [SPECIAL_GLYPH_TREE_TOP] = u8"┌─", + + /* Single glyphs in both cases */ + [SPECIAL_GLYPH_VERTICAL_DOTTED] = u8"┆", + [SPECIAL_GLYPH_TRIANGULAR_BULLET] = u8"‣", + [SPECIAL_GLYPH_BLACK_CIRCLE] = u8"●", + [SPECIAL_GLYPH_WHITE_CIRCLE] = u8"○", + [SPECIAL_GLYPH_MULTIPLICATION_SIGN] = u8"×", + [SPECIAL_GLYPH_CIRCLE_ARROW] = u8"↻", + [SPECIAL_GLYPH_BULLET] = u8"•", + [SPECIAL_GLYPH_MU] = u8"μ", /* actually called: GREEK SMALL LETTER MU */ + [SPECIAL_GLYPH_CHECK_MARK] = u8"✓", + [SPECIAL_GLYPH_CROSS_MARK] = u8"✗", /* actually called: BALLOT X */ + [SPECIAL_GLYPH_LIGHT_SHADE] = u8"░", + [SPECIAL_GLYPH_DARK_SHADE] = u8"▒", + [SPECIAL_GLYPH_SIGMA] = u8"Σ", + [SPECIAL_GLYPH_ARROW_UP] = u8"↑", /* actually called: UPWARDS ARROW */ + [SPECIAL_GLYPH_ARROW_DOWN] = u8"↓", /* actually called: DOWNWARDS ARROW */ + + /* Single glyph in Unicode, two in ASCII */ + [SPECIAL_GLYPH_ARROW_RIGHT] = u8"→", /* actually called: RIGHTWARDS ARROW */ + + /* Single glyph in Unicode, three in ASCII */ + [SPECIAL_GLYPH_ELLIPSIS] = u8"…", /* actually called: HORIZONTAL ELLIPSIS */ + + /* Three glyphs in Unicode, five in ASCII */ + [SPECIAL_GLYPH_EXTERNAL_LINK] = u8"[🡕]", /* actually called: NORTH EAST SANS-SERIF ARROW, enclosed in [] */ + + /* These smileys are a single glyph in Unicode, and three in ASCII */ + [SPECIAL_GLYPH_ECSTATIC_SMILEY] = u8"😇", /* actually called: SMILING FACE WITH HALO */ + [SPECIAL_GLYPH_HAPPY_SMILEY] = u8"😀", /* actually called: GRINNING FACE */ + [SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY] = u8"🙂", /* actually called: SLIGHTLY SMILING FACE */ + [SPECIAL_GLYPH_NEUTRAL_SMILEY] = u8"😐", /* actually called: NEUTRAL FACE */ + [SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY] = u8"🙁", /* actually called: SLIGHTLY FROWNING FACE */ + [SPECIAL_GLYPH_UNHAPPY_SMILEY] = u8"😨", /* actually called: FEARFUL FACE */ + [SPECIAL_GLYPH_DEPRESSED_SMILEY] = u8"🤢", /* actually called: NAUSEATED FACE */ + + /* This emoji is a single character cell glyph in Unicode, and three in ASCII */ + [SPECIAL_GLYPH_LOCK_AND_KEY] = u8"🔐", /* actually called: CLOSED LOCK WITH KEY */ + + /* This emoji is a single character cell glyph in Unicode, and two in ASCII */ + [SPECIAL_GLYPH_TOUCH] = u8"👆", /* actually called: BACKHAND INDEX POINTING UP */ + + /* These three emojis are single character cell glyphs in Unicode and also in ASCII. */ + [SPECIAL_GLYPH_RECYCLING] = u8"♻️", /* actually called: UNIVERSAL RECYCLNG SYMBOL */ + [SPECIAL_GLYPH_DOWNLOAD] = u8"⤵️", /* actually called: RIGHT ARROW CURVING DOWN */ + [SPECIAL_GLYPH_SPARKLES] = u8"✨", + }, + }; + + if (code < 0) + return NULL; + + assert(code < _SPECIAL_GLYPH_MAX); + return draw_table[code >= _SPECIAL_GLYPH_FIRST_EMOJI ? emoji_enabled() : is_locale_utf8()][code]; +} diff --git a/src/libnm-systemd-shared/src/basic/glyph-util.h b/src/libnm-systemd-shared/src/basic/glyph-util.h new file mode 100644 index 0000000000..065dde8a62 --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/glyph-util.h @@ -0,0 +1,60 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include + +#include "macro.h" + +typedef enum SpecialGlyph { + SPECIAL_GLYPH_TREE_VERTICAL, + SPECIAL_GLYPH_TREE_BRANCH, + SPECIAL_GLYPH_TREE_RIGHT, + SPECIAL_GLYPH_TREE_SPACE, + SPECIAL_GLYPH_TREE_TOP, + SPECIAL_GLYPH_VERTICAL_DOTTED, + SPECIAL_GLYPH_TRIANGULAR_BULLET, + SPECIAL_GLYPH_BLACK_CIRCLE, + SPECIAL_GLYPH_WHITE_CIRCLE, + SPECIAL_GLYPH_MULTIPLICATION_SIGN, + SPECIAL_GLYPH_CIRCLE_ARROW, + SPECIAL_GLYPH_BULLET, + SPECIAL_GLYPH_MU, + SPECIAL_GLYPH_CHECK_MARK, + SPECIAL_GLYPH_CROSS_MARK, + SPECIAL_GLYPH_ARROW_RIGHT, + SPECIAL_GLYPH_ARROW_UP, + SPECIAL_GLYPH_ARROW_DOWN, + SPECIAL_GLYPH_ELLIPSIS, + SPECIAL_GLYPH_LIGHT_SHADE, + SPECIAL_GLYPH_DARK_SHADE, + SPECIAL_GLYPH_SIGMA, + SPECIAL_GLYPH_EXTERNAL_LINK, + _SPECIAL_GLYPH_FIRST_EMOJI, + SPECIAL_GLYPH_ECSTATIC_SMILEY = _SPECIAL_GLYPH_FIRST_EMOJI, + SPECIAL_GLYPH_HAPPY_SMILEY, + SPECIAL_GLYPH_SLIGHTLY_HAPPY_SMILEY, + SPECIAL_GLYPH_NEUTRAL_SMILEY, + SPECIAL_GLYPH_SLIGHTLY_UNHAPPY_SMILEY, + SPECIAL_GLYPH_UNHAPPY_SMILEY, + SPECIAL_GLYPH_DEPRESSED_SMILEY, + SPECIAL_GLYPH_LOCK_AND_KEY, + SPECIAL_GLYPH_TOUCH, + SPECIAL_GLYPH_RECYCLING, + SPECIAL_GLYPH_DOWNLOAD, + SPECIAL_GLYPH_SPARKLES, + _SPECIAL_GLYPH_MAX, + _SPECIAL_GLYPH_INVALID = -EINVAL, +} SpecialGlyph; + +const char *special_glyph(SpecialGlyph code) _const_; + +bool emoji_enabled(void); + +static inline const char *special_glyph_check_mark(bool b) { + return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : special_glyph(SPECIAL_GLYPH_CROSS_MARK); +} + +static inline const char *special_glyph_check_mark_space(bool b) { + return b ? special_glyph(SPECIAL_GLYPH_CHECK_MARK) : " "; +} diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.c b/src/libnm-systemd-shared/src/basic/hash-funcs.c index 084ed0c0a2..6addb76f1b 100644 --- a/src/libnm-systemd-shared/src/basic/hash-funcs.c +++ b/src/libnm-systemd-shared/src/basic/hash-funcs.c @@ -102,10 +102,16 @@ DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func void devt_hash_func(const dev_t *p, struct siphash *state) { siphash24_compress(p, sizeof(dev_t), state); } +#endif int devt_compare_func(const dev_t *a, const dev_t *b) { - return CMP(*a, *b); + int r; + + r = CMP(major(*a), major(*b)); + if (r != 0) + return r; + + return CMP(minor(*a), minor(*b)); } DEFINE_HASH_OPS(devt_hash_ops, dev_t, devt_hash_func, devt_compare_func); -#endif diff --git a/src/libnm-systemd-shared/src/basic/hash-funcs.h b/src/libnm-systemd-shared/src/basic/hash-funcs.h index 023cfdf530..c537c6af7e 100644 --- a/src/libnm-systemd-shared/src/basic/hash-funcs.h +++ b/src/libnm-systemd-shared/src/basic/hash-funcs.h @@ -102,10 +102,9 @@ extern const struct hash_ops uint64_hash_ops; * 64bit archs. Yuck! */ #if SIZEOF_DEV_T != 8 void devt_hash_func(const dev_t *p, struct siphash *state) _pure_; -int devt_compare_func(const dev_t *a, const dev_t *b) _pure_; -extern const struct hash_ops devt_hash_ops; #else #define devt_hash_func uint64_hash_func -#define devt_compare_func uint64_compare_func -#define devt_hash_ops uint64_hash_ops #endif + +int devt_compare_func(const dev_t *a, const dev_t *b) _pure_; +extern const struct hash_ops devt_hash_ops; diff --git a/src/libnm-systemd-shared/src/basic/hashmap.c b/src/libnm-systemd-shared/src/basic/hashmap.c index 1855367072..1fadaad996 100644 --- a/src/libnm-systemd-shared/src/basic/hashmap.c +++ b/src/libnm-systemd-shared/src/basic/hashmap.c @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #include +#include #include #include #include @@ -770,16 +771,15 @@ static void shared_hash_key_initialize(void) { static struct HashmapBase* hashmap_base_new(const struct hash_ops *hash_ops, enum HashmapType type HASHMAP_DEBUG_PARAMS) { HashmapBase *h; const struct hashmap_type_info *hi = &hashmap_type_info[type]; - bool up; - up = mempool_enabled(); + bool use_pool = mempool_enabled && mempool_enabled(); - h = up ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); + h = use_pool ? mempool_alloc0_tile(hi->mempool) : malloc0(hi->head_size); if (!h) return NULL; h->type = type; - h->from_pool = up; + h->from_pool = use_pool; h->hash_ops = hash_ops ?: &trivial_hash_ops; if (type == HASHMAP_TYPE_ORDERED) { @@ -1841,7 +1841,7 @@ int _hashmap_put_strdup_full(Hashmap **h, const struct hash_ops *hash_ops, const return r; } -int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS) { +int _set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n HASHMAP_DEBUG_PARAMS) { char *c; int r; @@ -1852,10 +1852,13 @@ int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p if (r < 0) return r; - if (set_contains(*s, (char*) p)) - return 0; + if (n == SIZE_MAX) { + if (set_contains(*s, (char*) p)) + return 0; - c = strdup(p); + c = strdup(p); + } else + c = strndup(p, n); if (!c) return -ENOMEM; @@ -1868,7 +1871,7 @@ int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HA assert(s); STRV_FOREACH(i, l) { - r = _set_put_strdup_full(s, hash_ops, *i HASHMAP_DEBUG_PASS_ARGS); + r = _set_put_strndup_full(s, hash_ops, *i, SIZE_MAX HASHMAP_DEBUG_PASS_ARGS); if (r < 0) return r; @@ -2070,3 +2073,27 @@ bool set_equal(Set *a, Set *b) { return true; } + +static bool set_fnmatch_one(Set *patterns, const char *needle) { + const char *p; + + assert(needle); + + SET_FOREACH(p, patterns) + if (fnmatch(p, needle, 0) == 0) + return true; + + return false; +} + +bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle) { + assert(needle); + + if (set_fnmatch_one(exclude_patterns, needle)) + return false; + + if (set_isempty(include_patterns)) + return true; + + return set_fnmatch_one(include_patterns, needle); +} diff --git a/src/libnm-systemd-shared/src/basic/hostname-util.c b/src/libnm-systemd-shared/src/basic/hostname-util.c index d5d1388102..b710f07929 100644 --- a/src/libnm-systemd-shared/src/basic/hostname-util.c +++ b/src/libnm-systemd-shared/src/basic/hostname-util.c @@ -75,10 +75,8 @@ int gethostname_full(GetHostnameFlags flags, char **ret) { bool valid_ldh_char(char c) { /* "LDH" → "Letters, digits, hyphens", as per RFC 5890, Section 2.3.1 */ - return - (c >= 'a' && c <= 'z') || - (c >= 'A' && c <= 'Z') || - (c >= '0' && c <= '9') || + return ascii_isalpha(c) || + ascii_isdigit(c) || c == '-'; } diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.c b/src/libnm-systemd-shared/src/basic/in-addr-util.c index 660c1f1824..6f8ffaf259 100644 --- a/src/libnm-systemd-shared/src/basic/in-addr-util.c +++ b/src/libnm-systemd-shared/src/basic/in-addr-util.c @@ -14,6 +14,7 @@ #include "macro.h" #include "parse-util.h" #include "random-util.h" +#include "stdio-util.h" #include "string-util.h" #include "strxcpyx.h" #include "util.h" @@ -444,44 +445,33 @@ int in_addr_to_string(int family, const union in_addr_union *u, char **ret) { return -ENOMEM; errno = 0; - if (!inet_ntop(family, u, x, l)) + if (!typesafe_inet_ntop(family, u, x, l)) return errno_or_else(EINVAL); *ret = TAKE_PTR(x); return 0; } -int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret) { - _cleanup_free_ char *x = NULL; - char *p; - size_t l; +int in_addr_prefix_to_string( + int family, + const union in_addr_union *u, + unsigned prefixlen, + char *buf, + size_t buf_len) { assert(u); - assert(ret); + assert(buf); - if (family == AF_INET) - l = INET_ADDRSTRLEN + 3; - else if (family == AF_INET6) - l = INET6_ADDRSTRLEN + 4; - else + if (!IN_SET(family, AF_INET, AF_INET6)) return -EAFNOSUPPORT; - if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8) - return -EINVAL; - - x = new(char, l); - if (!x) - return -ENOMEM; - errno = 0; - if (!inet_ntop(family, u, x, l)) - return errno_or_else(EINVAL); + if (!typesafe_inet_ntop(family, u, buf, buf_len)) + return errno_or_else(ENOSPC); - p = x + strlen(x); - l -= strlen(x); - (void) strpcpyf(&p, l, "/%u", prefixlen); - - *ret = TAKE_PTR(x); + size_t l = strlen(buf); + if (!snprintf_ok(buf + l, buf_len - l, "/%u", prefixlen)) + return -ENOSPC; return 0; } diff --git a/src/libnm-systemd-shared/src/basic/in-addr-util.h b/src/libnm-systemd-shared/src/basic/in-addr-util.h index 5de87a9539..c1e7ef965d 100644 --- a/src/libnm-systemd-shared/src/basic/in-addr-util.h +++ b/src/libnm-systemd-shared/src/basic/in-addr-util.h @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include #include #include #include @@ -68,14 +69,62 @@ int in_addr_prefix_range( unsigned prefixlen, union in_addr_union *ret_start, union in_addr_union *ret_end); + int in_addr_to_string(int family, const union in_addr_union *u, char **ret); static inline int in6_addr_to_string(const struct in6_addr *u, char **ret) { return in_addr_to_string(AF_INET6, (const union in_addr_union*) u, ret); } -int in_addr_prefix_to_string(int family, const union in_addr_union *u, unsigned prefixlen, char **ret); -static inline int in6_addr_prefix_to_string(const struct in6_addr *u, unsigned prefixlen, char **ret) { - return in_addr_prefix_to_string(AF_INET6, (const union in_addr_union*) u, prefixlen, ret); + +static inline const char* typesafe_inet_ntop(int family, const union in_addr_union *a, char *buf, size_t len) { + return inet_ntop(family, a, buf, len); } +static inline const char* typesafe_inet_ntop4(const struct in_addr *a, char *buf, size_t len) { + return inet_ntop(AF_INET, a, buf, len); +} +static inline const char* typesafe_inet_ntop6(const struct in6_addr *a, char *buf, size_t len) { + return inet_ntop(AF_INET6, a, buf, len); +} + +/* Note: the lifetime of the compound literal is the immediately surrounding block, + * see C11 §6.5.2.5, and + * https://stackoverflow.com/questions/34880638/compound-literal-lifetime-and-if-blocks */ +#define IN_ADDR_MAX CONST_MAX(INET_ADDRSTRLEN, INET6_ADDRSTRLEN) +#define IN_ADDR_TO_STRING(family, addr) typesafe_inet_ntop(family, addr, (char[IN_ADDR_MAX]){}, IN_ADDR_MAX) +#define IN4_ADDR_TO_STRING(addr) typesafe_inet_ntop4(addr, (char[INET_ADDRSTRLEN]){}, INET_ADDRSTRLEN) +#define IN6_ADDR_TO_STRING(addr) typesafe_inet_ntop6(addr, (char[INET6_ADDRSTRLEN]){}, INET6_ADDRSTRLEN) + +int in_addr_prefix_to_string( + int family, + const union in_addr_union *u, + unsigned prefixlen, + char *buf, + size_t buf_len); + +static inline const char* _in_addr_prefix_to_string( + int family, + const union in_addr_union *u, + unsigned prefixlen, + char *buf, + size_t buf_len) { + /* We assume that this is called with an appropriately sized buffer and can never fail. */ + assert_se(in_addr_prefix_to_string(family, u, prefixlen, buf, buf_len) == 0); + return buf; +} +static inline const char* _in4_addr_prefix_to_string(const struct in_addr *a, unsigned prefixlen, char *buf, size_t buf_len) { + return _in_addr_prefix_to_string(AF_INET, (const union in_addr_union *) a, prefixlen, buf, buf_len); +} +static inline const char* _in6_addr_prefix_to_string(const struct in6_addr *a, unsigned prefixlen, char *buf, size_t buf_len) { + return _in_addr_prefix_to_string(AF_INET6, (const union in_addr_union *) a, prefixlen, buf, buf_len); +} + +#define PREFIX_SUFFIX_MAX (1 + DECIMAL_STR_MAX(unsigned)) +#define IN_ADDR_PREFIX_TO_STRING(family, addr, prefixlen) \ + _in_addr_prefix_to_string(family, addr, prefixlen, (char[IN_ADDR_MAX + PREFIX_SUFFIX_MAX]){}, IN_ADDR_MAX + PREFIX_SUFFIX_MAX) +#define IN4_ADDR_PREFIX_TO_STRING(addr, prefixlen) \ + _in4_addr_prefix_to_string(addr, prefixlen, (char[INET_ADDRSTRLEN + PREFIX_SUFFIX_MAX]){}, INET_ADDRSTRLEN + PREFIX_SUFFIX_MAX) +#define IN6_ADDR_PREFIX_TO_STRING(addr, prefixlen) \ + _in6_addr_prefix_to_string(addr, prefixlen, (char[INET6_ADDRSTRLEN + PREFIX_SUFFIX_MAX]){}, INET6_ADDRSTRLEN + PREFIX_SUFFIX_MAX) + int in_addr_port_ifindex_name_to_string(int family, const union in_addr_union *u, uint16_t port, int ifindex, const char *server_name, char **ret); static inline int in_addr_ifindex_to_string(int family, const union in_addr_union *u, int ifindex, char **ret) { return in_addr_port_ifindex_name_to_string(family, u, 0, ifindex, NULL, ret); diff --git a/src/libnm-systemd-shared/src/basic/locale-util.c b/src/libnm-systemd-shared/src/basic/locale-util.c new file mode 100644 index 0000000000..d8518ec06a --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/locale-util.c @@ -0,0 +1,370 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "def.h" +#include "dirent-util.h" +#include "env-util.h" +#include "fd-util.h" +#include "fileio.h" +#include "hashmap.h" +#include "locale-util.h" +#include "path-util.h" +#include "set.h" +#include "string-table.h" +#include "string-util.h" +#include "strv.h" +#include "utf8.h" + +static char *normalize_locale(const char *name) { + const char *e; + + /* Locale names are weird: glibc has some magic rules when looking for the charset name on disk: it + * lowercases everything, and removes most special chars. This means the official .UTF-8 suffix + * becomes .utf8 when looking things up on disk. When enumerating locales, let's do the reverse + * operation, and go back to ".UTF-8" which appears to be the more commonly accepted name. We only do + * that for UTF-8 however, since it's kinda the only charset that matters. */ + + e = endswith(name, ".utf8"); + if (e) { + _cleanup_free_ char *prefix = NULL; + + prefix = strndup(name, e - name); + if (!prefix) + return NULL; + + return strjoin(prefix, ".UTF-8"); + } + + e = strstr(name, ".utf8@"); + if (e) { + _cleanup_free_ char *prefix = NULL; + + prefix = strndup(name, e - name); + if (!prefix) + return NULL; + + return strjoin(prefix, ".UTF-8@", e + 6); + } + + return strdup(name); +} + +static int add_locales_from_archive(Set *locales) { + /* Stolen from glibc... */ + + struct locarhead { + uint32_t magic; + /* Serial number. */ + uint32_t serial; + /* Name hash table. */ + uint32_t namehash_offset; + uint32_t namehash_used; + uint32_t namehash_size; + /* String table. */ + uint32_t string_offset; + uint32_t string_used; + uint32_t string_size; + /* Table with locale records. */ + uint32_t locrectab_offset; + uint32_t locrectab_used; + uint32_t locrectab_size; + /* MD5 sum hash table. */ + uint32_t sumhash_offset; + uint32_t sumhash_used; + uint32_t sumhash_size; + }; + + struct namehashent { + /* Hash value of the name. */ + uint32_t hashval; + /* Offset of the name in the string table. */ + uint32_t name_offset; + /* Offset of the locale record. */ + uint32_t locrec_offset; + }; + + const struct locarhead *h; + const struct namehashent *e; + const void *p = MAP_FAILED; + _cleanup_close_ int fd = -1; + size_t sz = 0; + struct stat st; + int r; + + fd = open("/usr/lib/locale/locale-archive", O_RDONLY|O_NOCTTY|O_CLOEXEC); + if (fd < 0) + return errno == ENOENT ? 0 : -errno; + + if (fstat(fd, &st) < 0) + return -errno; + + if (!S_ISREG(st.st_mode)) + return -EBADMSG; + + if (st.st_size < (off_t) sizeof(struct locarhead)) + return -EBADMSG; + + if (file_offset_beyond_memory_size(st.st_size)) + return -EFBIG; + + p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + if (p == MAP_FAILED) + return -errno; + + h = (const struct locarhead *) p; + if (h->magic != 0xde020109 || + h->namehash_offset + h->namehash_size > st.st_size || + h->string_offset + h->string_size > st.st_size || + h->locrectab_offset + h->locrectab_size > st.st_size || + h->sumhash_offset + h->sumhash_size > st.st_size) { + r = -EBADMSG; + goto finish; + } + + e = (const struct namehashent*) ((const uint8_t*) p + h->namehash_offset); + for (size_t i = 0; i < h->namehash_size; i++) { + char *z; + + if (e[i].locrec_offset == 0) + continue; + + if (!utf8_is_valid((char*) p + e[i].name_offset)) + continue; + + z = normalize_locale((char*) p + e[i].name_offset); + if (!z) { + r = -ENOMEM; + goto finish; + } + + r = set_consume(locales, z); + if (r < 0) + goto finish; + } + + r = 0; + + finish: + if (p != MAP_FAILED) + munmap((void*) p, sz); + + return r; +} + +static int add_locales_from_libdir(Set *locales) { + _cleanup_closedir_ DIR *dir = NULL; + int r; + + dir = opendir("/usr/lib/locale"); + if (!dir) + return errno == ENOENT ? 0 : -errno; + + FOREACH_DIRENT(de, dir, return -errno) { + char *z; + + if (de->d_type != DT_DIR) + continue; + + z = normalize_locale(de->d_name); + if (!z) + return -ENOMEM; + + r = set_consume(locales, z); + if (r < 0 && r != -EEXIST) + return r; + } + + return 0; +} + +int get_locales(char ***ret) { + _cleanup_set_free_free_ Set *locales = NULL; + _cleanup_strv_free_ char **l = NULL; + int r; + + locales = set_new(&string_hash_ops); + if (!locales) + return -ENOMEM; + + r = add_locales_from_archive(locales); + if (r < 0 && r != -ENOENT) + return r; + + r = add_locales_from_libdir(locales); + if (r < 0) + return r; + + char *locale; + SET_FOREACH(locale, locales) { + r = locale_is_installed(locale); + if (r < 0) + return r; + if (r == 0) + free(set_remove(locales, locale)); + } + + l = set_get_strv(locales); + if (!l) + return -ENOMEM; + + /* Now, all elements are owned by strv 'l'. Hence, do not call set_free_free(). */ + locales = set_free(locales); + + r = getenv_bool("SYSTEMD_LIST_NON_UTF8_LOCALES"); + if (r == -ENXIO || r == 0) { + char **a, **b; + + /* Filter out non-UTF-8 locales, because it's 2019, by default */ + for (a = b = l; *a; a++) { + + if (endswith(*a, "UTF-8") || + strstr(*a, ".UTF-8@")) + *(b++) = *a; + else + free(*a); + } + + *b = NULL; + + } else if (r < 0) + log_debug_errno(r, "Failed to parse $SYSTEMD_LIST_NON_UTF8_LOCALES as boolean"); + + strv_sort(l); + + *ret = TAKE_PTR(l); + + return 0; +} + +bool locale_is_valid(const char *name) { + + if (isempty(name)) + return false; + + if (strlen(name) >= 128) + return false; + + if (!utf8_is_valid(name)) + return false; + + if (!filename_is_valid(name)) + return false; + + if (!string_is_safe(name)) + return false; + + return true; +} + +int locale_is_installed(const char *name) { + if (!locale_is_valid(name)) + return false; + + if (STR_IN_SET(name, "C", "POSIX")) /* These ones are always OK */ + return true; + + _cleanup_(freelocalep) locale_t loc = + newlocale(LC_ALL_MASK, name, 0); + if (loc == (locale_t) 0) + return errno == ENOMEM ? -ENOMEM : false; + + return true; +} + +void init_gettext(void) { + setlocale(LC_ALL, ""); + textdomain(GETTEXT_PACKAGE); +} + +bool is_locale_utf8(void) { + const char *set; + static int cached_answer = -1; + + /* Note that we default to 'true' here, since today UTF8 is + * pretty much supported everywhere. */ + + if (cached_answer >= 0) + goto out; + + if (!setlocale(LC_ALL, "")) { + cached_answer = true; + goto out; + } + + set = nl_langinfo(CODESET); + if (!set) { + cached_answer = true; + goto out; + } + + if (streq(set, "UTF-8")) { + cached_answer = true; + goto out; + } + + /* For LC_CTYPE=="C" return true, because CTYPE is effectively + * unset and everything can do to UTF-8 nowadays. */ + set = setlocale(LC_CTYPE, NULL); + if (!set) { + cached_answer = true; + goto out; + } + + /* Check result, but ignore the result if C was set + * explicitly. */ + cached_answer = + STR_IN_SET(set, "C", "POSIX") && + !getenv("LC_ALL") && + !getenv("LC_CTYPE") && + !getenv("LANG"); + +out: + return (bool) cached_answer; +} + +void locale_variables_free(char *l[_VARIABLE_LC_MAX]) { + if (!l) + return; + + for (LocaleVariable i = 0; i < _VARIABLE_LC_MAX; i++) + l[i] = mfree(l[i]); +} + +void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]) { + assert(l); + + for (LocaleVariable p = 0; p < _VARIABLE_LC_MAX; p++) { + if (p == VARIABLE_LANG) + continue; + if (isempty(l[p]) || streq_ptr(l[VARIABLE_LANG], l[p])) + l[p] = mfree(l[p]); + } +} + +static const char * const locale_variable_table[_VARIABLE_LC_MAX] = { + [VARIABLE_LANG] = "LANG", + [VARIABLE_LANGUAGE] = "LANGUAGE", + [VARIABLE_LC_CTYPE] = "LC_CTYPE", + [VARIABLE_LC_NUMERIC] = "LC_NUMERIC", + [VARIABLE_LC_TIME] = "LC_TIME", + [VARIABLE_LC_COLLATE] = "LC_COLLATE", + [VARIABLE_LC_MONETARY] = "LC_MONETARY", + [VARIABLE_LC_MESSAGES] = "LC_MESSAGES", + [VARIABLE_LC_PAPER] = "LC_PAPER", + [VARIABLE_LC_NAME] = "LC_NAME", + [VARIABLE_LC_ADDRESS] = "LC_ADDRESS", + [VARIABLE_LC_TELEPHONE] = "LC_TELEPHONE", + [VARIABLE_LC_MEASUREMENT] = "LC_MEASUREMENT", + [VARIABLE_LC_IDENTIFICATION] = "LC_IDENTIFICATION" +}; + +DEFINE_STRING_TABLE_LOOKUP(locale_variable, LocaleVariable); diff --git a/src/libnm-systemd-shared/src/basic/locale-util.h b/src/libnm-systemd-shared/src/basic/locale-util.h new file mode 100644 index 0000000000..8990cb6a75 --- /dev/null +++ b/src/libnm-systemd-shared/src/basic/locale-util.h @@ -0,0 +1,56 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include +#include +#include + +#include "macro.h" + +typedef enum LocaleVariable { + /* We don't list LC_ALL here on purpose. People should be + * using LANG instead. */ + + VARIABLE_LANG, + VARIABLE_LANGUAGE, + VARIABLE_LC_CTYPE, + VARIABLE_LC_NUMERIC, + VARIABLE_LC_TIME, + VARIABLE_LC_COLLATE, + VARIABLE_LC_MONETARY, + VARIABLE_LC_MESSAGES, + VARIABLE_LC_PAPER, + VARIABLE_LC_NAME, + VARIABLE_LC_ADDRESS, + VARIABLE_LC_TELEPHONE, + VARIABLE_LC_MEASUREMENT, + VARIABLE_LC_IDENTIFICATION, + _VARIABLE_LC_MAX, + _VARIABLE_LC_INVALID = -EINVAL, +} LocaleVariable; + +int get_locales(char ***l); +bool locale_is_valid(const char *name); +int locale_is_installed(const char *name); + +#define _(String) gettext(String) +#define N_(String) String +void init_gettext(void); + +bool is_locale_utf8(void); + +const char* locale_variable_to_string(LocaleVariable i) _const_; +LocaleVariable locale_variable_from_string(const char *s) _pure_; + +static inline void freelocalep(locale_t *p) { + if (*p == (locale_t) 0) + return; + + freelocale(*p); +} + +void locale_variables_free(char* l[_VARIABLE_LC_MAX]); +static inline void locale_variables_freep(char*(*l)[_VARIABLE_LC_MAX]) { + locale_variables_free(*l); +} +void locale_variables_simplify(char *l[_VARIABLE_LC_MAX]); diff --git a/src/libnm-systemd-shared/src/basic/log.h b/src/libnm-systemd-shared/src/basic/log.h index 0d927bfce9..b7b0a42e49 100644 --- a/src/libnm-systemd-shared/src/basic/log.h +++ b/src/libnm-systemd-shared/src/basic/log.h @@ -298,8 +298,16 @@ int log_emergency_level(void); bool log_on_console(void) _pure_; -/* Helper to prepare various field for structured logging */ -#define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ +/* Helper to wrap the main message in structured logging. The macro doesn't do much, + * except to provide visual grouping of the format string and its arguments. */ +#if LOG_MESSAGE_VERIFICATION || defined(__COVERITY__) +/* Do a fake formatting of the message string to let the scanner verify the arguments against the format + * message. The variable will never be set to true, but we don't tell the compiler that :) */ +extern bool _log_message_dummy; +# define LOG_MESSAGE(fmt, ...) "MESSAGE=%.0d" fmt, (_log_message_dummy && printf(fmt, ##__VA_ARGS__)), ##__VA_ARGS__ +#else +# define LOG_MESSAGE(fmt, ...) "MESSAGE=" fmt, ##__VA_ARGS__ +#endif void log_received_signal(int level, const struct signalfd_siginfo *si); diff --git a/src/libnm-systemd-shared/src/basic/macro.h b/src/libnm-systemd-shared/src/basic/macro.h index 68d8b062e8..bcac55620e 100644 --- a/src/libnm-systemd-shared/src/basic/macro.h +++ b/src/libnm-systemd-shared/src/basic/macro.h @@ -11,24 +11,6 @@ #include "macro-fundamental.h" -#define _printf_(a, b) __attribute__((__format__(printf, a, b))) -#ifdef __clang__ -# define _alloc_(...) -#else -# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__))) -#endif -#define _sentinel_ __attribute__((__sentinel__)) -#define _destructor_ __attribute__((__destructor__)) -#define _deprecated_ __attribute__((__deprecated__)) -#define _malloc_ __attribute__((__malloc__)) -#define _weak_ __attribute__((__weak__)) -#define _public_ __attribute__((__visibility__("default"))) -#define _hidden_ __attribute__((__visibility__("hidden"))) -#define _weakref_(x) __attribute__((__weakref__(#x))) -#define _alignas_(x) __attribute__((__aligned__(__alignof__(x)))) -#define _alignptr_ __attribute__((__aligned__(sizeof(void*)))) -#define _warn_unused_result_ __attribute__((__warn_unused_result__)) - #if !defined(HAS_FEATURE_MEMORY_SANITIZER) # if defined(__has_feature) # if __has_feature(memory_sanitizer) @@ -128,25 +110,6 @@ #error "neither int nor long are four bytes long?!?" #endif -/* Rounds up */ - -#define ALIGN4(l) (((l) + 3) & ~3) -#define ALIGN8(l) (((l) + 7) & ~7) - -#if __SIZEOF_POINTER__ == 8 -#define ALIGN(l) ALIGN8(l) -#elif __SIZEOF_POINTER__ == 4 -#define ALIGN(l) ALIGN4(l) -#else -#error "Wut? Pointers are neither 4 nor 8 bytes long?" -#endif - -#define ALIGN_PTR(p) ((void*) ALIGN((unsigned long) (p))) -#define ALIGN4_PTR(p) ((void*) ALIGN4((unsigned long) (p))) -#define ALIGN8_PTR(p) ((void*) ALIGN8((unsigned long) (p))) - -#define ALIGN_TO_PTR(p, ali) ((void*) ALIGN_TO((unsigned long) (p), (ali))) - /* align to next higher power-of-2 (except for: 0 => 0, overflow => 0) */ static inline unsigned long ALIGN_POWER2(unsigned long u) { @@ -361,7 +324,7 @@ static inline int __coverity_check_and_return__(int condition) { #ifndef thread_local /* * Don't break on glibc < 2.16 that doesn't define __STDC_NO_THREADS__ - * see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 + * see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=53769 */ #if __STDC_VERSION__ >= 201112L && !(defined(__STDC_NO_THREADS__) || (defined(__GNU_LIBRARY__) && __GLIBC__ == 2 && __GLIBC_MINOR__ < 16)) #define thread_local _Thread_local @@ -396,8 +359,12 @@ static inline int __coverity_check_and_return__(int condition) { if (!p) \ return NULL; \ \ - assert(p->n_ref > 0); \ - p->n_ref++; \ + /* For type check. */ \ + unsigned *q = &p->n_ref; \ + assert(*q > 0); \ + assert_se(*q < UINT_MAX); \ + \ + (*q)++; \ return p; \ } @@ -453,8 +420,15 @@ static inline int __coverity_check_and_return__(int condition) { _copy; \ }) +#define saturate_add(x, y, limit) \ + ({ \ + typeof(limit) _x = (x); \ + typeof(limit) _y = (y); \ + _x > (limit) || _y >= (limit) - _x ? (limit) : _x + _y; \ + }) + static inline size_t size_add(size_t x, size_t y) { - return y >= SIZE_MAX - x ? SIZE_MAX : x + y; + return saturate_add(x, y, SIZE_MAX); } typedef struct { diff --git a/src/libnm-systemd-shared/src/basic/mempool.c b/src/libnm-systemd-shared/src/basic/mempool.c index 9eedc20c4f..fff23fdbac 100644 --- a/src/libnm-systemd-shared/src/basic/mempool.c +++ b/src/libnm-systemd-shared/src/basic/mempool.c @@ -3,12 +3,9 @@ #include #include -#include "env-util.h" #include "macro.h" #include "memory-util.h" #include "mempool.h" -#include "process-util.h" -#include "util.h" struct pool { struct pool *next; @@ -73,20 +70,6 @@ void mempool_free_tile(struct mempool *mp, void *p) { mp->freelist = p; } -bool mempool_enabled(void) { - static int b = -1; - - if (!is_main_thread()) - return false; - - if (!mempool_use_allowed) - b = false; - if (b < 0) - b = getenv_bool("SYSTEMD_MEMPOOL") != 0; - - return b; -} - #if VALGRIND void mempool_drop(struct mempool *mp) { struct pool *p = mp->first_pool; diff --git a/src/libnm-systemd-shared/src/basic/mempool.h b/src/libnm-systemd-shared/src/basic/mempool.h index 0fe2f2789c..539ccbdf06 100644 --- a/src/libnm-systemd-shared/src/basic/mempool.h +++ b/src/libnm-systemd-shared/src/basic/mempool.h @@ -23,8 +23,7 @@ static struct mempool pool_name = { \ .at_least = alloc_at_least, \ } -extern const bool mempool_use_allowed; -bool mempool_enabled(void); +__attribute__((weak)) bool mempool_enabled(void); #if VALGRIND void mempool_drop(struct mempool *mp); diff --git a/src/libnm-systemd-shared/src/basic/ordered-set.h b/src/libnm-systemd-shared/src/basic/ordered-set.h index c0650e0158..e73da20573 100644 --- a/src/libnm-systemd-shared/src/basic/ordered-set.h +++ b/src/libnm-systemd-shared/src/basic/ordered-set.h @@ -74,6 +74,10 @@ static inline char** ordered_set_get_strv(OrderedSet *s) { return _hashmap_get_strv(HASHMAP_BASE((OrderedHashmap*) s)); } +static inline int ordered_set_reserve(OrderedSet *s, unsigned entries_add) { + return ordered_hashmap_reserve((OrderedHashmap*) s, entries_add); +} + int ordered_set_consume(OrderedSet *s, void *p); int _ordered_set_put_strdup(OrderedSet **s, const char *p HASHMAP_DEBUG_PARAMS); #define ordered_set_put_strdup(s, p) _ordered_set_put_strdup(s, p HASHMAP_DEBUG_SRC_ARGS) diff --git a/src/libnm-systemd-shared/src/basic/parse-util.c b/src/libnm-systemd-shared/src/basic/parse-util.c index 222b2304cd..787a681870 100644 --- a/src/libnm-systemd-shared/src/basic/parse-util.c +++ b/src/libnm-systemd-shared/src/basic/parse-util.c @@ -210,7 +210,7 @@ int parse_size(const char *t, uint64_t base, uint64_t *size) { e++; /* strtoull() itself would accept space/+/- */ - if (*e >= '0' && *e <= '9') { + if (ascii_isdigit(*e)) { unsigned long long l2; char *e2; @@ -599,7 +599,7 @@ int parse_fractional_part_u(const char **p, size_t digits, unsigned *res) { /* accept any number of digits, strtoull is limited to 19 */ for (size_t i = 0; i < digits; i++,s++) { - if (*s < '0' || *s > '9') { + if (!ascii_isdigit(*s)) { if (i == 0) return -EINVAL; @@ -692,34 +692,6 @@ int parse_ip_prefix_length(const char *s, int *ret) { return 0; } -int parse_dev(const char *s, dev_t *ret) { - const char *major; - unsigned x, y; - size_t n; - int r; - - n = strspn(s, DIGITS); - if (n == 0) - return -EINVAL; - if (s[n] != ':') - return -EINVAL; - - major = strndupa_safe(s, n); - r = safe_atou(major, &x); - if (r < 0) - return r; - - r = safe_atou(s + n + 1, &y); - if (r < 0) - return r; - - if (!DEVICE_MAJOR_VALID(x) || !DEVICE_MINOR_VALID(y)) - return -ERANGE; - - *ret = makedev(x, y); - return 0; -} - int parse_oom_score_adjust(const char *s, int *ret) { int r, v; diff --git a/src/libnm-systemd-shared/src/basic/parse-util.h b/src/libnm-systemd-shared/src/basic/parse-util.h index 8273124626..f2222dcffb 100644 --- a/src/libnm-systemd-shared/src/basic/parse-util.h +++ b/src/libnm-systemd-shared/src/basic/parse-util.h @@ -12,7 +12,6 @@ typedef unsigned long loadavg_t; int parse_boolean(const char *v) _pure_; -int parse_dev(const char *s, dev_t *ret); int parse_pid(const char *s, pid_t* ret_pid); int parse_mode(const char *s, mode_t *ret); int parse_ifindex(const char *s); diff --git a/src/libnm-systemd-shared/src/basic/path-util.c b/src/libnm-systemd-shared/src/basic/path-util.c index 5d93e107a7..94527eff4c 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.c +++ b/src/libnm-systemd-shared/src/basic/path-util.c @@ -17,17 +17,13 @@ #include "extract-word.h" #include "fd-util.h" #include "fs-util.h" -#include "glob-util.h" #include "log.h" #include "macro.h" -#include "nulstr-util.h" -#include "parse-util.h" #include "path-util.h" #include "stat-util.h" #include "string-util.h" #include "strv.h" #include "time-util.h" -#include "utf8.h" int path_split_and_make_absolute(const char *p, char ***ret) { char **l; @@ -376,52 +372,6 @@ char *path_simplify(char *path) { return path; } -int path_simplify_and_warn( - char *path, - unsigned flag, - const char *unit, - const char *filename, - unsigned line, - const char *lvalue) { - - bool fatal = flag & PATH_CHECK_FATAL; - - assert(!FLAGS_SET(flag, PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)); - - if (!utf8_is_valid(path)) - return log_syntax_invalid_utf8(unit, LOG_ERR, filename, line, path); - - if (flag & (PATH_CHECK_ABSOLUTE | PATH_CHECK_RELATIVE)) { - bool absolute; - - absolute = path_is_absolute(path); - - if (!absolute && (flag & PATH_CHECK_ABSOLUTE)) - return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), - "%s= path is not absolute%s: %s", - lvalue, fatal ? "" : ", ignoring", path); - - if (absolute && (flag & PATH_CHECK_RELATIVE)) - return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), - "%s= path is absolute%s: %s", - lvalue, fatal ? "" : ", ignoring", path); - } - - path_simplify(path); - - if (!path_is_valid(path)) - return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), - "%s= path has invalid length (%zu bytes)%s.", - lvalue, strlen(path), fatal ? "" : ", ignoring"); - - if (!path_is_normalized(path)) - return log_syntax(unit, LOG_ERR, filename, line, SYNTHETIC_ERRNO(EINVAL), - "%s= path is not normalized%s: %s", - lvalue, fatal ? "" : ", ignoring", path); - - return 0; -} - char *path_startswith_full(const char *path, const char *prefix, bool accept_dot_dot) { assert(path); assert(prefix); @@ -1314,74 +1264,6 @@ bool valid_device_allow_pattern(const char *path) { return valid_device_node_path(path); } -int systemd_installation_has_version(const char *root, unsigned minimal_version) { - const char *pattern; - int r; - - /* Try to guess if systemd installation is later than the specified version. This - * is hacky and likely to yield false negatives, particularly if the installation - * is non-standard. False positives should be relatively rare. - */ - - NULSTR_FOREACH(pattern, - /* /lib works for systems without usr-merge, and for systems with a sane - * usr-merge, where /lib is a symlink to /usr/lib. /usr/lib is necessary - * for Gentoo which does a merge without making /lib a symlink. - */ - "lib/systemd/libsystemd-shared-*.so\0" - "lib64/systemd/libsystemd-shared-*.so\0" - "usr/lib/systemd/libsystemd-shared-*.so\0" - "usr/lib64/systemd/libsystemd-shared-*.so\0") { - - _cleanup_strv_free_ char **names = NULL; - _cleanup_free_ char *path = NULL; - char *c; - - path = path_join(root, pattern); - if (!path) - return -ENOMEM; - - r = glob_extend(&names, path, 0); - if (r == -ENOENT) - continue; - if (r < 0) - return r; - - assert_se(c = endswith(path, "*.so")); - *c = '\0'; /* truncate the glob part */ - - STRV_FOREACH(name, names) { - /* This is most likely to run only once, hence let's not optimize anything. */ - char *t, *t2; - unsigned version; - - t = startswith(*name, path); - if (!t) - continue; - - t2 = endswith(t, ".so"); - if (!t2) - continue; - - t2[0] = '\0'; /* truncate the suffix */ - - r = safe_atou(t, &version); - if (r < 0) { - log_debug_errno(r, "Found libsystemd shared at \"%s.so\", but failed to parse version: %m", *name); - continue; - } - - log_debug("Found libsystemd shared at \"%s.so\", version %u (%s).", - *name, version, - version >= minimal_version ? "OK" : "too old"); - if (version >= minimal_version) - return true; - } - } - - return false; -} - bool dot_or_dot_dot(const char *path) { if (!path) return false; diff --git a/src/libnm-systemd-shared/src/basic/path-util.h b/src/libnm-systemd-shared/src/basic/path-util.h index 518f3340bf..553aa4fb58 100644 --- a/src/libnm-systemd-shared/src/basic/path-util.h +++ b/src/libnm-systemd-shared/src/basic/path-util.h @@ -77,14 +77,6 @@ char* path_extend_internal(char **x, ...); char* path_simplify(char *path); -enum { - PATH_CHECK_FATAL = 1 << 0, /* If not set, then error message is appended with 'ignoring'. */ - PATH_CHECK_ABSOLUTE = 1 << 1, - PATH_CHECK_RELATIVE = 1 << 2, -}; - -int path_simplify_and_warn(char *path, unsigned flag, const char *unit, const char *filename, unsigned line, const char *lvalue); - static inline bool path_equal_ptr(const char *a, const char *b) { return !!a == !!b && (!a || path_equal(a, b)); } @@ -181,8 +173,6 @@ bool is_device_path(const char *path); bool valid_device_node_path(const char *path); bool valid_device_allow_pattern(const char *path); -int systemd_installation_has_version(const char *root, unsigned minimal_version); - bool dot_or_dot_dot(const char *path); static inline const char *skip_dev_prefix(const char *p) { diff --git a/src/libnm-systemd-shared/src/basic/process-util.c b/src/libnm-systemd-shared/src/basic/process-util.c index 204a5d9490..6980e0c4f6 100644 --- a/src/libnm-systemd-shared/src/basic/process-util.c +++ b/src/libnm-systemd-shared/src/basic/process-util.c @@ -1026,7 +1026,7 @@ bool oom_score_adjust_is_valid(int oa) { } unsigned long personality_from_string(const char *p) { - int architecture; + Architecture architecture; if (!p) return PERSONALITY_INVALID; @@ -1050,7 +1050,7 @@ unsigned long personality_from_string(const char *p) { } const char* personality_to_string(unsigned long p) { - int architecture = _ARCHITECTURE_INVALID; + Architecture architecture = _ARCHITECTURE_INVALID; if (p == PER_LINUX) architecture = native_architecture(); diff --git a/src/libnm-systemd-shared/src/basic/random-util.c b/src/libnm-systemd-shared/src/basic/random-util.c index f2e68fcddd..9423a0805d 100644 --- a/src/libnm-systemd-shared/src/basic/random-util.c +++ b/src/libnm-systemd-shared/src/basic/random-util.c @@ -30,185 +30,142 @@ #include "missing_syscall.h" #include "parse-util.h" #include "random-util.h" -#include "siphash24.h" +#include "sha256.h" #include "time-util.h" -static bool srand_called = false; +/* This is a "best effort" kind of thing, but has no real security value. + * So, this should only be used by random_bytes(), which is not meant for + * crypto. This could be made better, but we're *not* trying to roll a + * userspace prng here, or even have forward secrecy, but rather just do + * the shortest thing that is at least better than libc rand(). */ +static void fallback_random_bytes(void *p, size_t n) { + static thread_local uint64_t fallback_counter = 0; + struct { + char label[32]; + uint64_t call_id, block_id; + usec_t stamp_mono, stamp_real; + pid_t pid, tid; + uint8_t auxval[16]; + } state = { + /* Arbitrary domain separation to prevent other usage of AT_RANDOM from clashing. */ + .label = "systemd fallback random bytes v1", + .call_id = fallback_counter++, + .stamp_mono = now(CLOCK_MONOTONIC), + .stamp_real = now(CLOCK_REALTIME), + .pid = getpid(), + .tid = gettid() + }; -int genuine_random_bytes(void *p, size_t n, RandomFlags flags) { - static int have_syscall = -1; - _cleanup_close_ int fd = -1; +#if HAVE_SYS_AUXV_H + memcpy(state.auxval, ULONG_TO_PTR(getauxval(AT_RANDOM)), sizeof(state.auxval)); +#endif - /* Gathers some high-quality randomness from the kernel. This call won't block, unless the RANDOM_BLOCK - * flag is set. If it doesn't block, it will still always return some data from the kernel, regardless - * of whether the random pool is fully initialized or not. When creating cryptographic key material you - * should always use RANDOM_BLOCK. */ + while (n > 0) { + struct sha256_ctx ctx; - if (n == 0) - return 0; - - /* Use the getrandom() syscall unless we know we don't have it. */ - if (have_syscall != 0 && !HAS_FEATURE_MEMORY_SANITIZER) { - for (;;) { - ssize_t l = getrandom(p, n, FLAGS_SET(flags, RANDOM_BLOCK) ? 0 : GRND_INSECURE); - - if (l > 0) { - have_syscall = true; - - if ((size_t) l == n) - return 0; /* Yay, success! */ - - /* We didn't get enough data, so try again */ - assert((size_t) l < n); - p = (uint8_t*) p + l; - n -= l; - continue; - - } else if (l == 0) { - have_syscall = true; - return -EIO; - - } else if (ERRNO_IS_NOT_SUPPORTED(errno)) { - /* We lack the syscall, continue with reading from /dev/urandom. */ - have_syscall = false; - break; - - } else if (errno == EINVAL) { - /* If we previously passed GRND_INSECURE, and this flag isn't known, then - * we're likely running an old kernel which has getrandom() but not - * GRND_INSECURE. In this case, fall back to /dev/urandom. */ - if (!FLAGS_SET(flags, RANDOM_BLOCK)) - break; - - return -errno; - } else - return -errno; + sha256_init_ctx(&ctx); + sha256_process_bytes(&state, sizeof(state), &ctx); + if (n < SHA256_DIGEST_SIZE) { + uint8_t partial[SHA256_DIGEST_SIZE]; + sha256_finish_ctx(&ctx, partial); + memcpy(p, partial, n); + break; } - } - - fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); - if (fd < 0) - return errno == ENOENT ? -ENOSYS : -errno; - - return loop_read_exact(fd, p, n, true); -} - -static void clear_srand_initialization(void) { - srand_called = false; -} - -void initialize_srand(void) { - static bool pthread_atfork_registered = false; - unsigned x; -#if HAVE_SYS_AUXV_H - const void *auxv; -#endif - if (srand_called) - return; - -#if HAVE_SYS_AUXV_H - /* The kernel provides us with 16 bytes of entropy in auxv, so let's try to make use of that to seed - * the pseudo-random generator. It's better than nothing... But let's first hash it to make it harder - * to recover the original value by watching any pseudo-random bits we generate. After all the - * AT_RANDOM data might be used by other stuff too (in particular: ASLR), and we probably shouldn't - * leak the seed for that. */ - - auxv = ULONG_TO_PTR(getauxval(AT_RANDOM)); - if (auxv) { - static const uint8_t auxval_hash_key[16] = { - 0x92, 0x6e, 0xfe, 0x1b, 0xcf, 0x00, 0x52, 0x9c, 0xcc, 0x42, 0xcf, 0xdc, 0x94, 0x1f, 0x81, 0x0f - }; - - x = (unsigned) siphash24(auxv, 16, auxval_hash_key); - } else -#endif - x = 0; - - x ^= (unsigned) now(CLOCK_REALTIME); - x ^= (unsigned) gettid(); - - srand(x); - srand_called = true; - - if (!pthread_atfork_registered) { - (void) pthread_atfork(NULL, NULL, clear_srand_initialization); - pthread_atfork_registered = true; - } -} - -/* INT_MAX gives us only 31 bits, so use 24 out of that. */ -#if RAND_MAX >= INT_MAX -assert_cc(RAND_MAX >= 16777215); -# define RAND_STEP 3 -#else -/* SHORT_INT_MAX or lower gives at most 15 bits, we just use 8 out of that. */ -assert_cc(RAND_MAX >= 255); -# define RAND_STEP 1 -#endif - -void pseudo_random_bytes(void *p, size_t n) { - uint8_t *q; - - /* This returns pseudo-random data using libc's rand() function. You probably never want to call this - * directly, because why would you use this if you can get better stuff cheaply? Use random_bytes() - * instead, see below: it will fall back to this function if there's nothing better to get, but only - * then. */ - - initialize_srand(); - - for (q = p; q < (uint8_t*) p + n; q += RAND_STEP) { - unsigned rr; - - rr = (unsigned) rand(); - -#if RAND_STEP >= 3 - if ((size_t) (q - (uint8_t*) p + 2) < n) - q[2] = rr >> 16; -#endif -#if RAND_STEP >= 2 - if ((size_t) (q - (uint8_t*) p + 1) < n) - q[1] = rr >> 8; -#endif - q[0] = rr; + sha256_finish_ctx(&ctx, p); + p = (uint8_t *) p + SHA256_DIGEST_SIZE; + n -= SHA256_DIGEST_SIZE; + ++state.block_id; } } void random_bytes(void *p, size_t n) { + static bool have_getrandom = true, have_grndinsecure = true; + _cleanup_close_ int fd = -1; - /* This returns high quality randomness if we can get it cheaply. If we can't because for some reason - * it is not available we'll try some crappy fallbacks. - * - * What this function will do: - * - * • Use getrandom(GRND_INSECURE) or /dev/urandom, to return high-quality random values if - * they are cheaply available, or less high-quality random values if they are not. - * - * • This function will return pseudo-random data, generated via libc rand() if nothing - * better is available. - * - * • This function will work fine in early boot - * - * • This function will always succeed - * - * What this function won't do: - * - * • This function will never fail: it will give you randomness no matter what. It might not - * be high quality, but it will return some, possibly generated via libc's rand() call. - * - * • This function will never block: if the only way to get good randomness is a blocking, - * synchronous getrandom() we'll instead provide you with pseudo-random data. - * - * This function is hence great for things like seeding hash tables, generating random numeric UNIX - * user IDs (that are checked for collisions before use) and such. - * - * This function is hence not useful for generating UUIDs or cryptographic key material. - */ - - if (genuine_random_bytes(p, n, 0) >= 0) + if (n == 0) return; - /* If for some reason some user made /dev/urandom unavailable to us, or the kernel has no entropy, use a PRNG instead. */ - pseudo_random_bytes(p, n); + for (;;) { + ssize_t l; + + if (!have_getrandom) + break; + + l = getrandom(p, n, have_grndinsecure ? GRND_INSECURE : GRND_NONBLOCK); + if (l > 0) { + if ((size_t) l == n) + return; /* Done reading, success. */ + p = (uint8_t *) p + l; + n -= l; + continue; /* Interrupted by a signal; keep going. */ + } else if (l == 0) + break; /* Weird, so fallback to /dev/urandom. */ + else if (ERRNO_IS_NOT_SUPPORTED(errno)) { + have_getrandom = false; + break; /* No syscall, so fallback to /dev/urandom. */ + } else if (errno == EINVAL && have_grndinsecure) { + have_grndinsecure = false; + continue; /* No GRND_INSECURE; fallback to GRND_NONBLOCK. */ + } else if (errno == EAGAIN && !have_grndinsecure) + break; /* Will block, but no GRND_INSECURE, so fallback to /dev/urandom. */ + + break; /* Unexpected, so just give up and fallback to /dev/urandom. */ + } + + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd >= 0 && loop_read_exact(fd, p, n, false) == 0) + return; + + /* This is a terrible fallback. Oh well. */ + fallback_random_bytes(p, n); +} + +int crypto_random_bytes(void *p, size_t n) { + static bool have_getrandom = true, seen_initialized = false; + _cleanup_close_ int fd = -1; + + if (n == 0) + return 0; + + for (;;) { + ssize_t l; + + if (!have_getrandom) + break; + + l = getrandom(p, n, 0); + if (l > 0) { + if ((size_t) l == n) + return 0; /* Done reading, success. */ + p = (uint8_t *) p + l; + n -= l; + continue; /* Interrupted by a signal; keep going. */ + } else if (l == 0) + return -EIO; /* Weird, should never happen. */ + else if (ERRNO_IS_NOT_SUPPORTED(errno)) { + have_getrandom = false; + break; /* No syscall, so fallback to /dev/urandom. */ + } + return -errno; + } + + if (!seen_initialized) { + _cleanup_close_ int ready_fd = -1; + int r; + + ready_fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (ready_fd < 0) + return -errno; + r = fd_wait_for_event(ready_fd, POLLIN, USEC_INFINITY); + if (r < 0) + return r; + seen_initialized = true; + } + + fd = open("/dev/urandom", O_RDONLY|O_CLOEXEC|O_NOCTTY); + if (fd < 0) + return -errno; + return loop_read_exact(fd, p, n, false); } size_t random_pool_size(void) { diff --git a/src/libnm-systemd-shared/src/basic/random-util.h b/src/libnm-systemd-shared/src/basic/random-util.h index ccee32792f..2d99807272 100644 --- a/src/libnm-systemd-shared/src/basic/random-util.h +++ b/src/libnm-systemd-shared/src/basic/random-util.h @@ -5,15 +5,8 @@ #include #include -typedef enum RandomFlags { - RANDOM_BLOCK = 1 << 0, /* Rather block than return crap randomness (only if the kernel supports that) */ -} RandomFlags; - -int genuine_random_bytes(void *p, size_t n, RandomFlags flags); /* returns "genuine" randomness, optionally filled up with pseudo random, if not enough is available */ -void pseudo_random_bytes(void *p, size_t n); /* returns only pseudo-randommess (but possibly seeded from something better) */ -void random_bytes(void *p, size_t n); /* returns genuine randomness if cheaply available, and pseudo randomness if not. */ - -void initialize_srand(void); +void random_bytes(void *p, size_t n); /* Returns random bytes suitable for most uses, but may be insecure sometimes. */ +int crypto_random_bytes(void *p, size_t n); /* Returns secure random bytes after waiting for the RNG to initialize. */ static inline uint64_t random_u64(void) { uint64_t u; diff --git a/src/libnm-systemd-shared/src/basic/set.h b/src/libnm-systemd-shared/src/basic/set.h index 5cae13160b..52cf63e2dd 100644 --- a/src/libnm-systemd-shared/src/basic/set.h +++ b/src/libnm-systemd-shared/src/basic/set.h @@ -127,9 +127,12 @@ int _set_ensure_consume(Set **s, const struct hash_ops *hash_ops, void *key HAS int set_consume(Set *s, void *value); -int _set_put_strdup_full(Set **s, const struct hash_ops *hash_ops, const char *p HASHMAP_DEBUG_PARAMS); -#define set_put_strdup_full(s, hash_ops, p) _set_put_strdup_full(s, hash_ops, p HASHMAP_DEBUG_SRC_ARGS) -#define set_put_strdup(s, p) set_put_strdup_full(s, &string_hash_ops_free, p) +int _set_put_strndup_full(Set **s, const struct hash_ops *hash_ops, const char *p, size_t n HASHMAP_DEBUG_PARAMS); +#define set_put_strndup_full(s, hash_ops, p, n) _set_put_strndup_full(s, hash_ops, p, n HASHMAP_DEBUG_SRC_ARGS) +#define set_put_strdup_full(s, hash_ops, p) set_put_strndup_full(s, hash_ops, p, SIZE_MAX) +#define set_put_strndup(s, p, n) set_put_strndup_full(s, &string_hash_ops_free, p, n) +#define set_put_strdup(s, p) set_put_strndup(s, p, SIZE_MAX) + int _set_put_strdupv_full(Set **s, const struct hash_ops *hash_ops, char **l HASHMAP_DEBUG_PARAMS); #define set_put_strdupv_full(s, hash_ops, l) _set_put_strdupv_full(s, hash_ops, l HASHMAP_DEBUG_SRC_ARGS) #define set_put_strdupv(s, l) set_put_strdupv_full(s, &string_hash_ops_free, l) @@ -153,3 +156,5 @@ DEFINE_TRIVIAL_CLEANUP_FUNC(Set*, set_free_free); int set_strjoin(Set *s, const char *separator, bool wrap_with_separator, char **ret); bool set_equal(Set *a, Set *b); + +bool set_fnmatch(Set *include_patterns, Set *exclude_patterns, const char *needle); diff --git a/src/libnm-systemd-shared/src/basic/socket-util.c b/src/libnm-systemd-shared/src/basic/socket-util.c index 8d0494ece5..f39be19a59 100644 --- a/src/libnm-systemd-shared/src/basic/socket-util.c +++ b/src/libnm-systemd-shared/src/basic/socket-util.c @@ -490,9 +490,7 @@ int sockaddr_pretty( if (r < 0) return -ENOMEM; } else { - char a[INET6_ADDRSTRLEN]; - - inet_ntop(AF_INET6, &sa->in6.sin6_addr, a, sizeof(a)); + const char *a = IN6_ADDR_TO_STRING(&sa->in6.sin6_addr); if (include_port) { if (asprintf(&p, @@ -651,24 +649,24 @@ int socknameinfo_pretty(union sockaddr_union *sa, socklen_t salen, char **_ret) } static const char* const netlink_family_table[] = { - [NETLINK_ROUTE] = "route", - [NETLINK_FIREWALL] = "firewall", - [NETLINK_INET_DIAG] = "inet-diag", - [NETLINK_NFLOG] = "nflog", - [NETLINK_XFRM] = "xfrm", - [NETLINK_SELINUX] = "selinux", - [NETLINK_ISCSI] = "iscsi", - [NETLINK_AUDIT] = "audit", - [NETLINK_FIB_LOOKUP] = "fib-lookup", - [NETLINK_CONNECTOR] = "connector", - [NETLINK_NETFILTER] = "netfilter", - [NETLINK_IP6_FW] = "ip6-fw", - [NETLINK_DNRTMSG] = "dnrtmsg", + [NETLINK_ROUTE] = "route", + [NETLINK_FIREWALL] = "firewall", + [NETLINK_INET_DIAG] = "inet-diag", + [NETLINK_NFLOG] = "nflog", + [NETLINK_XFRM] = "xfrm", + [NETLINK_SELINUX] = "selinux", + [NETLINK_ISCSI] = "iscsi", + [NETLINK_AUDIT] = "audit", + [NETLINK_FIB_LOOKUP] = "fib-lookup", + [NETLINK_CONNECTOR] = "connector", + [NETLINK_NETFILTER] = "netfilter", + [NETLINK_IP6_FW] = "ip6-fw", + [NETLINK_DNRTMSG] = "dnrtmsg", [NETLINK_KOBJECT_UEVENT] = "kobject-uevent", - [NETLINK_GENERIC] = "generic", - [NETLINK_SCSITRANSPORT] = "scsitransport", - [NETLINK_ECRYPTFS] = "ecryptfs", - [NETLINK_RDMA] = "rdma", + [NETLINK_GENERIC] = "generic", + [NETLINK_SCSITRANSPORT] = "scsitransport", + [NETLINK_ECRYPTFS] = "ecryptfs", + [NETLINK_RDMA] = "rdma", }; DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(netlink_family, int, INT_MAX); @@ -775,10 +773,10 @@ int fd_set_rcvbuf(int fd, size_t n, bool increase) { } static const char* const ip_tos_table[] = { - [IPTOS_LOWDELAY] = "low-delay", - [IPTOS_THROUGHPUT] = "throughput", + [IPTOS_LOWDELAY] = "low-delay", + [IPTOS_THROUGHPUT] = "throughput", [IPTOS_RELIABILITY] = "reliability", - [IPTOS_LOWCOST] = "low-cost", + [IPTOS_LOWCOST] = "low-cost", }; DEFINE_STRING_TABLE_LOOKUP_WITH_FALLBACK(ip_tos, int, 0xff); @@ -835,7 +833,7 @@ bool ifname_valid_full(const char *p, IfnameValidFlags flags) { if (!ifname_valid_char(*t)) return false; - numeric = numeric && (*t >= '0' && *t <= '9'); + numeric = numeric && ascii_isdigit(*t); } /* It's fully numeric but didn't parse as valid ifindex above? if so, it must be too large or zero or @@ -1236,7 +1234,10 @@ int sockaddr_un_set_path(struct sockaddr_un *ret, const char *path) { * addresses!), which the kernel doesn't. We do this to reduce chance of incompatibility with other apps that * do not expect non-NUL terminated file system path. */ if (l+1 > sizeof(ret->sun_path)) - return -EINVAL; + return path[0] == '@' ? -EINVAL : -ENAMETOOLONG; /* return a recognizable error if this is + * too long to fit into a sockaddr_un, but + * is a file system path, and thus might be + * connectible via O_PATH indirection. */ *ret = (struct sockaddr_un) { .sun_family = AF_UNIX, @@ -1423,3 +1424,51 @@ int socket_get_mtu(int fd, int af, size_t *ret) { *ret = (size_t) mtu; return 0; } + +int connect_unix_path(int fd, int dir_fd, const char *path) { + _cleanup_close_ int inode_fd = -1; + union sockaddr_union sa = { + .un.sun_family = AF_UNIX, + }; + size_t path_len; + socklen_t salen; + + assert(fd >= 0); + assert(dir_fd == AT_FDCWD || dir_fd >= 0); + assert(path); + + /* Connects to the specified AF_UNIX socket in the file system. Works around the 108 byte size limit + * in sockaddr_un, by going via O_PATH if needed. This hence works for any kind of path. */ + + path_len = strlen(path); + + /* Refuse zero length path early, to make sure AF_UNIX stack won't mistake this for an abstract + * namespace path, since first char is NUL */ + if (path_len <= 0) + return -EINVAL; + + if (dir_fd == AT_FDCWD && path_len < sizeof(sa.un.sun_path)) { + memcpy(sa.un.sun_path, path, path_len + 1); + salen = offsetof(struct sockaddr_un, sun_path) + path_len + 1; + } else { + const char *proc; + size_t proc_len; + + /* If dir_fd is specified, then we need to go the indirect O_PATH route, because connectat() + * does not exist. If the path is too long, we also need to take the indirect route, since we + * can't fit this into a sockaddr_un directly. */ + + inode_fd = openat(dir_fd, path, O_PATH|O_CLOEXEC); + if (inode_fd < 0) + return -errno; + + proc = FORMAT_PROC_FD_PATH(inode_fd); + proc_len = strlen(proc); + + assert(proc_len < sizeof(sa.un.sun_path)); + memcpy(sa.un.sun_path, proc, proc_len + 1); + salen = offsetof(struct sockaddr_un, sun_path) + proc_len + 1; + } + + return RET_NERRNO(connect(fd, &sa.sa, salen)); +} diff --git a/src/libnm-systemd-shared/src/basic/socket-util.h b/src/libnm-systemd-shared/src/basic/socket-util.h index 2fd1a2a165..2e36e1a56b 100644 --- a/src/libnm-systemd-shared/src/basic/socket-util.h +++ b/src/libnm-systemd-shared/src/basic/socket-util.h @@ -129,7 +129,7 @@ static inline int fd_inc_sndbuf(int fd, size_t n) { return fd_set_sndbuf(fd, n, true); } int fd_set_rcvbuf(int fd, size_t n, bool increase); -static inline int fd_inc_rcvbuf(int fd, size_t n) { +static inline int fd_increase_rxbuf(int fd, size_t n) { return fd_set_rcvbuf(fd, n, true); } @@ -224,9 +224,9 @@ struct cmsghdr* cmsg_find(struct msghdr *mh, int level, int type, socklen_t leng strnlen(_sa->sun_path, sizeof(_sa->sun_path))+1); \ }) -#define SOCKADDR_LEN(sa) \ +#define SOCKADDR_LEN(saddr) \ ({ \ - const union sockaddr_union *__sa = &(sa); \ + const union sockaddr_union *__sa = &(saddr); \ size_t _len; \ switch (__sa->sa.sa_family) { \ case AF_INET: \ @@ -332,3 +332,5 @@ int socket_get_mtu(int fd, int af, size_t *ret); /* an initializer for struct ucred that initialized all fields to the invalid value appropriate for each */ #define UCRED_INVALID { .pid = 0, .uid = UID_INVALID, .gid = GID_INVALID } + +int connect_unix_path(int fd, int dir_fd, const char *path); diff --git a/src/libnm-systemd-shared/src/basic/stat-util.c b/src/libnm-systemd-shared/src/basic/stat-util.c index b25cabc6b4..64c2f80f3c 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.c +++ b/src/libnm-systemd-shared/src/basic/stat-util.c @@ -71,13 +71,10 @@ int is_device_node(const char *path) { return !!(S_ISBLK(info.st_mode) || S_ISCHR(info.st_mode)); } -int dir_is_empty_at(int dir_fd, const char *path) { +int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup) { _cleanup_close_ int fd = -1; - /* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." + - * ".."), and only once we have seen if there's a third we know whether the dir is empty or not. */ - DEFINE_DIRENT_BUFFER(buffer, 3); - struct dirent *de; - ssize_t n; + struct dirent *buf; + size_t m; if (path) { assert(dir_fd >= 0 || dir_fd == AT_FDCWD); @@ -99,15 +96,30 @@ int dir_is_empty_at(int dir_fd, const char *path) { return fd; } - n = getdents64(fd, &buffer, sizeof(buffer)); - if (n < 0) - return -errno; + /* Allocate space for at least 3 full dirents, since every dir has at least two entries ("." + + * ".."), and only once we have seen if there's a third we know whether the dir is empty or not. If + * 'ignore_hidden_or_backup' is true we'll allocate a bit more, since we might skip over a bunch of + * entries that we end up ignoring. */ + m = (ignore_hidden_or_backup ? 16 : 3) * DIRENT_SIZE_MAX; + buf = alloca(m); - msan_unpoison(&buffer, n); + for (;;) { + struct dirent *de; + ssize_t n; - FOREACH_DIRENT_IN_BUFFER(de, &buffer.de, n) - if (!dot_or_dot_dot(de->d_name)) - return 0; + n = getdents64(fd, buf, m); + if (n < 0) + return -errno; + if (n == 0) + break; + + assert((size_t) n <= m); + msan_unpoison(buf, n); + + FOREACH_DIRENT_IN_BUFFER(de, buf, n) + if (!(ignore_hidden_or_backup ? hidden_or_backup_file(de->d_name) : dot_or_dot_dot(de->d_name))) + return 0; + } return 1; } @@ -314,101 +326,6 @@ int fd_verify_directory(int fd) { return stat_verify_directory(&st); } -int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret) { - const char *t; - - /* Generates the /dev/{char|block}/MAJOR:MINOR path for a dev_t */ - - if (S_ISCHR(mode)) - t = "char"; - else if (S_ISBLK(mode)) - t = "block"; - else - return -ENODEV; - - if (asprintf(ret, "/dev/%s/%u:%u", t, major(devno), minor(devno)) < 0) - return -ENOMEM; - - return 0; -} - -int device_path_make_canonical(mode_t mode, dev_t devno, char **ret) { - _cleanup_free_ char *p = NULL; - int r; - - /* Finds the canonical path for a device, i.e. resolves the /dev/{char|block}/MAJOR:MINOR path to the end. */ - - assert(ret); - - if (major(devno) == 0 && minor(devno) == 0) { - char *s; - - /* A special hack to make sure our 'inaccessible' device nodes work. They won't have symlinks in - * /dev/block/ and /dev/char/, hence we handle them specially here. */ - - if (S_ISCHR(mode)) - s = strdup("/run/systemd/inaccessible/chr"); - else if (S_ISBLK(mode)) - s = strdup("/run/systemd/inaccessible/blk"); - else - return -ENODEV; - - if (!s) - return -ENOMEM; - - *ret = s; - return 0; - } - - r = device_path_make_major_minor(mode, devno, &p); - if (r < 0) - return r; - - return chase_symlinks(p, NULL, 0, ret, NULL); -} - -int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno) { - mode_t mode; - dev_t devno; - int r; - - /* Tries to extract the major/minor directly from the device path if we can. Handles /dev/block/ and /dev/char/ - * paths, as well out synthetic inaccessible device nodes. Never goes to disk. Returns -ENODEV if the device - * path cannot be parsed like this. */ - - if (path_equal(path, "/run/systemd/inaccessible/chr")) { - mode = S_IFCHR; - devno = makedev(0, 0); - } else if (path_equal(path, "/run/systemd/inaccessible/blk")) { - mode = S_IFBLK; - devno = makedev(0, 0); - } else { - const char *w; - - w = path_startswith(path, "/dev/block/"); - if (w) - mode = S_IFBLK; - else { - w = path_startswith(path, "/dev/char/"); - if (!w) - return -ENODEV; - - mode = S_IFCHR; - } - - r = parse_dev(w, &devno); - if (r < 0) - return r; - } - - if (ret_mode) - *ret_mode = mode; - if (ret_devno) - *ret_devno = devno; - - return 0; -} - int proc_mounted(void) { int r; diff --git a/src/libnm-systemd-shared/src/basic/stat-util.h b/src/libnm-systemd-shared/src/basic/stat-util.h index 37513a43e7..7f0b3dc0af 100644 --- a/src/libnm-systemd-shared/src/basic/stat-util.h +++ b/src/libnm-systemd-shared/src/basic/stat-util.h @@ -17,17 +17,9 @@ int is_dir(const char *path, bool follow); int is_dir_fd(int fd); int is_device_node(const char *path); -int dir_is_empty_at(int dir_fd, const char *path); -static inline int dir_is_empty(const char *path) { - return dir_is_empty_at(AT_FDCWD, path); -} - -static inline int dir_is_populated(const char *path) { - int r; - r = dir_is_empty(path); - if (r < 0) - return r; - return !r; +int dir_is_empty_at(int dir_fd, const char *path, bool ignore_hidden_or_backup); +static inline int dir_is_empty(const char *path, bool ignore_hidden_or_backup) { + return dir_is_empty_at(AT_FDCWD, path, ignore_hidden_or_backup); } bool null_or_empty(struct stat *st) _pure_; @@ -71,29 +63,6 @@ int fd_verify_regular(int fd); int stat_verify_directory(const struct stat *st); int fd_verify_directory(int fd); -/* glibc and the Linux kernel have different ideas about the major/minor size. These calls will check whether the - * specified major is valid by the Linux kernel's standards, not by glibc's. Linux has 20bits of minor, and 12 bits of - * major space. See MINORBITS in linux/kdev_t.h in the kernel sources. (If you wonder why we define _y here, instead of - * comparing directly >= 0: it's to trick out -Wtype-limits, which would otherwise complain if the type is unsigned, as - * such a test would be pointless in such a case.) */ - -#define DEVICE_MAJOR_VALID(x) \ - ({ \ - typeof(x) _x = (x), _y = 0; \ - _x >= _y && _x < (UINT32_C(1) << 12); \ - \ - }) - -#define DEVICE_MINOR_VALID(x) \ - ({ \ - typeof(x) _x = (x), _y = 0; \ - _x >= _y && _x < (UINT32_C(1) << 20); \ - }) - -int device_path_make_major_minor(mode_t mode, dev_t devno, char **ret); -int device_path_make_canonical(mode_t mode, dev_t devno, char **ret); -int device_path_parse_major_minor(const char *path, mode_t *ret_mode, dev_t *ret_devno); - int proc_mounted(void); bool stat_inode_same(const struct stat *a, const struct stat *b); @@ -119,9 +88,3 @@ int statx_fallback(int dfd, const char *path, int flags, unsigned mask, struct s struct new_statx nsx; \ } var #endif - -static inline bool devid_set_and_equal(dev_t a, dev_t b) { - /* Returns true if a and b definitely refer to the same device. If either is zero, this means "don't - * know" and we'll return false */ - return a == b && a != 0; -} diff --git a/src/libnm-systemd-shared/src/basic/string-util.c b/src/libnm-systemd-shared/src/basic/string-util.c index 6ceaeaf9df..128aea99c0 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.c +++ b/src/libnm-systemd-shared/src/basic/string-util.c @@ -1162,3 +1162,30 @@ bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok) { return in_charset(s1, ok) && in_charset(s2, ok); } + +char *string_replace_char(char *str, char old_char, char new_char) { + assert(str); + assert(old_char != '\0'); + assert(new_char != '\0'); + assert(old_char != new_char); + + for (char *p = strchr(str, old_char); p; p = strchr(p + 1, old_char)) + *p = new_char; + + return str; +} + +size_t strspn_from_end(const char *str, const char *accept) { + size_t n = 0; + + if (isempty(str)) + return 0; + + if (isempty(accept)) + return 0; + + for (const char *p = str + strlen(str); p > str && strchr(accept, p[-1]); p--) + n++; + + return n; +} diff --git a/src/libnm-systemd-shared/src/basic/string-util.h b/src/libnm-systemd-shared/src/basic/string-util.h index a1d88fbb95..1dd46f7f20 100644 --- a/src/libnm-systemd-shared/src/basic/string-util.h +++ b/src/libnm-systemd-shared/src/basic/string-util.h @@ -10,17 +10,18 @@ #include "string-util-fundamental.h" /* What is interpreted as whitespace? */ -#define WHITESPACE " \t\n\r" -#define NEWLINE "\n\r" -#define QUOTES "\"\'" -#define COMMENTS "#;" -#define GLOB_CHARS "*?[" -#define DIGITS "0123456789" -#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" -#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" -#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS -#define ALPHANUMERICAL LETTERS DIGITS -#define HEXDIGITS DIGITS "abcdefABCDEF" +#define WHITESPACE " \t\n\r" +#define NEWLINE "\n\r" +#define QUOTES "\"\'" +#define COMMENTS "#;" +#define GLOB_CHARS "*?[" +#define DIGITS "0123456789" +#define LOWERCASE_LETTERS "abcdefghijklmnopqrstuvwxyz" +#define UPPERCASE_LETTERS "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +#define LETTERS LOWERCASE_LETTERS UPPERCASE_LETTERS +#define ALPHANUMERICAL LETTERS DIGITS +#define HEXDIGITS DIGITS "abcdefABCDEF" +#define LOWERCASE_HEXDIGITS DIGITS "abcdef" static inline char* strstr_ptr(const char *haystack, const char *needle) { if (!haystack || !needle) @@ -28,10 +29,6 @@ static inline char* strstr_ptr(const char *haystack, const char *needle) { return strstr(haystack, needle); } -static inline const char* strempty(const char *s) { - return s ?: ""; -} - static inline const char* strnull(const char *s) { return s ?: "(null)"; } @@ -180,13 +177,6 @@ int free_and_strndup(char **p, const char *s, size_t l); bool string_is_safe(const char *p) _pure_; -static inline size_t strlen_ptr(const char *s) { - if (!s) - return 0; - - return strlen(s); -} - DISABLE_WARNING_STRINGOP_TRUNCATION; static inline void strncpy_exact(char *buf, const char *src, size_t buf_len) { strncpy(buf, src, buf_len); @@ -232,3 +222,7 @@ static inline int string_contains_word(const char *string, const char *separator } bool streq_skip_trailing_chars(const char *s1, const char *s2, const char *ok); + +char *string_replace_char(char *str, char old_char, char new_char); + +size_t strspn_from_end(const char *str, const char *accept); diff --git a/src/libnm-systemd-shared/src/basic/strv.c b/src/libnm-systemd-shared/src/basic/strv.c index c4e3dad446..b2fe8d9d4e 100644 --- a/src/libnm-systemd-shared/src/basic/strv.c +++ b/src/libnm-systemd-shared/src/basic/strv.c @@ -351,7 +351,7 @@ int strv_split_colon_pairs(char ***t, const char *s) { return (int) n; } -char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool unescape_separators) { +char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator) { char *r, *e; size_t n, k, m; @@ -361,7 +361,7 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix, k = strlen(separator); m = strlen_ptr(prefix); - if (unescape_separators) /* If there separator is multi-char, we won't know how to escape it. */ + if (escape_separator) /* If the separator was multi-char, we wouldn't know how to escape it. */ assert(k == 1); n = 0; @@ -369,7 +369,7 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix, if (s != l) n += k; - bool needs_escaping = unescape_separators && strchr(*s, separator[0]); + bool needs_escaping = escape_separator && strchr(*s, *separator); n += m + strlen(*s) * (1 + needs_escaping); } @@ -386,11 +386,11 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix, if (prefix) e = stpcpy(e, prefix); - bool needs_escaping = unescape_separators && strchr(*s, separator[0]); + bool needs_escaping = escape_separator && strchr(*s, *separator); if (needs_escaping) for (size_t i = 0; (*s)[i]; i++) { - if ((*s)[i] == separator[0]) + if ((*s)[i] == *separator) *(e++) = '\\'; *(e++) = (*s)[i]; } @@ -403,27 +403,33 @@ char* strv_join_full(char * const *l, const char *separator, const char *prefix, return r; } -int strv_push(char ***l, char *value) { - char **c; - size_t n; +int strv_push_with_size(char ***l, size_t *n, char *value) { + /* n is a pointer to a variable to store the size of l. + * If not given (i.e. n is NULL or *n is SIZE_MAX), size will be calculated using strv_length(). + * If n is not NULL, the size after the push will be returned. + * If value is empty, no action is taken and *n is not set. */ if (!value) return 0; - n = strv_length(*l); + size_t size = n ? *n : SIZE_MAX; + if (size == SIZE_MAX) + size = strv_length(*l); /* Check for overflow */ - if (n > SIZE_MAX-2) + if (size > SIZE_MAX-2) return -ENOMEM; - c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(n + 2), sizeof(char*)); + char **c = reallocarray(*l, GREEDY_ALLOC_ROUND_UP(size + 2), sizeof(char*)); if (!c) return -ENOMEM; - c[n] = value; - c[n+1] = NULL; + c[size] = value; + c[size+1] = NULL; *l = c; + if (n) + *n = size + 1; return 0; } @@ -484,10 +490,10 @@ int strv_insert(char ***l, size_t position, char *value) { return free_and_replace(*l, c); } -int strv_consume(char ***l, char *value) { +int strv_consume_with_size(char ***l, size_t *n, char *value) { int r; - r = strv_push(l, value); + r = strv_push_with_size(l, n, value); if (r < 0) free(value); @@ -529,7 +535,7 @@ int strv_prepend(char ***l, const char *value) { return strv_consume_prepend(l, v); } -int strv_extend(char ***l, const char *value) { +int strv_extend_with_size(char ***l, size_t *n, const char *value) { char *v; if (!value) @@ -539,7 +545,7 @@ int strv_extend(char ***l, const char *value) { if (!v) return -ENOMEM; - return strv_consume(l, v); + return strv_consume_with_size(l, n, v); } int strv_extend_front(char ***l, const char *value) { diff --git a/src/libnm-systemd-shared/src/basic/strv.h b/src/libnm-systemd-shared/src/basic/strv.h index 2a858326c6..072739df35 100644 --- a/src/libnm-systemd-shared/src/basic/strv.h +++ b/src/libnm-systemd-shared/src/basic/strv.h @@ -35,18 +35,36 @@ size_t strv_length(char * const *l) _pure_; int strv_extend_strv(char ***a, char * const *b, bool filter_duplicates); int strv_extend_strv_concat(char ***a, char * const *b, const char *suffix); int strv_prepend(char ***l, const char *value); -int strv_extend(char ***l, const char *value); + +/* _with_size() are lower-level functions where the size can be provided externally, + * which allows us to skip iterating over the strv to find the end, which saves + * a bit of time and reduces the complexity of appending from O(n²) to O(n). */ + +int strv_extend_with_size(char ***l, size_t *n, const char *value); +static inline int strv_extend(char ***l, const char *value) { + return strv_extend_with_size(l, NULL, value); +} + int strv_extendf(char ***l, const char *format, ...) _printf_(2,0); int strv_extend_front(char ***l, const char *value); -int strv_push(char ***l, char *value); + +int strv_push_with_size(char ***l, size_t *n, char *value); +static inline int strv_push(char ***l, char *value) { + return strv_push_with_size(l, NULL, value); +} int strv_push_pair(char ***l, char *a, char *b); + int strv_insert(char ***l, size_t position, char *value); static inline int strv_push_prepend(char ***l, char *value) { return strv_insert(l, 0, value); } -int strv_consume(char ***l, char *value); +int strv_consume_with_size(char ***l, size_t *n, char *value); +static inline int strv_consume(char ***l, char *value) { + return strv_consume_with_size(l, NULL, value); +} + int strv_consume_pair(char ***l, char *a, char *b); int strv_consume_prepend(char ***l, char *value); @@ -77,7 +95,7 @@ int strv_split_full(char ***t, const char *s, const char *separators, ExtractFla static inline char** strv_split(const char *s, const char *separators) { char **ret; - if (strv_split_full(&ret, s, separators, 0) < 0) + if (strv_split_full(&ret, s, separators, EXTRACT_RETAIN_ESCAPE) < 0) return NULL; return ret; @@ -101,7 +119,7 @@ static inline char** strv_split_newlines(const char *s) { * string in the vector is an empty string. */ int strv_split_colon_pairs(char ***t, const char *s); -char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separtor); +char* strv_join_full(char * const *l, const char *separator, const char *prefix, bool escape_separator); static inline char *strv_join(char * const *l, const char *separator) { return strv_join_full(l, separator, NULL, false); } @@ -122,12 +140,6 @@ static inline int strv_from_nulstr(char ***a, const char *nulstr) { bool strv_overlap(char * const *a, char * const *b) _pure_; -#define _STRV_FOREACH(s, l, i) \ - for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++) - -#define STRV_FOREACH(s, l) \ - _STRV_FOREACH(s, l, UNIQ_T(i, UNIQ)) - #define _STRV_FOREACH_BACKWARDS(s, l, h, i) \ for (typeof(*(l)) *s, *h = (l), *i = ({ \ size_t _len = strv_length(h); \ diff --git a/src/libnm-systemd-shared/src/basic/time-util.c b/src/libnm-systemd-shared/src/basic/time-util.c index ad4a189ff7..abbc4ad5cd 100644 --- a/src/libnm-systemd-shared/src/basic/time-util.c +++ b/src/libnm-systemd-shared/src/basic/time-util.c @@ -29,10 +29,10 @@ static clockid_t map_clock_id(clockid_t c) { - /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, clock_gettime() will - * fail for them. Since they are essentially the same as their non-ALARM pendants (their only difference is - * when timers are set on them), let's just map them accordingly. This way, we can get the correct time even on - * those archs. */ + /* Some more exotic archs (s390, ppc, …) lack the "ALARM" flavour of the clocks. Thus, + * clock_gettime() will fail for them. Since they are essentially the same as their non-ALARM + * pendants (their only difference is when timers are set on them), let's just map them + * accordingly. This way, we can get the correct time even on those archs. */ switch (c) { @@ -295,8 +295,8 @@ char *format_timestamp_style( usec_t t, TimestampStyle style) { - /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that our - * generated timestamps may be parsed with parse_timestamp(), and always read the same. */ + /* The weekdays in non-localized (English) form. We use this instead of the localized form, so that + * our generated timestamps may be parsed with parse_timestamp(), and always read the same. */ static const char * const weekdays[] = { [0] = "Sun", [1] = "Mon", @@ -383,8 +383,8 @@ char *format_timestamp_style( /* Append the timezone */ n = strlen(buf); if (utc) { - /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() normally uses the - * obsolete "GMT" instead. */ + /* If this is UTC then let's explicitly use the "UTC" string here, because gmtime_r() + * normally uses the obsolete "GMT" instead. */ if (n + 5 > l) return NULL; /* "UTC" doesn't fit. */ @@ -399,12 +399,14 @@ char *format_timestamp_style( /* The full time zone does not fit in. Yuck. */ if (n + 1 + _POSIX_TZNAME_MAX + 1 > l) - return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that case, complain that it doesn't fit */ + return NULL; /* Not even enough space for the POSIX minimum (of 6)? In that + * case, complain that it doesn't fit. */ - /* So the time zone doesn't fit in fully, but the caller passed enough space for the POSIX - * minimum time zone length. In this case suppress the timezone entirely, in order not to dump - * an overly long, hard to read string on the user. This should be safe, because the user will - * assume the local timezone anyway if none is shown. And so does parse_timestamp(). */ + /* So the time zone doesn't fit in fully, but the caller passed enough space for the + * POSIX minimum time zone length. In this case suppress the timezone entirely, in + * order not to dump an overly long, hard to read string on the user. This should be + * safe, because the user will assume the local timezone anyway if none is shown. And + * so does parse_timestamp(). */ } else { buf[n++] = ' '; strcpy(buf + n, tm.tm_zone); @@ -700,10 +702,11 @@ static int parse_timestamp_impl(const char *t, usec_t *usec, bool with_tz) { tzset(); - /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note that we only - * support the local timezones here, nothing else. Not because we wouldn't want to, but simply because - * there are no nice APIs available to cover this. By accepting the local time zone strings, we make - * sure that all timestamps written by format_timestamp() can be parsed correctly, even though we don't + /* See if the timestamp is suffixed by either the DST or non-DST local timezone. Note + * that we only support the local timezones here, nothing else. Not because we + * wouldn't want to, but simply because there are no nice APIs available to cover + * this. By accepting the local time zone strings, we make sure that all timestamps + * written by format_timestamp() can be parsed correctly, even though we don't * support arbitrary timezone specifications. */ for (j = 0; j <= 1; j++) { @@ -1408,9 +1411,8 @@ int verify_timezone(const char *name, int log_level) { return -EINVAL; for (p = name; *p; p++) { - if (!(*p >= '0' && *p <= '9') && - !(*p >= 'a' && *p <= 'z') && - !(*p >= 'A' && *p <= 'Z') && + if (!ascii_isdigit(*p) && + !ascii_isalpha(*p) && !IN_SET(*p, '-', '_', '+', '/')) return -EINVAL; diff --git a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h index 1c198f6ad9..3c38afcab8 100644 --- a/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/macro-fundamental.h @@ -2,36 +2,50 @@ #pragma once #ifndef SD_BOOT -#include +# include #endif #include -#include "types-fundamental.h" +#include +#include +#include #define _align_(x) __attribute__((__aligned__(x))) -#define _const_ __attribute__((__const__)) -#define _pure_ __attribute__((__pure__)) -#define _section_(x) __attribute__((__section__(x))) -#define _packed_ __attribute__((__packed__)) -#define _retain_ __attribute__((__retain__)) -#define _used_ __attribute__((__used__)) -#define _unused_ __attribute__((__unused__)) +#define _alignas_(x) __attribute__((__aligned__(__alignof__(x)))) +#define _alignptr_ __attribute__((__aligned__(sizeof(void *)))) #define _cleanup_(x) __attribute__((__cleanup__(x))) +#define _const_ __attribute__((__const__)) +#define _deprecated_ __attribute__((__deprecated__)) +#define _destructor_ __attribute__((__destructor__)) +#define _hidden_ __attribute__((__visibility__("hidden"))) #define _likely_(x) (__builtin_expect(!!(x), 1)) -#define _unlikely_(x) (__builtin_expect(!!(x), 0)) -#if __GNUC__ >= 7 -#define _fallthrough_ __attribute__((__fallthrough__)) -#else -#define _fallthrough_ -#endif -/* Define C11 noreturn without and even on older gcc - * compiler versions */ -#ifndef _noreturn_ -#if __STDC_VERSION__ >= 201112L +#define _malloc_ __attribute__((__malloc__)) #define _noreturn_ _Noreturn +#define _packed_ __attribute__((__packed__)) +#define _printf_(a, b) __attribute__((__format__(printf, a, b))) +#define _public_ __attribute__((__visibility__("default"))) +#define _pure_ __attribute__((__pure__)) +#define _retain_ __attribute__((__retain__)) +#define _returns_nonnull_ __attribute__((__returns_nonnull__)) +#define _section_(x) __attribute__((__section__(x))) +#define _sentinel_ __attribute__((__sentinel__)) +#define _unlikely_(x) (__builtin_expect(!!(x), 0)) +#define _unused_ __attribute__((__unused__)) +#define _used_ __attribute__((__used__)) +#define _warn_unused_result_ __attribute__((__warn_unused_result__)) +#define _weak_ __attribute__((__weak__)) +#define _weakref_(x) __attribute__((__weakref__(#x))) + +#ifdef __clang__ +# define _alloc_(...) #else -#define _noreturn_ __attribute__((__noreturn__)) +# define _alloc_(...) __attribute__((__alloc_size__(__VA_ARGS__))) #endif + +#if __GNUC__ >= 7 || __clang__ +# define _fallthrough_ __attribute__((__fallthrough__)) +#else +# define _fallthrough_ #endif #define XSTRINGIFY(x) #x @@ -53,7 +67,7 @@ #define CONCATENATE(x, y) XCONCATENATE(x, y) #ifdef SD_BOOT - void efi_assert(const char *expr, const char *file, unsigned line, const char *function) _noreturn_; + _noreturn_ void efi_assert(const char *expr, const char *file, unsigned line, const char *function); #ifdef NDEBUG #define assert(expr) @@ -62,10 +76,8 @@ #define assert(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); }) #define assert_not_reached() efi_assert("Code should not be reached", __FILE__, __LINE__, __PRETTY_FUNCTION__) #endif + #define static_assert _Static_assert #define assert_se(expr) ({ _likely_(expr) ? VOID_0 : efi_assert(#expr, __FILE__, __LINE__, __PRETTY_FUNCTION__); }) - - #define memcpy(a, b, c) CopyMem((a), (b), (c)) - #define free(a) FreePool(a) #endif /* This passes the argument through after (if asserts are enabled) checking that it is not null. */ @@ -83,15 +95,8 @@ _expr_; \ }) -#if defined(static_assert) -#define assert_cc(expr) \ - static_assert(expr, #expr) -#else -#define assert_cc(expr) \ - struct CONCATENATE(_assert_struct_, __COUNTER__) { \ - char x[(expr) ? 0 : -1]; \ - } -#endif +#define assert_cc(expr) static_assert(expr, #expr) + #define UNIQ_T(x, uniq) CONCATENATE(__unique_prefix_, CONCATENATE(x, uniq)) #define UNIQ __COUNTER__ @@ -101,10 +106,10 @@ * on this macro will run concurrently to all other code conditionalized * the same way, there's no ordering or completion enforced. */ #define ONCE __ONCE(UNIQ_T(_once_, UNIQ)) -#define __ONCE(o) \ - ({ \ - static sd_bool (o) = sd_false; \ - __sync_bool_compare_and_swap(&(o), sd_false, sd_true); \ +#define __ONCE(o) \ + ({ \ + static bool (o) = false; \ + __sync_bool_compare_and_swap(&(o), false, true); \ }) #undef MAX @@ -254,7 +259,7 @@ #define IN_SET(x, ...) \ ({ \ - sd_bool _found = sd_false; \ + bool _found = false; \ /* If the build breaks in the line below, you need to extend the case macros. (We use "long double" as \ * type for the array, in the hope that checkers such as ubsan don't complain that the initializers for \ * the array are not representable by the base type. Ideally we'd use typeof(x) as base type, but that \ @@ -263,7 +268,7 @@ assert_cc(ELEMENTSOF(__assert_in_set) <= 20); \ switch (x) { \ FOR_EACH_MAKE_CASE(__VA_ARGS__) \ - _found = sd_true; \ + _found = true; \ break; \ default: \ break; \ @@ -295,9 +300,6 @@ }) static inline size_t ALIGN_TO(size_t l, size_t ali) { - /* sd-boot uses UINTN for size_t, let's make sure SIZE_MAX is correct. */ - assert_cc(SIZE_MAX == ~(size_t)0); - /* Check that alignment is exponent of 2 */ #if SIZE_MAX == UINT_MAX assert(__builtin_popcount(ali) == 1); @@ -315,6 +317,14 @@ static inline size_t ALIGN_TO(size_t l, size_t ali) { return ((l + ali - 1) & ~(ali - 1)); } +#define ALIGN4(l) ALIGN_TO(l, 4) +#define ALIGN8(l) ALIGN_TO(l, 8) +#ifndef SD_BOOT +/* libefi also provides ALIGN, and we do not use them in sd-boot explicitly. */ +#define ALIGN(l) ALIGN_TO(l, sizeof(void*)) +#define ALIGN_PTR(p) ((void*) ALIGN((uintptr_t) (p))) +#endif + /* Same as ALIGN_TO but callable in constant contexts. */ #define CONST_ALIGN_TO(l, ali) \ __builtin_choose_expr( \ diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.c b/src/libnm-systemd-shared/src/fundamental/sha256.c new file mode 100644 index 0000000000..31d9674d09 --- /dev/null +++ b/src/libnm-systemd-shared/src/fundamental/sha256.c @@ -0,0 +1,291 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +/* Stolen from glibc and converted to our style. In glibc it comes with the following copyright blurb: */ + +/* Functions to compute SHA256 message digest of files or memory blocks. + according to the definition of SHA256 in FIPS 180-2. + Copyright (C) 2007-2022 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library 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. + + The GNU C Library 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 the GNU C Library; if not, see + . */ + +#include +#ifdef SD_BOOT +# include "efi-string.h" +#else +# include +#endif + +#include "macro-fundamental.h" +#include "sha256.h" + +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +# define SWAP(n) \ + (((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24)) +# define SWAP64(n) \ + (((n) << 56) \ + | (((n) & 0xff00) << 40) \ + | (((n) & 0xff0000) << 24) \ + | (((n) & 0xff000000) << 8) \ + | (((n) >> 8) & 0xff000000) \ + | (((n) >> 24) & 0xff0000) \ + | (((n) >> 40) & 0xff00) \ + | ((n) >> 56)) +#else +# define SWAP(n) (n) +# define SWAP64(n) (n) +#endif + +/* The condition below is from glibc's string/string-inline.c. + * See definition of _STRING_INLINE_unaligned. */ +#if !defined(__mc68020__) && !defined(__s390__) && !defined(__i386__) +# define UNALIGNED_P(p) (((uintptr_t) p) % __alignof__(uint32_t) != 0) +#else +# define UNALIGNED_P(p) false +#endif + +/* This array contains the bytes used to pad the buffer to the next + 64-byte boundary. (FIPS 180-2:5.1.1) */ +static const uint8_t fillbuf[64] = { + 0x80, 0 /* , 0, 0, ... */ +}; + +/* Constants for SHA256 from FIPS 180-2:4.2.2. */ +static const uint32_t K[64] = { + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, + 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, + 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, + 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, + 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, + 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, + 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, + 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, + 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2 +}; + +static void sha256_process_block(const void *, size_t, struct sha256_ctx *); + +/* Initialize structure containing state of computation. + (FIPS 180-2:5.3.2) */ +void sha256_init_ctx(struct sha256_ctx *ctx) { + assert(ctx); + + ctx->H[0] = 0x6a09e667; + ctx->H[1] = 0xbb67ae85; + ctx->H[2] = 0x3c6ef372; + ctx->H[3] = 0xa54ff53a; + ctx->H[4] = 0x510e527f; + ctx->H[5] = 0x9b05688c; + ctx->H[6] = 0x1f83d9ab; + ctx->H[7] = 0x5be0cd19; + + ctx->total64 = 0; + ctx->buflen = 0; +} + +/* Process the remaining bytes in the internal buffer and the usual + prolog according to the standard and write the result to RESBUF. */ +void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf) { + /* Take yet unprocessed bytes into account. */ + uint32_t bytes = ctx->buflen; + size_t pad; + + assert(ctx); + assert(resbuf); + + /* Now count remaining bytes. */ + ctx->total64 += bytes; + + pad = bytes >= 56 ? 64 + 56 - bytes : 56 - bytes; + memcpy(&ctx->buffer[bytes], fillbuf, pad); + + /* Put the 64-bit file length in *bits* at the end of the buffer. */ + ctx->buffer32[(bytes + pad + 4) / 4] = SWAP(ctx->total[TOTAL64_low] << 3); + ctx->buffer32[(bytes + pad) / 4] = SWAP((ctx->total[TOTAL64_high] << 3) + | (ctx->total[TOTAL64_low] >> 29)); + + /* Process last bytes. */ + sha256_process_block(ctx->buffer, bytes + pad + 8, ctx); + + /* Put result from CTX in first 32 bytes following RESBUF. */ + for (size_t i = 0; i < 8; ++i) + if (UNALIGNED_P(resbuf)) + memcpy((uint8_t*) resbuf + i * sizeof(uint32_t), (uint32_t[]) { SWAP(ctx->H[i]) }, sizeof(uint32_t)); + else + ((uint32_t *) resbuf)[i] = SWAP(ctx->H[i]); + + return resbuf; +} + +void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx) { + assert(buffer); + assert(ctx); + + /* When we already have some bits in our internal buffer concatenate + both inputs first. */ + + if (ctx->buflen != 0) { + size_t left_over = ctx->buflen; + size_t add = 128 - left_over > len ? len : 128 - left_over; + + memcpy(&ctx->buffer[left_over], buffer, add); + ctx->buflen += add; + + if (ctx->buflen > 64) { + sha256_process_block(ctx->buffer, ctx->buflen & ~63, ctx); + + ctx->buflen &= 63; + /* The regions in the following copy operation cannot overlap. */ + memcpy(ctx->buffer, &ctx->buffer[(left_over + add) & ~63], + ctx->buflen); + } + + buffer = (const char *) buffer + add; + len -= add; + } + + /* Process available complete blocks. */ + if (len >= 64) { + if (UNALIGNED_P(buffer)) + while (len > 64) { + memcpy(ctx->buffer, buffer, 64); + sha256_process_block(ctx->buffer, 64, ctx); + buffer = (const char *) buffer + 64; + len -= 64; + } + else { + sha256_process_block(buffer, len & ~63, ctx); + buffer = (const char *) buffer + (len & ~63); + len &= 63; + } + } + + /* Move remaining bytes into internal buffer. */ + if (len > 0) { + size_t left_over = ctx->buflen; + + memcpy(&ctx->buffer[left_over], buffer, len); + left_over += len; + if (left_over >= 64) { + sha256_process_block(ctx->buffer, 64, ctx); + left_over -= 64; + memcpy(ctx->buffer, &ctx->buffer[64], left_over); + } + ctx->buflen = left_over; + } +} + +/* Process LEN bytes of BUFFER, accumulating context into CTX. + It is assumed that LEN % 64 == 0. */ +static void sha256_process_block(const void *buffer, size_t len, struct sha256_ctx *ctx) { + const uint32_t *words = buffer; + size_t nwords = len / sizeof(uint32_t); + + assert(buffer); + assert(ctx); + + uint32_t a = ctx->H[0]; + uint32_t b = ctx->H[1]; + uint32_t c = ctx->H[2]; + uint32_t d = ctx->H[3]; + uint32_t e = ctx->H[4]; + uint32_t f = ctx->H[5]; + uint32_t g = ctx->H[6]; + uint32_t h = ctx->H[7]; + + /* First increment the byte count. FIPS 180-2 specifies the possible + length of the file up to 2^64 bits. Here we only compute the + number of bytes. */ + ctx->total64 += len; + + /* Process all bytes in the buffer with 64 bytes in each round of + the loop. */ + while (nwords > 0) { + uint32_t W[64]; + uint32_t a_save = a; + uint32_t b_save = b; + uint32_t c_save = c; + uint32_t d_save = d; + uint32_t e_save = e; + uint32_t f_save = f; + uint32_t g_save = g; + uint32_t h_save = h; + + /* Operators defined in FIPS 180-2:4.1.2. */ +#define Ch(x, y, z) ((x & y) ^ (~x & z)) +#define Maj(x, y, z) ((x & y) ^ (x & z) ^ (y & z)) +#define S0(x) (CYCLIC (x, 2) ^ CYCLIC (x, 13) ^ CYCLIC (x, 22)) +#define S1(x) (CYCLIC (x, 6) ^ CYCLIC (x, 11) ^ CYCLIC (x, 25)) +#define R0(x) (CYCLIC (x, 7) ^ CYCLIC (x, 18) ^ (x >> 3)) +#define R1(x) (CYCLIC (x, 17) ^ CYCLIC (x, 19) ^ (x >> 10)) + + /* It is unfortunate that C does not provide an operator for + cyclic rotation. Hope the C compiler is smart enough. */ +#define CYCLIC(w, s) ((w >> s) | (w << (32 - s))) + + /* Compute the message schedule according to FIPS 180-2:6.2.2 step 2. */ + for (size_t t = 0; t < 16; ++t) { + W[t] = SWAP (*words); + ++words; + } + for (size_t t = 16; t < 64; ++t) + W[t] = R1 (W[t - 2]) + W[t - 7] + R0 (W[t - 15]) + W[t - 16]; + + /* The actual computation according to FIPS 180-2:6.2.2 step 3. */ + for (size_t t = 0; t < 64; ++t) { + uint32_t T1 = h + S1 (e) + Ch (e, f, g) + K[t] + W[t]; + uint32_t T2 = S0 (a) + Maj (a, b, c); + h = g; + g = f; + f = e; + e = d + T1; + d = c; + c = b; + b = a; + a = T1 + T2; + } + + /* Add the starting values of the context according to FIPS 180-2:6.2.2 + step 4. */ + a += a_save; + b += b_save; + c += c_save; + d += d_save; + e += e_save; + f += f_save; + g += g_save; + h += h_save; + + /* Prepare for the next round. */ + nwords -= 16; + } + + /* Put checksum in context given as argument. */ + ctx->H[0] = a; + ctx->H[1] = b; + ctx->H[2] = c; + ctx->H[3] = d; + ctx->H[4] = e; + ctx->H[5] = f; + ctx->H[6] = g; + ctx->H[7] = h; +} diff --git a/src/libnm-systemd-shared/src/fundamental/sha256.h b/src/libnm-systemd-shared/src/fundamental/sha256.h new file mode 100644 index 0000000000..f296f76ae8 --- /dev/null +++ b/src/libnm-systemd-shared/src/fundamental/sha256.h @@ -0,0 +1,29 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +#pragma once + +#include "stdint.h" + +#define SHA256_DIGEST_SIZE 32 + +struct sha256_ctx { + uint32_t H[8]; + + union { + uint64_t total64; +#define TOTAL64_low (1 - (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) +#define TOTAL64_high (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) + uint32_t total[2]; + }; + + uint32_t buflen; + + union { + uint8_t buffer[128]; /* NB: always correctly aligned for UINT32. */ + uint32_t buffer32[32]; + uint64_t buffer64[16]; + }; +}; + +void sha256_init_ctx(struct sha256_ctx *ctx); +void *sha256_finish_ctx(struct sha256_ctx *ctx, void *resbuf); +void sha256_process_bytes(const void *buffer, size_t len, struct sha256_ctx *ctx); diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c index 101d3f7196..11701ebe52 100644 --- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c +++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.c @@ -1,10 +1,10 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef SD_BOOT -#include - -#include "macro.h" +# include #endif + +#include "macro-fundamental.h" #include "string-util-fundamental.h" sd_char *startswith(const sd_char *s, const sd_char *prefix) { @@ -77,36 +77,27 @@ sd_char* endswith_no_case(const sd_char *s, const sd_char *postfix) { return (sd_char*) s + sl - pl; } -#ifdef SD_BOOT -static sd_bool isdigit(sd_char a) { - return a >= '0' && a <= '9'; -} -#endif - -static sd_bool is_alpha(sd_char a) { - /* Locale independent version of isalpha(). */ - return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'); +static bool is_valid_version_char(sd_char a) { + return ascii_isdigit(a) || ascii_isalpha(a) || IN_SET(a, '~', '-', '^', '.'); } -static sd_bool is_valid_version_char(sd_char a) { - return isdigit(a) || is_alpha(a) || IN_SET(a, '~', '-', '^', '.'); -} - -sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { - - /* This is based on RPM's rpmvercmp(). But this explicitly handles '-' and '.', as we usually - * want to directly compare strings which contain both version and release; e.g. - * '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'. - * Unlike rpmvercmp(), this distiguishes e.g. 123a and 123.a, and 123a is newer. +int strverscmp_improved(const sd_char *a, const sd_char *b) { + /* This function is similar to strverscmp(3), but it treats '-' and '.' as separators. * - * This splits the input strings into segments. Each segment is numeric or alpha, and may be + * The logic is based on rpm's rpmvercmp(), but unlike rpmvercmp(), it distiguishes e.g. + * '123a' and '123.a', with '123a' being newer. + * + * It allows direct comparison of strings which contain both a version and a release; e.g. + * '247.2-3.1.fc33.x86_64' or '5.11.0-0.rc5.20210128git76c057c84d28.137.fc34'. + * + * The input string is split into segments. Each segment is numeric or alphabetic, and may be * prefixed with the following: * '~' : used for pre-releases, a segment prefixed with this is the oldest, * '-' : used for the separator between version and release, * '^' : used for patched releases, a segment with this is newer than one with '-'. * '.' : used for point releases. - * Note, no prefix segment is the newest. All non-supported characters are dropped, and - * handled as a separator of segments, e.g., 123_a is equivalent to 123a. + * Note that no prefix segment is the newest. All non-supported characters are dropped, and + * handled as a separator of segments, e.g., '123_a' is equivalent to '123a'. * * By using this, version strings can be sorted like following: * (older) 122.1 @@ -123,12 +114,12 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { * (newer) 124-1 */ - if (isempty(a) || isempty(b)) - return strcmp_ptr(a, b); + a = strempty(a); + b = strempty(b); for (;;) { const sd_char *aa, *bb; - sd_int r; + int r; /* Drop leading invalid characters. */ while (*a != '\0' && !is_valid_version_char(*a)) @@ -149,7 +140,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { } /* If at least one string reaches the end, then longer is newer. - * Note that except for '~' prefixed segments, a string has more segments is newer. + * Note that except for '~' prefixed segments, a string which has more segments is newer. * So, this check must be after the '~' check. */ if (*a == '\0' || *b == '\0') return CMP(*a, *b); @@ -185,20 +176,25 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { b++; } - if (isdigit(*a) || isdigit(*b)) { + if (ascii_isdigit(*a) || ascii_isdigit(*b)) { + /* Find the leading numeric segments. One may be an empty string. So, + * numeric segments are always newer than alpha segments. */ + for (aa = a; ascii_isdigit(*aa); aa++) + ; + for (bb = b; ascii_isdigit(*bb); bb++) + ; + + /* Check if one of the strings was empty, but the other not. */ + r = CMP(a != aa, b != bb); + if (r != 0) + return r; + /* Skip leading '0', to make 00123 equivalent to 123. */ while (*a == '0') a++; while (*b == '0') b++; - /* Find the leading numeric segments. One may be an empty string. So, - * numeric segments are always newer than alpha segments. */ - for (aa = a; isdigit(*aa); aa++) - ; - for (bb = b; isdigit(*bb); bb++) - ; - /* To compare numeric segments without parsing their values, first compare the * lengths of the segments. Eg. 12345 vs 123, longer is newer. */ r = CMP(aa - a, bb - b); @@ -206,18 +202,18 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { return r; /* Then, compare them as strings. */ - r = strncmp(a, b, aa - a); + r = CMP(strncmp(a, b, aa - a), 0); if (r != 0) return r; } else { /* Find the leading non-numeric segments. */ - for (aa = a; is_alpha(*aa); aa++) + for (aa = a; ascii_isalpha(*aa); aa++) ; - for (bb = b; is_alpha(*bb); bb++) + for (bb = b; ascii_isalpha(*bb); bb++) ; /* Note that the segments are usually not NUL-terminated. */ - r = strncmp(a, b, MIN(aa - a, bb - b)); + r = CMP(strncmp(a, b, MIN(aa - a, bb - b)), 0); if (r != 0) return r; @@ -227,7 +223,7 @@ sd_int strverscmp_improved(const sd_char *a, const sd_char *b) { return r; } - /* The current segments are equivalent. Let's compare the next one. */ + /* The current segments are equivalent. Let's move to the next one. */ a = aa; b = bb; } diff --git a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h index dc0c1202be..ecf32e519f 100644 --- a/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h +++ b/src/libnm-systemd-shared/src/fundamental/string-util-fundamental.h @@ -2,54 +2,62 @@ #pragma once #ifdef SD_BOOT -#include -#include +# include +# include +# include "efi-string.h" #else -#include +# include #endif #include "macro-fundamental.h" #ifdef SD_BOOT -#define strlen(a) StrLen((a)) -#define strcmp(a, b) StrCmp((a), (b)) -#define strncmp(a, b, n) StrnCmp((a), (b), (n)) -#define strcasecmp(a, b) StriCmp((a), (b)) -#define STR_C(str) (L ## str) -#define memcmp(a, b, n) CompareMem(a, b, n) +# define strlen strlen16 +# define strcmp strcmp16 +# define strncmp strncmp16 +# define strcasecmp strcasecmp16 +# define strncasecmp strncasecmp16 +# define STR_C(str) (L ## str) +typedef char16_t sd_char; #else -#define STR_C(str) (str) +# define STR_C(str) (str) +typedef char sd_char; #endif #define streq(a,b) (strcmp((a),(b)) == 0) #define strneq(a, b, n) (strncmp((a), (b), (n)) == 0) #define strcaseeq(a,b) (strcasecmp((a),(b)) == 0) -#ifndef SD_BOOT #define strncaseeq(a, b, n) (strncasecmp((a), (b), (n)) == 0) -#endif -static inline sd_int strcmp_ptr(const sd_char *a, const sd_char *b) { +static inline int strcmp_ptr(const sd_char *a, const sd_char *b) { if (a && b) return strcmp(a, b); return CMP(a, b); } -static inline sd_int strcasecmp_ptr(const sd_char *a, const sd_char *b) { +static inline int strcasecmp_ptr(const sd_char *a, const sd_char *b) { if (a && b) return strcasecmp(a, b); return CMP(a, b); } -static inline sd_bool streq_ptr(const sd_char *a, const sd_char *b) { +static inline bool streq_ptr(const sd_char *a, const sd_char *b) { return strcmp_ptr(a, b) == 0; } -static inline sd_bool strcaseeq_ptr(const sd_char *a, const sd_char *b) { +static inline bool strcaseeq_ptr(const sd_char *a, const sd_char *b) { return strcasecmp_ptr(a, b) == 0; } +static inline size_t strlen_ptr(const sd_char *s) { + if (!s) + return 0; + + return strlen(s); +} + sd_char *startswith(const sd_char *s, const sd_char *prefix) _pure_; #ifndef SD_BOOT sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_; @@ -57,15 +65,23 @@ sd_char *startswith_no_case(const sd_char *s, const sd_char *prefix) _pure_; sd_char *endswith(const sd_char *s, const sd_char *postfix) _pure_; sd_char *endswith_no_case(const sd_char *s, const sd_char *postfix) _pure_; -static inline sd_bool isempty(const sd_char *a) { +static inline bool isempty(const sd_char *a) { return !a || a[0] == '\0'; } -static inline const sd_char *yes_no(sd_bool b) { +static inline const sd_char *strempty(const sd_char *s) { + return s ?: STR_C(""); +} + +static inline const sd_char *yes_no(bool b) { return b ? STR_C("yes") : STR_C("no"); } -sd_int strverscmp_improved(const sd_char *a, const sd_char *b); +static inline const sd_char* comparison_operator(int result) { + return result < 0 ? STR_C("<") : result > 0 ? STR_C(">") : STR_C("=="); +} + +int strverscmp_improved(const sd_char *a, const sd_char *b); /* Like startswith(), but operates on arbitrary memory blocks */ static inline void *memory_startswith(const void *p, size_t sz, const sd_char *token) { @@ -82,3 +98,19 @@ static inline void *memory_startswith(const void *p, size_t sz, const sd_char *t return (uint8_t*) p + n; } + +#define _STRV_FOREACH(s, l, i) \ + for (typeof(*(l)) *s, *i = (l); (s = i) && *i; i++) + +#define STRV_FOREACH(s, l) \ + _STRV_FOREACH(s, l, UNIQ_T(i, UNIQ)) + +static inline bool ascii_isdigit(sd_char a) { + /* A pure ASCII, locale independent version of isdigit() */ + return a >= '0' && a <= '9'; +} + +static inline bool ascii_isalpha(sd_char a) { + /* A pure ASCII, locale independent version of isalpha() */ + return (a >= 'a' && a <= 'z') || (a >= 'A' && a <= 'Z'); +} diff --git a/src/libnm-systemd-shared/src/fundamental/types-fundamental.h b/src/libnm-systemd-shared/src/fundamental/types-fundamental.h deleted file mode 100644 index 5977e40c6c..0000000000 --- a/src/libnm-systemd-shared/src/fundamental/types-fundamental.h +++ /dev/null @@ -1,39 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#pragma once - -/* This defines a number of basic types that are one thing in userspace and another in the UEFI environment, - * but mostly the same in concept and behaviour. - * - * Note: if the definition of these types/values has slightly different semantics in userspace and in the - * UEFI environment then please prefix its name with "sd_" to make clear these types have special semantics, - * and *we* defined them. Otherwise, if the types are effectively 100% identical in behaviour in userspace - * and UEFI environment you can omit the prefix. (Examples: sd_char is 8 bit in userspace and 16 bit in UEFI - * space hence it should have the sd_ prefix; but size_t in userspace and UINTN in UEFI environment are 100% - * defined the same way ultimately, hence it's OK to just define size_t as alias to UINTN in UEFI - * environment, so that size_t can be used everywhere, without any "sd_" prefix.) - * - * Note: we generally prefer the userspace names of types and concepts. i.e. if in doubt please name types - * after the userspace vocabulary, and let's keep UEFI vocabulary specific to the UEFI build environment. */ - -#ifdef SD_BOOT -#include - -typedef BOOLEAN sd_bool; -typedef CHAR16 sd_char; -typedef INTN sd_int; -typedef UINTN size_t; - -#define sd_true TRUE -#define sd_false FALSE -#else -#include -#include - -typedef bool sd_bool; -typedef char sd_char; -typedef int sd_int; - -#define sd_true true -#define sd_false false - -#endif diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.c b/src/libnm-systemd-shared/src/shared/dns-domain.c index 0ae1de1c5b..ebf86d2405 100644 --- a/src/libnm-systemd-shared/src/shared/dns-domain.c +++ b/src/libnm-systemd-shared/src/shared/dns-domain.c @@ -7,6 +7,7 @@ #include "alloc-util.h" #include "dns-domain.h" +#include "glyph-util.h" #include "hashmap.h" #include "hexdecoct.h" #include "hostname-util.h" @@ -235,9 +236,8 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) { sz -= 2; } else if (IN_SET(*p, '_', '-') || - (*p >= '0' && *p <= '9') || - (*p >= 'a' && *p <= 'z') || - (*p >= 'A' && *p <= 'Z')) { + ascii_isdigit(*p) || + ascii_isalpha(*p)) { /* Proper character */ @@ -450,12 +450,8 @@ int dns_name_concat(const char *a, const char *b, DNSLabelFlags flags, char **_r return r; } - if (!first) - n++; - else - first = false; - - n += r; + n += r + !first; + first = false; } finish: @@ -910,15 +906,13 @@ static bool srv_type_label_is_valid(const char *label, size_t n) { return false; /* Second char must be a letter */ - if (!(label[1] >= 'A' && label[1] <= 'Z') && - !(label[1] >= 'a' && label[1] <= 'z')) + if (!ascii_isalpha(label[1])) return false; /* Third and further chars must be alphanumeric or a hyphen */ for (k = 2; k < n; k++) { - if (!(label[k] >= 'A' && label[k] <= 'Z') && - !(label[k] >= 'a' && label[k] <= 'z') && - !(label[k] >= '0' && label[k] <= '9') && + if (!ascii_isalpha(label[k]) && + !ascii_isdigit(label[k]) && label[k] != '-') return false; } @@ -1026,10 +1020,10 @@ static bool dns_service_name_label_is_valid(const char *label, size_t n) { return dns_service_name_is_valid(s); } -int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) { +int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain) { _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL; - const char *p = joined, *q = NULL, *d = NULL; - char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX]; + const char *p = joined, *q = NULL, *d = joined; + char a[DNS_LABEL_MAX+1], b[DNS_LABEL_MAX+1], c[DNS_LABEL_MAX+1]; int an, bn, cn, r; unsigned x = 0; @@ -1049,6 +1043,9 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do return bn; if (bn > 0) { + if (!srv_type_label_is_valid(b, bn)) + goto finish; + x++; /* If there was a second label, try to get the third one */ @@ -1057,64 +1054,58 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do if (cn < 0) return cn; - if (cn > 0) + if (cn > 0 && srv_type_label_is_valid(c, cn)) x++; - } else - cn = 0; - } else - an = 0; - - if (x >= 2 && srv_type_label_is_valid(b, bn)) { - - if (x >= 3 && srv_type_label_is_valid(c, cn)) { - - if (dns_service_name_label_is_valid(a, an)) { - /* OK, got . . . */ - - name = strndup(a, an); - if (!name) - return -ENOMEM; - - type = strjoin(b, ".", c); - if (!type) - return -ENOMEM; - - d = p; - goto finish; - } - - } else if (srv_type_label_is_valid(a, an)) { - - /* OK, got . . */ - - name = NULL; - - type = strjoin(a, ".", b); - if (!type) - return -ENOMEM; - - d = q; - goto finish; } } - name = NULL; - type = NULL; - d = joined; + switch (x) { + case 2: + if (!srv_type_label_is_valid(a, an)) + break; + + /* OK, got . . */ + + name = NULL; + + type = strjoin(a, ".", b); + if (!type) + return -ENOMEM; + + d = q; + break; + + case 3: + if (!dns_service_name_label_is_valid(a, an)) + break; + + /* OK, got . . . */ + + name = strndup(a, an); + if (!name) + return -ENOMEM; + + type = strjoin(b, ".", c); + if (!type) + return -ENOMEM; + + d = p; + break; + } finish: r = dns_name_normalize(d, 0, &domain); if (r < 0) return r; - if (_domain) - *_domain = TAKE_PTR(domain); + if (ret_domain) + *ret_domain = TAKE_PTR(domain); - if (_type) - *_type = TAKE_PTR(type); + if (ret_type) + *ret_type = TAKE_PTR(type); - if (_name) - *_name = TAKE_PTR(name); + if (ret_name) + *ret_name = TAKE_PTR(name); return 0; } @@ -1294,7 +1285,7 @@ int dns_name_apply_idna(const char *name, char **ret) { r = sym_idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t, IDN2_NFC_INPUT | IDN2_TRANSITIONAL); - log_debug("idn2_lookup_u8: %s → %s", name, t); + log_debug("idn2_lookup_u8: %s %s %s", name, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), t); if (r == IDN2_OK) { if (!startswith(name, "xn--")) { _cleanup_free_ char *s = NULL; @@ -1308,8 +1299,9 @@ int dns_name_apply_idna(const char *name, char **ret) { } if (!streq_ptr(name, s)) { - log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.", - name, t, s); + log_debug("idn2 roundtrip failed: \"%s\" %s \"%s\" %s \"%s\", ignoring.", + name, special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), t, + special_glyph(SPECIAL_GLYPH_ARROW_RIGHT), s); *ret = NULL; return 0; } diff --git a/src/libnm-systemd-shared/src/shared/dns-domain.h b/src/libnm-systemd-shared/src/shared/dns-domain.h index e5f3d4d9e7..5421c60ee7 100644 --- a/src/libnm-systemd-shared/src/shared/dns-domain.h +++ b/src/libnm-systemd-shared/src/shared/dns-domain.h @@ -40,8 +40,8 @@ static inline int dns_name_normalize(const char *s, DNSLabelFlags flags, char ** static inline int dns_name_is_valid(const char *s) { int r; - /* dns_name_normalize() verifies as a side effect */ - r = dns_name_normalize(s, 0, NULL); + /* dns_name_concat() verifies as a side effect */ + r = dns_name_concat(s, NULL, 0, NULL); if (r == -EINVAL) return 0; if (r < 0) @@ -88,7 +88,7 @@ bool dnssd_srv_type_is_valid(const char *name); bool dns_service_name_is_valid(const char *name); int dns_service_join(const char *name, const char *type, const char *domain, char **ret); -int dns_service_split(const char *joined, char **name, char **type, char **domain); +int dns_service_split(const char *joined, char **ret_name, char **ret_type, char **ret_domain); int dns_name_suffix(const char *name, unsigned n_labels, const char **ret); int dns_name_count_labels(const char *name);