systemd: upgrade to 262-rc1
- sysvinit-path was removed - all carried patches are in the release Signed-off-by: Clayton Craft <craftyguy@postmarketos.org> Part-of: <https://gitlab.postmarketos.org/postmarketOS/pmaports/-/merge_requests/9472>
This commit is contained in:
@@ -2,10 +2,10 @@
|
||||
# Co-Maintainer: Oliver Smith <ollieparanoid@postmarketos.org>
|
||||
maintainer="Clayton Craft <craftyguy@postmarketos.org>"
|
||||
pkgname=systemd-stage0
|
||||
pkgver=261.2
|
||||
pkgver=262_rc1
|
||||
_pkgver="${pkgver/_/-}"
|
||||
# pkgrel must match systemd!
|
||||
pkgrel=1
|
||||
pkgrel=0
|
||||
pkgdesc="Minimal systemd bootstrap package"
|
||||
url="https://github.com/systemd/systemd"
|
||||
# armhf: pmb#2618
|
||||
@@ -101,7 +101,6 @@ build() {
|
||||
-Ddefault-locale=en_US.UTF-8 \
|
||||
\
|
||||
-Didn=false \
|
||||
-Dsysvinit-path="" \
|
||||
\
|
||||
-Dbacklight=false \
|
||||
-Dbinfmt=false \
|
||||
@@ -163,5 +162,5 @@ package() {
|
||||
}
|
||||
|
||||
sha512sums="
|
||||
876f043970cb65b39ae15fba39f23bf94c7c3d80569503d6e8ea2c8013c30ee40ce43cb55cbcb1cf14d5c3021aafc09c0f67473bbf742d8964bf9fa30693b971 systemd-261.2.tar.gz
|
||||
5bd4ed38246de1ea17b46fcc6f921f94a53047cec4dc53b005afd4ca75cd50d631b92c6662204871ad2c0808694244ec15d90732b1251d15bf5f9d74b6a2a7f0 systemd-262_rc1.tar.gz
|
||||
"
|
||||
|
||||
-249
@@ -1,249 +0,0 @@
|
||||
From c5f08a2e5cf1f246c908ddaaefbccdcfbdbaa754 Mon Sep 17 00:00:00 2001
|
||||
From: Nick Rosbrook <enr0n@ubuntu.com>
|
||||
Date: Fri, 19 Jun 2026 15:00:59 -0400
|
||||
Subject: [PATCH] json-util: generalize json_dispatch_address_family
|
||||
|
||||
There are several places where address family is dispatched from JSON,
|
||||
so take json_dispatch_address_family from networkd and put it in
|
||||
json-util.c.
|
||||
|
||||
Update the all instances in the tree to use this new function, adding
|
||||
SD_JSON_RELAX to the dispatch flags if AF_UNSPEC should be allowed
|
||||
in that case.
|
||||
---
|
||||
src/libsystemd/sd-json/json-util.c | 24 ++++++++++++++++++++++++
|
||||
src/libsystemd/sd-json/json-util.h | 1 +
|
||||
src/network/networkd-serialize.c | 22 ----------------------
|
||||
src/nss-resolve/nss-resolve.c | 23 +++--------------------
|
||||
src/resolve/resolvectl.c | 2 +-
|
||||
src/resolve/resolved-varlink.c | 15 +++------------
|
||||
src/shared/dns-configuration.c | 14 +++++++-------
|
||||
7 files changed, 39 insertions(+), 62 deletions(-)
|
||||
|
||||
diff --git a/src/libsystemd/sd-json/json-util.c b/src/libsystemd/sd-json/json-util.c
|
||||
index c6727ac760..485b4a03c8 100644
|
||||
--- a/src/libsystemd/sd-json/json-util.c
|
||||
+++ b/src/libsystemd/sd-json/json-util.c
|
||||
@@ -918,3 +918,27 @@ int json_variant_compare(sd_json_variant *a, sd_json_variant *b) {
|
||||
|
||||
return CMP(sd_json_variant_type(a), sd_json_variant_type(b));
|
||||
}
|
||||
+
|
||||
+int json_dispatch_address_family(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
+ int *family = ASSERT_PTR(userdata), r;
|
||||
+
|
||||
+ assert(variant);
|
||||
+
|
||||
+ if (sd_json_variant_is_negative(variant))
|
||||
+ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
|
||||
+ "JSON field '%s' for an address family cannot be negative.", strna(name));
|
||||
+
|
||||
+ int k = AF_UNSPEC;
|
||||
+ if (!sd_json_variant_is_null(variant)) {
|
||||
+ r = sd_json_dispatch_int(name, variant, flags, &k);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ }
|
||||
+
|
||||
+ if (!IN_SET(k, AF_INET, AF_INET6) && !(FLAGS_SET(flags, SD_JSON_RELAX) && k == AF_UNSPEC))
|
||||
+ return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE),
|
||||
+ "JSON field '%s' out of range for an address family.", strna(name));
|
||||
+
|
||||
+ *family = k;
|
||||
+ return 0;
|
||||
+}
|
||||
diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h
|
||||
index ecb4e2d633..de7790a6d3 100644
|
||||
--- a/src/libsystemd/sd-json/json-util.h
|
||||
+++ b/src/libsystemd/sd-json/json-util.h
|
||||
@@ -133,6 +133,7 @@ int json_dispatch_log_level(const char *name, sd_json_variant *variant, sd_json_
|
||||
int json_dispatch_strv_environment(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_access_mode(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_job_id(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
+int json_dispatch_address_family(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
|
||||
static inline int json_variant_unbase64_iovec(sd_json_variant *v, struct iovec *ret) {
|
||||
return sd_json_variant_unbase64(v, ret ? &ret->iov_base : NULL, ret ? &ret->iov_len : NULL);
|
||||
diff --git a/src/network/networkd-serialize.c b/src/network/networkd-serialize.c
|
||||
index 394f03ced6..224fcc93a0 100644
|
||||
--- a/src/network/networkd-serialize.c
|
||||
+++ b/src/network/networkd-serialize.c
|
||||
@@ -102,28 +102,6 @@ int manager_set_serialization_fd(Manager *manager, int fd, const char *name) {
|
||||
|
||||
static JSON_DISPATCH_ENUM_DEFINE(json_dispatch_network_config_source, NetworkConfigSource, network_config_source_from_string);
|
||||
|
||||
-static int json_dispatch_address_family(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
- int r, *i = ASSERT_PTR(userdata);
|
||||
- int64_t i64;
|
||||
-
|
||||
- assert_return(variant, -EINVAL);
|
||||
-
|
||||
- if (FLAGS_SET(flags, SD_JSON_RELAX) && sd_json_variant_is_null(variant)) {
|
||||
- *i = AF_UNSPEC;
|
||||
- return 0;
|
||||
- }
|
||||
-
|
||||
- r = sd_json_dispatch_int64(name, variant, flags, &i64);
|
||||
- if (r < 0)
|
||||
- return r;
|
||||
-
|
||||
- if (!IN_SET(i64, AF_INET, AF_INET6) && !(FLAGS_SET(flags, SD_JSON_RELAX) && i64 == AF_UNSPEC))
|
||||
- return json_log(variant, flags, SYNTHETIC_ERRNO(ERANGE), "JSON field '%s' out of bounds for an address family.", strna(name));
|
||||
-
|
||||
- *i = (int) i64;
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
typedef struct AddressParam {
|
||||
int family;
|
||||
struct iovec address;
|
||||
diff --git a/src/nss-resolve/nss-resolve.c b/src/nss-resolve/nss-resolve.c
|
||||
index 86eaf4e3b3..9f4225be3f 100644
|
||||
--- a/src/nss-resolve/nss-resolve.c
|
||||
+++ b/src/nss-resolve/nss-resolve.c
|
||||
@@ -78,23 +78,6 @@ static uint32_t ifindex_to_scopeid(int family, const void *a, int ifindex) {
|
||||
return in6_addr_is_link_local(&in6) ? ifindex : 0;
|
||||
}
|
||||
|
||||
-static int json_dispatch_family(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
- int *family = ASSERT_PTR(userdata);
|
||||
- int64_t t;
|
||||
-
|
||||
- assert(variant);
|
||||
-
|
||||
- if (!sd_json_variant_is_integer(variant))
|
||||
- return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an integer.", strna(name));
|
||||
-
|
||||
- t = sd_json_variant_integer(variant);
|
||||
- if (t < 0 || t > INT_MAX)
|
||||
- return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not a valid family.", strna(name));
|
||||
-
|
||||
- *family = (int) t;
|
||||
- return 0;
|
||||
-}
|
||||
-
|
||||
typedef struct ResolveHostnameReply {
|
||||
sd_json_variant *addresses;
|
||||
char *name;
|
||||
@@ -159,9 +142,9 @@ static int json_dispatch_address(const char *name, sd_json_variant *variant, sd_
|
||||
}
|
||||
|
||||
static const sd_json_dispatch_field address_parameters_dispatch_table[] = {
|
||||
- { "ifindex", SD_JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(AddressParameters, ifindex), 0 },
|
||||
- { "family", SD_JSON_VARIANT_INTEGER, json_dispatch_family, offsetof(AddressParameters, family), SD_JSON_MANDATORY },
|
||||
- { "address", SD_JSON_VARIANT_ARRAY, json_dispatch_address, 0, SD_JSON_MANDATORY },
|
||||
+ { "ifindex", SD_JSON_VARIANT_INTEGER, json_dispatch_ifindex, offsetof(AddressParameters, ifindex), 0 },
|
||||
+ { "family", SD_JSON_VARIANT_INTEGER, json_dispatch_address_family, offsetof(AddressParameters, family), SD_JSON_MANDATORY },
|
||||
+ { "address", SD_JSON_VARIANT_ARRAY, json_dispatch_address, 0, SD_JSON_MANDATORY },
|
||||
{}
|
||||
};
|
||||
|
||||
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c
|
||||
index 67be81195a..b3895df6cf 100644
|
||||
--- a/src/resolve/resolvectl.c
|
||||
+++ b/src/resolve/resolvectl.c
|
||||
@@ -2386,7 +2386,7 @@ static int dump_cache_scope(sd_json_variant *scope) {
|
||||
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "protocol", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct scope_info, protocol), SD_JSON_MANDATORY },
|
||||
- { "family", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(struct scope_info, family), 0 },
|
||||
+ { "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(struct scope_info, family), SD_JSON_RELAX },
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(struct scope_info, ifindex), SD_JSON_RELAX },
|
||||
{ "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(struct scope_info, ifname), 0 },
|
||||
{ "cache", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_variant_noref, offsetof(struct scope_info, cache), SD_JSON_MANDATORY },
|
||||
diff --git a/src/resolve/resolved-varlink.c b/src/resolve/resolved-varlink.c
|
||||
index 2ac4ee9555..db26ccb11a 100644
|
||||
--- a/src/resolve/resolved-varlink.c
|
||||
+++ b/src/resolve/resolved-varlink.c
|
||||
@@ -346,7 +346,7 @@ static int vl_method_resolve_hostname(sd_varlink *link, sd_json_variant *paramet
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(LookupParameters, ifindex), SD_JSON_RELAX },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParameters, name), SD_JSON_MANDATORY },
|
||||
- { "family", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(LookupParameters, family), 0 },
|
||||
+ { "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(LookupParameters, family), SD_JSON_RELAX },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LookupParameters, flags), 0 },
|
||||
{}
|
||||
};
|
||||
@@ -377,9 +377,6 @@ static int vl_method_resolve_hostname(sd_varlink *link, sd_json_variant *paramet
|
||||
if (r == 0)
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("name"));
|
||||
|
||||
- if (!IN_SET(p.family, AF_UNSPEC, AF_INET, AF_INET6))
|
||||
- return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
|
||||
-
|
||||
if (validate_and_mangle_query_flags(m, &p.flags, p.name, SD_RESOLVED_NO_SEARCH) < 0)
|
||||
return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("flags"));
|
||||
|
||||
@@ -475,7 +472,7 @@ finish:
|
||||
static int vl_method_resolve_address(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field dispatch_table[] = {
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(LookupParameters, ifindex), SD_JSON_RELAX },
|
||||
- { "family", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(LookupParameters, family), SD_JSON_MANDATORY },
|
||||
+ { "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(LookupParameters, family), SD_JSON_MANDATORY },
|
||||
{ "address", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(LookupParameters, address), SD_JSON_MANDATORY },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LookupParameters, flags), 0 },
|
||||
{}
|
||||
@@ -501,9 +498,6 @@ static int vl_method_resolve_address(sd_varlink *link, sd_json_variant *paramete
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
- if (!IN_SET(p.family, AF_INET, AF_INET6))
|
||||
- return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
|
||||
-
|
||||
if (FAMILY_ADDRESS_SIZE(p.family) != p.address.iov_len)
|
||||
return sd_varlink_error(link, "io.systemd.Resolve.BadAddressSize", NULL);
|
||||
|
||||
@@ -961,7 +955,7 @@ static int vl_method_resolve_service(sd_varlink* link, sd_json_variant* paramete
|
||||
{ "type", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParametersResolveService, type), 0 },
|
||||
{ "domain", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(LookupParametersResolveService, domain), SD_JSON_MANDATORY },
|
||||
{ "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(LookupParametersResolveService, ifindex), SD_JSON_RELAX },
|
||||
- { "family", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(LookupParametersResolveService, family), 0 },
|
||||
+ { "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(LookupParametersResolveService, family), SD_JSON_RELAX },
|
||||
{ "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(LookupParametersResolveService, flags), 0 },
|
||||
{}
|
||||
};
|
||||
@@ -987,9 +981,6 @@ static int vl_method_resolve_service(sd_varlink* link, sd_json_variant* paramete
|
||||
if (r != 0)
|
||||
return r;
|
||||
|
||||
- if (!IN_SET(p.family, AF_INET, AF_INET6, AF_UNSPEC))
|
||||
- return sd_varlink_error_invalid_parameter(link, JSON_VARIANT_STRING_CONST("family"));
|
||||
-
|
||||
if (isempty(p.name))
|
||||
p.name = NULL;
|
||||
else if (!dns_service_name_is_valid(p.name))
|
||||
diff --git a/src/shared/dns-configuration.c b/src/shared/dns-configuration.c
|
||||
index 1194e87258..01b59bbd89 100644
|
||||
--- a/src/shared/dns-configuration.c
|
||||
+++ b/src/shared/dns-configuration.c
|
||||
@@ -36,7 +36,7 @@ static int dispatch_dns_server(const char *name, sd_json_variant *variant, sd_js
|
||||
static const sd_json_dispatch_field dns_server_dispatch_table[] = {
|
||||
{ "address", SD_JSON_VARIANT_ARRAY, json_dispatch_byte_array_iovec, offsetof(DNSServer, addr), SD_JSON_MANDATORY },
|
||||
{ "addressString", _SD_JSON_VARIANT_TYPE_INVALID, NULL, 0, 0 },
|
||||
- { "family", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(DNSServer, family), SD_JSON_MANDATORY },
|
||||
+ { "family", SD_JSON_VARIANT_INTEGER, json_dispatch_address_family, offsetof(DNSServer, family), SD_JSON_MANDATORY },
|
||||
{ "port", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint16, offsetof(DNSServer, port), 0 },
|
||||
{ "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSServer, ifindex), SD_JSON_RELAX },
|
||||
{ "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSServer, server_name), 0 },
|
||||
@@ -177,12 +177,12 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(
|
||||
|
||||
static int dispatch_dns_scope(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
static const sd_json_dispatch_field dns_scope_dispatch_table[] = {
|
||||
- { "protocol", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, protocol), SD_JSON_MANDATORY },
|
||||
- { "family", SD_JSON_VARIANT_UNSIGNED, sd_json_dispatch_uint, offsetof(DNSScope, family), 0 },
|
||||
- { "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, ifname), 0 },
|
||||
- { "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSScope, ifindex), SD_JSON_RELAX },
|
||||
- { "dnssec", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, dnssec_mode_str), 0 },
|
||||
- { "dnsOverTLS", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, dns_over_tls_mode_str), 0 },
|
||||
+ { "protocol", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, protocol), SD_JSON_MANDATORY },
|
||||
+ { "family", SD_JSON_VARIANT_INTEGER, json_dispatch_address_family, offsetof(DNSScope, family), SD_JSON_RELAX },
|
||||
+ { "ifname", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, ifname), 0 },
|
||||
+ { "ifindex", SD_JSON_VARIANT_UNSIGNED, json_dispatch_ifindex, offsetof(DNSScope, ifindex), SD_JSON_RELAX },
|
||||
+ { "dnssec", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, dnssec_mode_str), 0 },
|
||||
+ { "dnsOverTLS", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(DNSScope, dns_over_tls_mode_str), 0 },
|
||||
{},
|
||||
};
|
||||
DNSScope **ret = ASSERT_PTR(userdata);
|
||||
--
|
||||
2.55.0
|
||||
|
||||
-305
@@ -1,305 +0,0 @@
|
||||
From 3f73f1ef75d5c8da66eda2cff270676e70becf9b Mon Sep 17 00:00:00 2001
|
||||
From: Nick Rosbrook <enr0n@ubuntu.com>
|
||||
Date: Tue, 23 Jun 2026 12:02:19 -0400
|
||||
Subject: [PATCH] json-util: introduce json_dispatch_in_addr_data
|
||||
|
||||
Generalize json_dispatch_address from nss-resolve, and add support for
|
||||
strings to be compatible with the existing json_dispatch_{in,in6}_addr
|
||||
helpers. This will be used in a later commit.
|
||||
---
|
||||
src/libsystemd/sd-json/json-util.c | 55 ++++++++
|
||||
src/libsystemd/sd-json/json-util.h | 1 +
|
||||
src/libsystemd/sd-json/test-json.c | 194 +++++++++++++++++++++++++++++
|
||||
3 files changed, 250 insertions(+)
|
||||
|
||||
diff --git a/src/libsystemd/sd-json/json-util.c b/src/libsystemd/sd-json/json-util.c
|
||||
index 485b4a03c8..193ee714d0 100644
|
||||
--- a/src/libsystemd/sd-json/json-util.c
|
||||
+++ b/src/libsystemd/sd-json/json-util.c
|
||||
@@ -248,6 +248,61 @@ int json_dispatch_in6_addr(const char *name, sd_json_variant *variant, sd_json_d
|
||||
return 0;
|
||||
}
|
||||
|
||||
+int json_dispatch_in_addr_data(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
+ struct in_addr_data *ret = ASSERT_PTR(userdata), data = { .family = AF_UNSPEC, .address = IN_ADDR_NULL };
|
||||
+ int r;
|
||||
+
|
||||
+ assert(variant);
|
||||
+
|
||||
+ if (sd_json_variant_is_null(variant)) {
|
||||
+ *ret = data;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ /* We support both a more human readable string based encoding and an array based encoding */
|
||||
+ if (sd_json_variant_is_string(variant)) {
|
||||
+ r = in_addr_from_string_auto(sd_json_variant_string(variant), &data.family, &data.address);
|
||||
+ if (r < 0)
|
||||
+ return json_log(variant, flags, r,
|
||||
+ "JSON field '%s' is not a valid IPv4 or IPv6 address string: %s", strna(name), sd_json_variant_string(variant));
|
||||
+ *ret = data;
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ if (!sd_json_variant_is_array(variant))
|
||||
+ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is not an array.", strna(name));
|
||||
+
|
||||
+ switch (sd_json_variant_elements(variant)) {
|
||||
+ case sizeof(struct in_addr):
|
||||
+ data.family = AF_INET;
|
||||
+ break;
|
||||
+ case sizeof(struct in6_addr):
|
||||
+ data.family = AF_INET6;
|
||||
+ break;
|
||||
+ default:
|
||||
+ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "JSON field '%s' is array of unexpected size.", strna(name));
|
||||
+ }
|
||||
+
|
||||
+ size_t k = 0;
|
||||
+ sd_json_variant *i;
|
||||
+ JSON_VARIANT_ARRAY_FOREACH(i, variant) {
|
||||
+ if (!sd_json_variant_is_integer(i))
|
||||
+ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "Element %zu of JSON field '%s' is not an integer.", k, strna(name));
|
||||
+
|
||||
+ int64_t b = sd_json_variant_integer(i);
|
||||
+ if (b < 0 || b > 0xff)
|
||||
+ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL),
|
||||
+ "Element %zu of JSON field '%s' is out of range 0%s255.",
|
||||
+ k, strna(name), glyph(GLYPH_ELLIPSIS));
|
||||
+
|
||||
+ data.address.bytes[k++] = (uint8_t) b;
|
||||
+ }
|
||||
+ assert(k == FAMILY_ADDRESS_SIZE_SAFE(data.family));
|
||||
+
|
||||
+ *ret = data;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
int json_dispatch_const_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
const char **p = ASSERT_PTR(userdata), *path;
|
||||
|
||||
diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h
|
||||
index de7790a6d3..2032566fdd 100644
|
||||
--- a/src/libsystemd/sd-json/json-util.h
|
||||
+++ b/src/libsystemd/sd-json/json-util.h
|
||||
@@ -119,6 +119,7 @@ int json_dispatch_const_user_group_name(const char *name, sd_json_variant *varia
|
||||
int json_dispatch_const_unit_name(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_in_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_in6_addr(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
+int json_dispatch_in_addr_data(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_const_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
int json_dispatch_strv_path(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
diff --git a/src/libsystemd/sd-json/test-json.c b/src/libsystemd/sd-json/test-json.c
|
||||
index bb94dfea4b..6992d095c6 100644
|
||||
--- a/src/libsystemd/sd-json/test-json.c
|
||||
+++ b/src/libsystemd/sd-json/test-json.c
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "fd-util.h"
|
||||
#include "format-util.h"
|
||||
#include "fileio.h"
|
||||
+#include "in-addr-util.h"
|
||||
#include "io-util.h"
|
||||
#include "iovec-util.h"
|
||||
#include "json-internal.h"
|
||||
@@ -1998,4 +1999,197 @@ TEST(json_dispatch_in6_addr) {
|
||||
ASSERT_EQ(data.addr.s6_addr[i], 0);
|
||||
}
|
||||
|
||||
+TEST(json_dispatch_in_addr_data) {
|
||||
+ _cleanup_(sd_json_variant_unrefp) sd_json_variant *j = NULL;
|
||||
+
|
||||
+ /* 192.168.1.1 = { 192, 168, 1, 1 } */
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", JSON_BUILD_IN4_ADDR(&(const struct in_addr) { .s_addr = htobe32(0xC0A80101U) })),
|
||||
+ SD_JSON_BUILD_PAIR("null_addr", SD_JSON_BUILD_NULL))));
|
||||
+
|
||||
+ struct {
|
||||
+ struct in_addr_data addr;
|
||||
+ struct in_addr_data null_addr;
|
||||
+ } data = {};
|
||||
+
|
||||
+ ASSERT_OK(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(typeof(data), addr) },
|
||||
+ { "null_addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(typeof(data), null_addr) },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &data));
|
||||
+
|
||||
+ ASSERT_EQ(be32toh(data.addr.address.in.s_addr), 0xC0A80101U);
|
||||
+ ASSERT_EQ(data.null_addr.address.in.s_addr, 0U);
|
||||
+ ASSERT_EQ(data.addr.family, AF_INET);
|
||||
+ ASSERT_EQ(data.null_addr.family, AF_UNSPEC);
|
||||
+
|
||||
+ struct in_addr_data dummy = {};
|
||||
+
|
||||
+ /* Too few bytes (3 instead of 4) */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_UNSIGNED(192), SD_JSON_BUILD_UNSIGNED(168), SD_JSON_BUILD_UNSIGNED(1))))));
|
||||
+ ASSERT_ERROR(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &dummy), EINVAL);
|
||||
+
|
||||
+ /* Too many bytes (5 instead of 4) */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_UNSIGNED(192), SD_JSON_BUILD_UNSIGNED(168), SD_JSON_BUILD_UNSIGNED(1), SD_JSON_BUILD_UNSIGNED(1), SD_JSON_BUILD_UNSIGNED(0))))));
|
||||
+ ASSERT_ERROR(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &dummy), EINVAL);
|
||||
+
|
||||
+ /* Not an array or string */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_BOOLEAN(true)))));
|
||||
+ ASSERT_ERROR(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &dummy), EINVAL);
|
||||
+
|
||||
+ /* A string */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", JSON_BUILD_CONST_STRING("192.168.1.1")))));
|
||||
+ zero(data);
|
||||
+ ASSERT_OK(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &data));
|
||||
+ ASSERT_EQ(be32toh(data.addr.address.in.s_addr), 0xC0A80101U);
|
||||
+ ASSERT_EQ(data.addr.family, AF_INET);
|
||||
+
|
||||
+ /* Byte value out of range (> 255) */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_UNSIGNED(256), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1))))));
|
||||
+ ASSERT_ERROR(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &dummy), EINVAL);
|
||||
+
|
||||
+ /* Negative element */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(SD_JSON_BUILD_INTEGER(-1), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1))))));
|
||||
+ ASSERT_ERROR(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &dummy), EINVAL);
|
||||
+
|
||||
+ /* ::1 */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", JSON_BUILD_IN6_ADDR(&(const struct in6_addr) { .s6_addr = { [15] = 1 } })),
|
||||
+ SD_JSON_BUILD_PAIR("null_addr", SD_JSON_BUILD_NULL))));
|
||||
+
|
||||
+ zero(data);
|
||||
+ ASSERT_OK(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(typeof(data), addr) },
|
||||
+ { "null_addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(typeof(data), null_addr) },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &data));
|
||||
+
|
||||
+ ASSERT_EQ(data.addr.address.in6.s6_addr[15], 1);
|
||||
+ for (size_t i = 0; i < 15; i++)
|
||||
+ ASSERT_EQ(data.addr.address.in6.s6_addr[i], 0);
|
||||
+ for (size_t i = 0; i < 16; i++)
|
||||
+ ASSERT_EQ(data.null_addr.address.in6.s6_addr[i], 0);
|
||||
+ ASSERT_EQ(data.addr.family, AF_INET6);
|
||||
+ ASSERT_EQ(data.null_addr.family, AF_UNSPEC);
|
||||
+
|
||||
+ /* Too few bytes (15 instead of 16) */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(
|
||||
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1))))));
|
||||
+ ASSERT_ERROR(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &dummy), EINVAL);
|
||||
+
|
||||
+ /* Too many bytes (17 instead of 16) */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_ARRAY(
|
||||
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0),
|
||||
+ SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(0), SD_JSON_BUILD_UNSIGNED(1),
|
||||
+ SD_JSON_BUILD_UNSIGNED(0))))));
|
||||
+ ASSERT_ERROR(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &dummy), EINVAL);
|
||||
+
|
||||
+ /* Not an array */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", SD_JSON_BUILD_BOOLEAN(true)))));
|
||||
+ ASSERT_ERROR(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &dummy), EINVAL);
|
||||
+
|
||||
+ /* A string */
|
||||
+ j = sd_json_variant_unref(j);
|
||||
+ ASSERT_OK(sd_json_build(&j, SD_JSON_BUILD_OBJECT(
|
||||
+ SD_JSON_BUILD_PAIR("addr", JSON_BUILD_CONST_STRING("::1")))));
|
||||
+
|
||||
+ zero(data);
|
||||
+ ASSERT_OK(sd_json_dispatch(j,
|
||||
+ (const sd_json_dispatch_field[]) {
|
||||
+ { "addr", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, 0 },
|
||||
+ {},
|
||||
+ },
|
||||
+ /* flags= */ 0,
|
||||
+ &data));
|
||||
+
|
||||
+ ASSERT_EQ(data.addr.address.in6.s6_addr[15], 1);
|
||||
+ for (size_t i = 0; i < 15; i++)
|
||||
+ ASSERT_EQ(data.addr.address.in6.s6_addr[i], 0);
|
||||
+ ASSERT_EQ(data.addr.family, AF_INET6);
|
||||
+}
|
||||
+
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
--
|
||||
2.55.0
|
||||
|
||||
-440
@@ -1,440 +0,0 @@
|
||||
From 35d611622a0c4277e1a3e0b8866a800c0fc6fcf8 Mon Sep 17 00:00:00 2001
|
||||
From: Nick Rosbrook <enr0n@ubuntu.com>
|
||||
Date: Fri, 19 Jun 2026 15:01:00 -0400
|
||||
Subject: [PATCH] resolvectl: use varlink instead of dbus for ResolveHostname
|
||||
|
||||
---
|
||||
src/resolve/resolvectl.c | 202 +++++++++++++++++++-----------
|
||||
src/shared/meson.build | 1 +
|
||||
src/shared/resolve-varlink-util.c | 107 ++++++++++++++++
|
||||
src/shared/resolve-varlink-util.h | 34 +++++
|
||||
4 files changed, 274 insertions(+), 70 deletions(-)
|
||||
create mode 100644 src/shared/resolve-varlink-util.c
|
||||
create mode 100644 src/shared/resolve-varlink-util.h
|
||||
|
||||
diff --git a/src/resolve/resolvectl.c b/src/resolve/resolvectl.c
|
||||
index b3895df6cf..4baa2f3868 100644
|
||||
--- a/src/resolve/resolvectl.c
|
||||
+++ b/src/resolve/resolvectl.c
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "resolvectl.h"
|
||||
#include "resolved-def.h"
|
||||
#include "resolved-util.h"
|
||||
+#include "resolve-varlink-util.h"
|
||||
#include "set.h"
|
||||
#include "socket-netlink.h"
|
||||
#include "string-table.h"
|
||||
@@ -278,20 +279,97 @@ static void print_ifindex_comment(int printed_so_far, int ifindex) {
|
||||
ansi_grey(), ifname, ansi_normal());
|
||||
}
|
||||
|
||||
-static int resolve_host_error(const char *name, int r, const sd_bus_error *error) {
|
||||
- if (sd_bus_error_has_name(error, BUS_ERROR_DNS_NXDOMAIN))
|
||||
- return log_error_errno(r, "%s: %s", name, bus_error_message(error, r));
|
||||
+static int varlink_log_resolve_error(const char *name, const char *error_id, sd_json_variant *reply) {
|
||||
+ int r;
|
||||
+
|
||||
+ assert(name);
|
||||
+ assert(!isempty(error_id));
|
||||
+
|
||||
+ int ret = sd_varlink_error_to_errno(error_id, reply);
|
||||
+ static const struct {
|
||||
+ const char *error_id;
|
||||
+ const char *msg;
|
||||
+ } error_message_table[] = {
|
||||
+ { "io.systemd.Resolve.NoNameServers", "No appropriate name servers or networks for name found" },
|
||||
+ { "io.systemd.Resolve.QueryTimedOut", "Query timed out" },
|
||||
+ { "io.systemd.Resolve.MaxAttemptsReached", "All attempts to contact name servers or networks failed" },
|
||||
+ { "io.systemd.Resolve.InvalidReply", "Received invalid reply" },
|
||||
+ { "io.systemd.Resolve.QueryAborted", "Query aborted" },
|
||||
+ { "io.systemd.Resolve.QueryRefused", "DNS query type refused" },
|
||||
+ { "io.systemd.Resolve.NoTrustAnchor", "No suitable trust anchor known" },
|
||||
+ { "io.systemd.Resolve.ResourceRecordTypeUnsupported", "Server does not support requested resource record type" },
|
||||
+ { "io.systemd.Resolve.NetworkDown", "Network is down" },
|
||||
+ { "io.systemd.Resolve.NoSource", "All suitable resolution sources turned off" },
|
||||
+ { "io.systemd.Resolve.StubLoop", "Configured DNS server loops back to us" },
|
||||
+ { "io.systemd.Resolve.ZoneTransfersNotPermitted", "Zone transfers not permitted via this programming interface" },
|
||||
+ };
|
||||
+ FOREACH_ELEMENT(em, error_message_table)
|
||||
+ if (streq(em->error_id, error_id))
|
||||
+ return log_error_errno(ret, "%s: resolve call failed: %s", name, em->msg);
|
||||
+
|
||||
+ if (streq(error_id, "io.systemd.Resolve.NoSuchResourceRecord"))
|
||||
+ return log_error_errno(ret, "%s: resolve call failed: '%s' does not have any RR of the requested type", name, name);
|
||||
|
||||
- return log_error_errno(r, "%s: resolve call failed: %s", name, bus_error_message(error, r));
|
||||
+ if (streq(error_id, "io.systemd.Resolve.CNAMELoop"))
|
||||
+ return log_error_errno(ret, "%s: resolve call failed: CNAME loop detected, or CNAME resolving disabled on '%s'", name, name);
|
||||
+
|
||||
+ if (streq(error_id, "io.systemd.Resolve.ServiceNotProvided"))
|
||||
+ return log_error_errno(ret, "%s: resolve call failed: '%s' does not provide the requested service", name, name);
|
||||
+
|
||||
+ if (streq(error_id, "io.systemd.Resolve.InconsistentServiceRecords"))
|
||||
+ return log_error_errno(ret, "%s: resolve call failed: '%s' does not provide a consistent set of service resource records", name, name);
|
||||
+
|
||||
+ _cleanup_(resolve_error_done) ResolveError error = {
|
||||
+ .rcode = _DNS_RCODE_INVALID,
|
||||
+ .ede_rcode = _DNS_EDE_RCODE_INVALID,
|
||||
+ };
|
||||
+ r = dispatch_resolve_error(/* name = */ NULL, reply, SD_JSON_LOG, &error);
|
||||
+ if (r < 0)
|
||||
+ log_debug_errno(r, "Failed to dispatch error JSON, ignoring: %m");
|
||||
+
|
||||
+ _cleanup_free_ char *msg_extended = NULL;
|
||||
+ if (error.ede_rcode >= 0) {
|
||||
+ msg_extended = strjoin(" (",
|
||||
+ FORMAT_DNS_EDE_RCODE(error.ede_rcode),
|
||||
+ !isempty(error.ede_msg) ? ": " : "",
|
||||
+ strempty(error.ede_msg),
|
||||
+ ")");
|
||||
+ if (!msg_extended)
|
||||
+ return log_oom();
|
||||
+ }
|
||||
+
|
||||
+ if (streq(error_id, "io.systemd.Resolve.DNSSECValidationFailed"))
|
||||
+ return log_error_errno(ret, "%s: resolve call failed: DNSSEC validation failed: %s%s", name, error.result, strempty(msg_extended));
|
||||
+
|
||||
+ if (error.rcode != _DNS_RCODE_INVALID) {
|
||||
+ if (error.rcode == DNS_RCODE_NXDOMAIN)
|
||||
+ return log_error_errno(SYNTHETIC_ERRNO(ENXIO), "%s: resolve call failed: Name '%s' not found%s%s",
|
||||
+ name, error.query_string ?: name, error.ede_rcode >= 0 ? ":" : "", strempty(msg_extended));
|
||||
+
|
||||
+ return log_error_errno(ret, "%s: resolve call failed: Could not resolve '%s', server or network returned error: %s%s",
|
||||
+ name, error.query_string ?: name, FORMAT_DNS_RCODE(error.rcode), strempty(msg_extended));
|
||||
+ }
|
||||
+
|
||||
+ return log_error_errno(ret, "%s: resolve call failed: %s", name, error_id);
|
||||
}
|
||||
|
||||
-static int resolve_host(sd_bus *bus, const char *name) {
|
||||
- _cleanup_(sd_bus_message_unrefp) sd_bus_message *req = NULL, *reply = NULL;
|
||||
- _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
- const char *canonical = NULL;
|
||||
- unsigned c = 0;
|
||||
- uint64_t flags;
|
||||
- usec_t ts;
|
||||
+static int varlink_connect_with_query_timeout(sd_varlink **vl) {
|
||||
+ int r;
|
||||
+
|
||||
+ assert(vl);
|
||||
+
|
||||
+ r = sd_varlink_connect_address(vl, "/run/systemd/resolve/io.systemd.Resolve");
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to connect to service /run/systemd/resolve/io.systemd.Resolve: %m");
|
||||
+
|
||||
+ r = sd_varlink_set_relative_timeout(*vl, SD_RESOLVED_QUERY_TIMEOUT_USEC);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to set query timeout: %m");
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int resolve_host(const char *name) {
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
@@ -301,85 +379,69 @@ static int resolve_host(sd_bus *bus, const char *name) {
|
||||
|
||||
log_debug("Resolving %s (family %s, interface %s).", name, af_to_name(arg_family) ?: "*", isempty(arg_ifname) ? "*" : arg_ifname);
|
||||
|
||||
- r = bus_message_new_method_call(bus, &req, bus_resolve_mgr, "ResolveHostname");
|
||||
- if (r < 0)
|
||||
- return bus_log_create_error(r);
|
||||
-
|
||||
- r = sd_bus_message_append(req, "isit", arg_ifindex, name, arg_family, arg_flags);
|
||||
+ _cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
|
||||
+ r = varlink_connect_with_query_timeout(&vl);
|
||||
if (r < 0)
|
||||
- return bus_log_create_error(r);
|
||||
+ return r;
|
||||
|
||||
- ts = now(CLOCK_MONOTONIC);
|
||||
+ usec_t ts = now(CLOCK_MONOTONIC);
|
||||
|
||||
- r = sd_bus_call(bus, req, SD_RESOLVED_QUERY_TIMEOUT_USEC, &error, &reply);
|
||||
+ const char *error_id = NULL;
|
||||
+ sd_json_variant *v = NULL;
|
||||
+ r = sd_varlink_callbo(
|
||||
+ vl,
|
||||
+ "io.systemd.Resolve.ResolveHostname",
|
||||
+ &v,
|
||||
+ &error_id,
|
||||
+ SD_JSON_BUILD_PAIR_STRING("name", name),
|
||||
+ JSON_BUILD_PAIR_CONDITION_UNSIGNED(arg_ifindex > 0, "ifindex", arg_ifindex),
|
||||
+ JSON_BUILD_PAIR_CONDITION_UNSIGNED(arg_family != AF_UNSPEC, "family", arg_family),
|
||||
+ JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("flags", arg_flags));
|
||||
if (r < 0)
|
||||
- return resolve_host_error(name, r, &error);
|
||||
+ return log_error_errno(r, "Failed to issue varlink call: %m");
|
||||
|
||||
ts = now(CLOCK_MONOTONIC) - ts;
|
||||
|
||||
- r = sd_bus_message_enter_container(reply, 'a', "(iiay)");
|
||||
+ if (!isempty(error_id))
|
||||
+ return varlink_log_resolve_error(name, error_id, v);
|
||||
+
|
||||
+ _cleanup_(resolve_hostname_reply_done) ResolveHostnameReply reply = {};
|
||||
+ r = dispatch_resolve_hostname_reply(/* name = */ NULL, v, SD_JSON_LOG, &reply);
|
||||
if (r < 0)
|
||||
- return bus_log_parse_error(r);
|
||||
+ return r;
|
||||
|
||||
- while ((r = sd_bus_message_enter_container(reply, 'r', "iiay")) > 0) {
|
||||
+ bool first = true;
|
||||
+ FOREACH_ARRAY(address, reply.addresses, reply.n_addresses) {
|
||||
_cleanup_free_ char *pretty = NULL;
|
||||
- int ifindex, family, k;
|
||||
- union in_addr_union a;
|
||||
-
|
||||
- assert_cc(sizeof(int) == sizeof(int32_t));
|
||||
-
|
||||
- r = sd_bus_message_read(reply, "i", &ifindex);
|
||||
- if (r < 0)
|
||||
- return bus_log_parse_error(r);
|
||||
-
|
||||
- sd_bus_error_free(&error);
|
||||
- r = bus_message_read_in_addr_auto(reply, &error, &family, &a);
|
||||
- if (r < 0 && !sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS))
|
||||
- return log_error_errno(r, "%s: systemd-resolved returned invalid result: %s", name, bus_error_message(&error, r));
|
||||
-
|
||||
- r = sd_bus_message_exit_container(reply);
|
||||
- if (r < 0)
|
||||
- return bus_log_parse_error(r);
|
||||
-
|
||||
- if (sd_bus_error_has_name(&error, SD_BUS_ERROR_INVALID_ARGS)) {
|
||||
- log_debug_errno(r, "%s: systemd-resolved returned invalid result, ignoring: %s", name, bus_error_message(&error, r));
|
||||
- continue;
|
||||
- }
|
||||
-
|
||||
- r = in_addr_ifindex_to_string(family, &a, ifindex, &pretty);
|
||||
+ r = in_addr_ifindex_to_string(address->family, &address->in_addr.address, address->ifindex, &pretty);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to print address for %s: %m", name);
|
||||
|
||||
- k = printf("%*s%s %s%s%s",
|
||||
- (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
|
||||
- ansi_highlight(), pretty, ansi_normal());
|
||||
+ int k = printf("%*s%s %s%s%s",
|
||||
+ (int) strlen(name),
|
||||
+ first ? name : "",
|
||||
+ first ? ":" : " ",
|
||||
+ ansi_highlight(),
|
||||
+ pretty,
|
||||
+ ansi_normal());
|
||||
|
||||
- print_ifindex_comment(k, ifindex);
|
||||
+ print_ifindex_comment(k, address->ifindex);
|
||||
fputc('\n', stdout);
|
||||
|
||||
- c++;
|
||||
+ first = false;
|
||||
}
|
||||
- if (r < 0)
|
||||
- return bus_log_parse_error(r);
|
||||
-
|
||||
- r = sd_bus_message_exit_container(reply);
|
||||
- if (r < 0)
|
||||
- return bus_log_parse_error(r);
|
||||
|
||||
- r = sd_bus_message_read(reply, "st", &canonical, &flags);
|
||||
- if (r < 0)
|
||||
- return bus_log_parse_error(r);
|
||||
-
|
||||
- if (!streq(name, canonical))
|
||||
+ if (!streq(name, reply.name))
|
||||
printf("%*s%s (%s)\n",
|
||||
- (int) strlen(name), c == 0 ? name : "", c == 0 ? ":" : " ",
|
||||
- canonical);
|
||||
+ (int) strlen(name),
|
||||
+ reply.n_addresses == 0 ? name : "",
|
||||
+ reply.n_addresses == 0 ? ":" : " ",
|
||||
+ reply.name);
|
||||
|
||||
- if (c == 0)
|
||||
- return log_error_errno(SYNTHETIC_ERRNO(ESRCH),
|
||||
- "%s: no addresses found", name);
|
||||
+ if (reply.n_addresses == 0)
|
||||
+ return log_error_errno(SYNTHETIC_ERRNO(ESRCH), "%s: no addresses found", name);
|
||||
|
||||
- print_source(flags, ts);
|
||||
+ print_source(reply.flags, ts);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -827,7 +889,7 @@ static int verb_query(int argc, char *argv[], uintptr_t _data, void *userdata) {
|
||||
if (r >= 0)
|
||||
RET_GATHER(ret, resolve_address(bus, family, &a, ifindex));
|
||||
else
|
||||
- RET_GATHER(ret, resolve_host(bus, *p));
|
||||
+ RET_GATHER(ret, resolve_host(*p));
|
||||
}
|
||||
}
|
||||
|
||||
diff --git a/src/shared/meson.build b/src/shared/meson.build
|
||||
index 6fa4216305..7b2a8b5ee2 100644
|
||||
--- a/src/shared/meson.build
|
||||
+++ b/src/shared/meson.build
|
||||
@@ -185,6 +185,7 @@ shared_sources = files(
|
||||
'resize-fs.c',
|
||||
'resolve-hook-util.c',
|
||||
'resolve-util.c',
|
||||
+ 'resolve-varlink-util.c',
|
||||
'rm-rf.c',
|
||||
'seccomp-util.c',
|
||||
'securebits-util.c',
|
||||
diff --git a/src/shared/resolve-varlink-util.c b/src/shared/resolve-varlink-util.c
|
||||
new file mode 100644
|
||||
index 0000000000..3459cfc9d6
|
||||
--- /dev/null
|
||||
+++ b/src/shared/resolve-varlink-util.c
|
||||
@@ -0,0 +1,107 @@
|
||||
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
+
|
||||
+#include "sd-json.h"
|
||||
+
|
||||
+#include "dns-packet.h"
|
||||
+#include "json-util.h"
|
||||
+#include "resolve-varlink-util.h"
|
||||
+
|
||||
+void resolve_error_done(ResolveError *error) {
|
||||
+ if (!error)
|
||||
+ return;
|
||||
+
|
||||
+ error->ede_msg = mfree(error->ede_msg);
|
||||
+ error->query_string = mfree(error->query_string);
|
||||
+ error->result = mfree(error->result);
|
||||
+}
|
||||
+
|
||||
+int dispatch_resolve_error(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
+ static const sd_json_dispatch_field resolve_error_dispatch_table[] = {
|
||||
+ { "rcode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(ResolveError, rcode), 0 },
|
||||
+ { "extendedDNSErrorCode", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_int, offsetof(ResolveError, ede_rcode), 0 },
|
||||
+ { "extendedDNSErrorMessage", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveError, ede_msg), 0 },
|
||||
+ { "queryString", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveError, query_string), 0 },
|
||||
+ { "result", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveError, result), 0 },
|
||||
+ {},
|
||||
+ };
|
||||
+ ResolveError *ret = ASSERT_PTR(userdata);
|
||||
+ int r;
|
||||
+
|
||||
+ _cleanup_(resolve_error_done) ResolveError error = {
|
||||
+ .rcode = _DNS_RCODE_INVALID,
|
||||
+ .ede_rcode = _DNS_EDE_RCODE_INVALID,
|
||||
+ };
|
||||
+ r = sd_json_dispatch(variant, resolve_error_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &error);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ *ret = TAKE_STRUCT(error);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int dispatch_resolved_address(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
+ static const sd_json_dispatch_field resolved_address_dispatch_table[] = {
|
||||
+ { "ifindex", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_ifindex, offsetof(ResolvedAddress, ifindex), SD_JSON_RELAX },
|
||||
+ { "family", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_address_family, offsetof(ResolvedAddress, family), SD_JSON_MANDATORY },
|
||||
+ { "address", _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_in_addr_data, offsetof(ResolvedAddress, in_addr), SD_JSON_MANDATORY },
|
||||
+ {},
|
||||
+ };
|
||||
+ ResolvedAddress *ret = ASSERT_PTR(userdata);
|
||||
+ int r;
|
||||
+
|
||||
+ ResolvedAddress address = {};
|
||||
+ r = sd_json_dispatch(variant, resolved_address_dispatch_table, flags & ~SD_JSON_MANDATORY, &address);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ if (address.family != address.in_addr.family)
|
||||
+ return json_log(variant, flags, SYNTHETIC_ERRNO(EINVAL), "'%s' address and family are inconsistent.", strna(name));
|
||||
+
|
||||
+ *ret = TAKE_STRUCT(address);
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int dispatch_resolved_address_array(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
+ ResolveHostnameReply *reply = ASSERT_PTR(userdata);
|
||||
+ int r;
|
||||
+
|
||||
+ sd_json_variant *v;
|
||||
+ JSON_VARIANT_ARRAY_FOREACH(v, variant) {
|
||||
+ if (!GREEDY_REALLOC0(reply->addresses, reply->n_addresses + 1))
|
||||
+ return json_log_oom(variant, flags);
|
||||
+
|
||||
+ r = dispatch_resolved_address(name, v, flags, &reply->addresses[reply->n_addresses++]);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+void resolve_hostname_reply_done(ResolveHostnameReply *reply) {
|
||||
+ if (!reply)
|
||||
+ return;
|
||||
+
|
||||
+ reply->name = mfree(reply->name);
|
||||
+ reply->addresses = mfree(reply->addresses);
|
||||
+ reply->n_addresses = 0;
|
||||
+}
|
||||
+
|
||||
+int dispatch_resolve_hostname_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata) {
|
||||
+ static const sd_json_dispatch_field resolve_hostname_reply_dispatch_table[] = {
|
||||
+ { "name", SD_JSON_VARIANT_STRING, sd_json_dispatch_string, offsetof(ResolveHostnameReply, name), SD_JSON_MANDATORY },
|
||||
+ { "flags", _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint64, offsetof(ResolveHostnameReply, flags), SD_JSON_MANDATORY },
|
||||
+ { "addresses", SD_JSON_VARIANT_ARRAY, dispatch_resolved_address_array, 0, SD_JSON_MANDATORY },
|
||||
+ {},
|
||||
+ };
|
||||
+ ResolveHostnameReply *ret = ASSERT_PTR(userdata);
|
||||
+ int r;
|
||||
+
|
||||
+ _cleanup_(resolve_hostname_reply_done) ResolveHostnameReply reply = {};
|
||||
+ r = sd_json_dispatch(variant, resolve_hostname_reply_dispatch_table, flags | SD_JSON_ALLOW_EXTENSIONS, &reply);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+
|
||||
+ *ret = TAKE_STRUCT(reply);
|
||||
+ return 0;
|
||||
+}
|
||||
diff --git a/src/shared/resolve-varlink-util.h b/src/shared/resolve-varlink-util.h
|
||||
new file mode 100644
|
||||
index 0000000000..4e94fbe8c6
|
||||
--- /dev/null
|
||||
+++ b/src/shared/resolve-varlink-util.h
|
||||
@@ -0,0 +1,34 @@
|
||||
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
+#pragma once
|
||||
+
|
||||
+#include "in-addr-util.h"
|
||||
+#include "shared-forward.h"
|
||||
+
|
||||
+typedef struct ResolveError {
|
||||
+ int rcode;
|
||||
+ int ede_rcode;
|
||||
+ char *ede_msg;
|
||||
+ char *query_string;
|
||||
+ char *result;
|
||||
+} ResolveError;
|
||||
+
|
||||
+void resolve_error_done(ResolveError *error);
|
||||
+
|
||||
+int dispatch_resolve_error(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
+
|
||||
+typedef struct ResolvedAddress {
|
||||
+ int ifindex;
|
||||
+ int family;
|
||||
+ struct in_addr_data in_addr;
|
||||
+} ResolvedAddress;
|
||||
+
|
||||
+typedef struct ResolveHostnameReply {
|
||||
+ char *name;
|
||||
+ uint64_t flags;
|
||||
+ ResolvedAddress *addresses;
|
||||
+ size_t n_addresses;
|
||||
+} ResolveHostnameReply;
|
||||
+
|
||||
+void resolve_hostname_reply_done(ResolveHostnameReply *reply);
|
||||
+
|
||||
+int dispatch_resolve_hostname_reply(const char *name, sd_json_variant *variant, sd_json_dispatch_flags_t flags, void *userdata);
|
||||
--
|
||||
2.55.0
|
||||
|
||||
@@ -1,267 +0,0 @@
|
||||
From 58fc96bb716cdd5ec17796914283720ef9f28240 Mon Sep 17 00:00:00 2001
|
||||
From: Clayton Craft <clayton@craftyguy.net>
|
||||
Date: Sat, 23 May 2026 17:42:55 -0700
|
||||
Subject: [PATCH 1/3] pam_systemd: add inhibit= and inhibit-why= module
|
||||
arguments to parse_argv
|
||||
|
||||
This adds two new module arguments to parse_argv:
|
||||
|
||||
1) inhibit= takes a colon-separated list of inhibitor lock types to acquire
|
||||
|
||||
2) inhibit-why= takes an optional human-readable reason string.
|
||||
|
||||
Both are currently parsed but are unused until a later commit.
|
||||
---
|
||||
src/login/pam_systemd.c | 14 +++++++++++++-
|
||||
1 file changed, 13 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
|
||||
index 9bdd147db4d08..aeb917977bdbf 100644
|
||||
--- a/src/login/pam_systemd.c
|
||||
+++ b/src/login/pam_systemd.c
|
||||
@@ -117,6 +117,8 @@ static int parse_argv(
|
||||
const char **type,
|
||||
const char **desktop,
|
||||
const char **area,
|
||||
+ const char **inhibit_what,
|
||||
+ const char **inhibit_why,
|
||||
bool *debug,
|
||||
uint64_t *default_capability_bounding_set,
|
||||
uint64_t *default_capability_ambient_set) {
|
||||
@@ -148,6 +150,12 @@ static int parse_argv(
|
||||
sym_pam_syslog(pamh, LOG_WARNING, "Area name specified among PAM module parameters is not valid, ignoring: %s", p);
|
||||
else if (area)
|
||||
*area = p;
|
||||
+ } else if ((p = startswith(argv[i], "inhibit="))) {
|
||||
+ if (inhibit_what)
|
||||
+ *inhibit_what = p;
|
||||
+ } else if ((p = startswith(argv[i], "inhibit-why="))) {
|
||||
+ if (inhibit_why)
|
||||
+ *inhibit_why = p;
|
||||
|
||||
} else if (streq(argv[i], "debug")) {
|
||||
if (debug)
|
||||
@@ -1755,7 +1763,7 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
pam_log_setup();
|
||||
|
||||
uint64_t default_capability_bounding_set = CAP_MASK_UNSET, default_capability_ambient_set = CAP_MASK_UNSET;
|
||||
- const char *class_pam = NULL, *type_pam = NULL, *desktop_pam = NULL, *area_pam = NULL;
|
||||
+ const char *class_pam = NULL, *type_pam = NULL, *desktop_pam = NULL, *area_pam = NULL, *inhibit_what = NULL, *inhibit_why = NULL;
|
||||
bool debug = false;
|
||||
if (parse_argv(pamh,
|
||||
argc, argv,
|
||||
@@ -1763,6 +1771,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
&type_pam,
|
||||
&desktop_pam,
|
||||
&area_pam,
|
||||
+ &inhibit_what,
|
||||
+ &inhibit_why,
|
||||
&debug,
|
||||
&default_capability_bounding_set,
|
||||
&default_capability_ambient_set) < 0)
|
||||
@@ -1859,6 +1869,8 @@ _public_ PAM_EXTERN int pam_sm_close_session(
|
||||
/* type= */ NULL,
|
||||
/* desktop= */ NULL,
|
||||
/* area= */ NULL,
|
||||
+ /* inhibit_what= */ NULL,
|
||||
+ /* inhibit_why= */ NULL,
|
||||
&debug,
|
||||
/* default_capability_bounding_set= */ NULL,
|
||||
/* default_capability_ambient_set= */ NULL) < 0)
|
||||
|
||||
From 179b7c2ab5491e7772c51acc33abd0a991be9851 Mon Sep 17 00:00:00 2001
|
||||
From: Clayton Craft <clayton@craftyguy.net>
|
||||
Date: Sat, 23 May 2026 20:06:31 -0700
|
||||
Subject: [PATCH 2/3] pam_systemd: acquire inhibit lock when inhibit= is
|
||||
specified
|
||||
|
||||
This adds a new function, acquire_inhibit_lock, that takes a logind
|
||||
inhibitor lock for the duration of the PAM session. The lock fd is
|
||||
stored in PAM data with pam_cleanup_close. In pam_sm_close_session, the
|
||||
lock is released explicitly by passing NULL to pam_set_data, which
|
||||
triggers the registered cleanup function immediately rather than waiting
|
||||
for pam_end.
|
||||
|
||||
The inhibit type and reason string can also be configured via the
|
||||
XDG_SESSION_INHIBIT and XDG_SESSION_INHIBIT_WHY environment variables,
|
||||
which take precedence over the module arguments.
|
||||
|
||||
Fixes: #20654
|
||||
---
|
||||
src/login/pam_systemd.c | 60 +++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 60 insertions(+)
|
||||
|
||||
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
|
||||
index aeb917977bdbf..06d19607b2f9c 100644
|
||||
--- a/src/login/pam_systemd.c
|
||||
+++ b/src/login/pam_systemd.c
|
||||
@@ -1747,6 +1747,57 @@ static int close_osc_context(pam_handle_t *pamh, bool debug) {
|
||||
return PAM_SUCCESS;
|
||||
}
|
||||
|
||||
+static int acquire_inhibit_lock(
|
||||
+ pam_handle_t *pamh,
|
||||
+ const char *inhibit_what,
|
||||
+ const char *inhibit_why,
|
||||
+ bool debug) {
|
||||
+
|
||||
+ _cleanup_(pam_bus_data_disconnectp) PamBusData *d = NULL;
|
||||
+ _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
|
||||
+ _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
+ _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
|
||||
+ const char *service = NULL;
|
||||
+ int r;
|
||||
+
|
||||
+ assert(pamh);
|
||||
+ assert(inhibit_what);
|
||||
+
|
||||
+ r = pam_acquire_bus_connection(pamh, "pam-systemd", debug, &bus, &d);
|
||||
+ if (r != PAM_SUCCESS)
|
||||
+ return r;
|
||||
+
|
||||
+ (void) sym_pam_get_item(pamh, PAM_SERVICE, (const void **) &service);
|
||||
+
|
||||
+ r = bus_call_method(bus, bus_login_mgr, "Inhibit", &error, &reply, "ssss",
|
||||
+ inhibit_what,
|
||||
+ service ?: "pam_systemd",
|
||||
+ inhibit_why ?: "Active PAM session",
|
||||
+ "block");
|
||||
+ if (r < 0) {
|
||||
+ sym_pam_syslog(pamh, LOG_WARNING, "Failed to acquire inhibit lock: %s", bus_error_message(&error, r));
|
||||
+ return PAM_SESSION_ERR;
|
||||
+ }
|
||||
+
|
||||
+ int raw_fd;
|
||||
+ r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_UNIX_FD, &raw_fd);
|
||||
+ if (r < 0)
|
||||
+ return pam_bus_log_parse_error(pamh, r);
|
||||
+
|
||||
+ _cleanup_close_ int fd = fcntl(raw_fd, F_DUPFD_CLOEXEC, 3);
|
||||
+ if (fd < 0)
|
||||
+ return pam_syslog_errno(pamh, LOG_ERR, errno, "Failed to dup inhibit lock fd: %m");
|
||||
+
|
||||
+ r = sym_pam_set_data(pamh, "systemd.inhibit-fd", FD_TO_PTR(fd), pam_cleanup_close);
|
||||
+ if (r != PAM_SUCCESS)
|
||||
+ return pam_syslog_pam_error(pamh, LOG_ERR, r,
|
||||
+ "Failed to store inhibit lock fd: @PAMERR@");
|
||||
+ TAKE_FD(fd);
|
||||
+
|
||||
+ pam_debug_syslog(pamh, debug, "Acquired inhibit lock for '%s'.", inhibit_what);
|
||||
+ return PAM_SUCCESS;
|
||||
+}
|
||||
+
|
||||
_public_ PAM_EXTERN int pam_sm_open_session(
|
||||
pam_handle_t *pamh,
|
||||
int flags,
|
||||
@@ -1803,6 +1854,8 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
c.desktop = getenv_harder(pamh, "XDG_SESSION_DESKTOP", desktop_pam);
|
||||
c.area = getenv_harder(pamh, "XDG_AREA", area_pam);
|
||||
c.incomplete = getenv_harder_bool(pamh, "XDG_SESSION_INCOMPLETE", false);
|
||||
+ inhibit_what = getenv_harder(pamh, "XDG_SESSION_INHIBIT", inhibit_what);
|
||||
+ inhibit_why = getenv_harder(pamh, "XDG_SESSION_INHIBIT_WHY", inhibit_why);
|
||||
|
||||
const char *extra_device_access = getenv_harder(pamh, "XDG_SESSION_EXTRA_DEVICE_ACCESS", NULL);
|
||||
if (extra_device_access) {
|
||||
@@ -1828,6 +1881,11 @@ _public_ PAM_EXTERN int pam_sm_open_session(
|
||||
if (r != PAM_SUCCESS)
|
||||
return r;
|
||||
|
||||
+ if (inhibit_what)
|
||||
+ /* Failure to acquire the inhibit lock is not fatal, session setup should proceed
|
||||
+ * regardless. */
|
||||
+ (void) acquire_inhibit_lock(pamh, inhibit_what, inhibit_why, debug);
|
||||
+
|
||||
r = import_shell_credentials(pamh, debug);
|
||||
if (r != PAM_SUCCESS)
|
||||
return r;
|
||||
@@ -1880,6 +1938,8 @@ _public_ PAM_EXTERN int pam_sm_close_session(
|
||||
|
||||
(void) close_osc_context(pamh, debug);
|
||||
|
||||
+ (void) sym_pam_set_data(pamh, "systemd.inhibit-fd", NULL, NULL);
|
||||
+
|
||||
id = sym_pam_getenv(pamh, "XDG_SESSION_ID");
|
||||
if (id) {
|
||||
_cleanup_(sd_varlink_unrefp) sd_varlink *vl = NULL;
|
||||
|
||||
From 87fa1c28a5f084b5837e58baf5d6a7482c02f382 Mon Sep 17 00:00:00 2001
|
||||
From: Clayton Craft <clayton@craftyguy.net>
|
||||
Date: Sat, 23 May 2026 19:53:56 -0700
|
||||
Subject: [PATCH 3/3] pam_systemd: document inhibit= and inhibit-why= options
|
||||
|
||||
---
|
||||
man/pam_systemd.xml | 47 +++++++++++++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 47 insertions(+)
|
||||
|
||||
diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml
|
||||
index 5482ced067745..bb464556954f0 100644
|
||||
--- a/man/pam_systemd.xml
|
||||
+++ b/man/pam_systemd.xml
|
||||
@@ -238,6 +238,33 @@
|
||||
<xi:include href="version-info.xml" xpointer="v258"/></listitem>
|
||||
</varlistentry>
|
||||
|
||||
+ <varlistentry>
|
||||
+ <term><varname>inhibit=</varname></term>
|
||||
+
|
||||
+ <listitem><para>Takes a colon-separated list of inhibitor lock types to acquire for the duration of
|
||||
+ the session. The <varname>XDG_SESSION_INHIBIT</varname> environment variable (see below) takes
|
||||
+ precedence. Inhibitor locks prevent the system from performing certain actions, such as sleeping.
|
||||
+ The supported lock types are the same as for the
|
||||
+ <citerefentry><refentrytitle>systemd-inhibit</refentrytitle><manvolnum>1</manvolnum></citerefentry>
|
||||
+ command, e.g. <constant>shutdown</constant>, <constant>sleep</constant>, <constant>idle</constant>.
|
||||
+ If not set, no inhibitor lock is acquired. The lock is taken in block mode, the requested
|
||||
+ actions are fully inhibited as long as the session is active.</para>
|
||||
+
|
||||
+ <xi:include href="version-info.xml" xpointer="v262"/></listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
+ <varlistentry>
|
||||
+ <term><varname>inhibit-why=</varname></term>
|
||||
+
|
||||
+ <listitem><para>Takes a short human-readable string describing the reason for the inhibitor lock
|
||||
+ acquired via <varname>inhibit=</varname>. The <varname>XDG_SESSION_INHIBIT_WHY</varname>
|
||||
+ environment variable (see below) takes precedence. Defaults to <literal>Active PAM session</literal>
|
||||
+ if not set. Only has an effect if <varname>inhibit=</varname> or
|
||||
+ <varname>XDG_SESSION_INHIBIT</varname> is set.</para>
|
||||
+
|
||||
+ <xi:include href="version-info.xml" xpointer="v262"/></listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
<varlistentry>
|
||||
<term><varname>default-capability-bounding-set=</varname></term>
|
||||
<term><varname>default-capability-ambient-set=</varname></term>
|
||||
@@ -414,6 +441,25 @@
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v260"/></listitem>
|
||||
</varlistentry>
|
||||
+
|
||||
+ <varlistentry>
|
||||
+ <term><varname>$XDG_SESSION_INHIBIT</varname></term>
|
||||
+
|
||||
+ <listitem><para>The inhibitor lock types to acquire for the duration of the session, as a
|
||||
+ colon-separated list. This may be used instead of <varname>inhibit=</varname> on the module
|
||||
+ parameter line.</para>
|
||||
+
|
||||
+ <xi:include href="version-info.xml" xpointer="v262"/></listitem>
|
||||
+ </varlistentry>
|
||||
+
|
||||
+ <varlistentry>
|
||||
+ <term><varname>$XDG_SESSION_INHIBIT_WHY</varname></term>
|
||||
+
|
||||
+ <listitem><para>The reason string for the inhibitor lock. This may be used instead of
|
||||
+ <varname>inhibit-why=</varname> on the module parameter line.</para>
|
||||
+
|
||||
+ <xi:include href="version-info.xml" xpointer="v262"/></listitem>
|
||||
+ </varlistentry>
|
||||
</variablelist>
|
||||
|
||||
<para>If not set, <command>pam_systemd</command> will initialize
|
||||
@@ -528,6 +574,7 @@ session required pam_unix.so</programlisting>
|
||||
<member><citerefentry><refentrytitle>logind.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>loginctl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>pam_systemd_home</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
+ <member><citerefentry><refentrytitle>systemd-inhibit</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='man-pages'><refentrytitle>pam.conf</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='man-pages'><refentrytitle>pam.d</refentrytitle><manvolnum>5</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='man-pages'><refentrytitle>pam</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
@@ -1,418 +0,0 @@
|
||||
From 98e7cc36f019e48a3f20db9787ccd38d899957f5 Mon Sep 17 00:00:00 2001
|
||||
From: Clayton Craft <clayton@craftyguy.net>
|
||||
Date: Thu, 13 Aug 2026 13:51:30 -0700
|
||||
Subject: [PATCH 1/4] timesyncd: resolve NTP hostnames through resolved's
|
||||
varlink interface
|
||||
|
||||
With DNSSEC on, resolved can't validate anything until the clock is
|
||||
right, and without an RTC the only thing that fixes the clock is talking
|
||||
to the NTP servers we're trying to resolve. On glibc the timesyncd unit
|
||||
sets SYSTEMD_NSS_RESOLVE_VALIDATE=0 and nss-resolve turns that into a
|
||||
per-query flag, which breaks the chicken/egg. musl (and other systems
|
||||
not using nss-resolve) have no NSS, so nothing reads it there and we're
|
||||
stuck.
|
||||
|
||||
So talk to resolved directly when it's there, and pass
|
||||
SD_RESOLVED_NO_VALIDATE until we've synced the clock ourselves.
|
||||
NTP-related lookups after that are validated normally, which is better
|
||||
than what we get from nss. If resolved isn't around we just keep using
|
||||
getaddrinfo().
|
||||
|
||||
The reply handler duplicates the tail of the getaddrinfo handler, since
|
||||
the two differ in how they report failures. Varlink discards what the
|
||||
callback returns, so it has to move on to the next host itself.
|
||||
|
||||
This also drops SYSTEMD_NSS_RESOLVE_VALIDATE=0 from the unit because
|
||||
nss-resolve talks to resolved over the same socket we do, so the
|
||||
getaddrinfo() path is only ever taken when resolved is unreachable, and
|
||||
then nothing validates anyway.
|
||||
---
|
||||
src/timesync/timesyncd-manager.c | 136 +++++++++++++++++++++++++++--
|
||||
src/timesync/timesyncd-manager.h | 1 +
|
||||
units/systemd-timesyncd.service.in | 4 -
|
||||
3 files changed, 132 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
|
||||
index b0f22516dfe3..7b2ed4f831a0 100644
|
||||
--- a/src/timesync/timesyncd-manager.c
|
||||
+++ b/src/timesync/timesyncd-manager.c
|
||||
@@ -10,8 +10,10 @@
|
||||
|
||||
#include "sd-bus.h"
|
||||
#include "sd-daemon.h"
|
||||
+#include "sd-json.h"
|
||||
#include "sd-messages.h"
|
||||
#include "sd-network.h"
|
||||
+#include "sd-varlink.h"
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "clock-util.h"
|
||||
@@ -23,6 +25,7 @@
|
||||
#include "format-util.h"
|
||||
#include "fs-util.h"
|
||||
#include "hashmap.h"
|
||||
+#include "in-addr-util.h"
|
||||
#include "list.h"
|
||||
#include "log.h"
|
||||
#include "logarithm.h"
|
||||
@@ -30,6 +33,8 @@
|
||||
#include "random-util.h"
|
||||
#include "ratelimit.h"
|
||||
#include "resolve-private.h"
|
||||
+#include "resolve-varlink-util.h"
|
||||
+#include "resolved-def.h"
|
||||
#include "socket-util.h"
|
||||
#include "string-util.h"
|
||||
#include "strv.h"
|
||||
@@ -780,6 +785,119 @@ static int manager_resolve_handler(sd_resolve_query *q, int ret, const struct ad
|
||||
return manager_begin(m);
|
||||
}
|
||||
|
||||
+static int manager_resolve_varlink_reply(
|
||||
+ sd_varlink *link,
|
||||
+ sd_json_variant *parameters,
|
||||
+ const char *error_id,
|
||||
+ sd_varlink_reply_flags_t flags,
|
||||
+ void *userdata) {
|
||||
+
|
||||
+ Manager *m = ASSERT_PTR(userdata);
|
||||
+ int r;
|
||||
+
|
||||
+ assert(m->current_server_name);
|
||||
+
|
||||
+ _unused_ _cleanup_(sd_varlink_unrefp) sd_varlink *link_free = TAKE_PTR(m->resolve_varlink);
|
||||
+
|
||||
+ if (!isempty(error_id)) {
|
||||
+ log_debug("Failed to resolve %s: %s", m->current_server_name->string, error_id);
|
||||
+
|
||||
+ /* Try next one */
|
||||
+ return manager_connect(m);
|
||||
+ }
|
||||
+
|
||||
+ _cleanup_(resolve_hostname_reply_done) ResolveHostnameReply reply = {};
|
||||
+ r = dispatch_resolve_hostname_reply(/* name = */ NULL, parameters, SD_JSON_LOG, &reply);
|
||||
+ if (r < 0) {
|
||||
+ log_warning_errno(r, "Failed to parse reply for %s, ignoring: %m", m->current_server_name->string);
|
||||
+
|
||||
+ return manager_connect(m);
|
||||
+ }
|
||||
+
|
||||
+ FOREACH_ARRAY(entry, reply.addresses, reply.n_addresses) {
|
||||
+ _cleanup_free_ char *pretty = NULL;
|
||||
+ union sockaddr_union sa = {};
|
||||
+ ServerAddress *a;
|
||||
+
|
||||
+ if (!IN_SET(entry->family, AF_INET, AF_INET6)) {
|
||||
+ log_debug("Ignoring unsuitable address protocol for %s.", m->current_server_name->string);
|
||||
+ continue;
|
||||
+ }
|
||||
+
|
||||
+ r = sockaddr_set_in_addr(&sa, entry->family, &entry->in_addr.address, 123);
|
||||
+ if (r < 0) {
|
||||
+ log_warning_errno(r, "Failed to convert address for %s, trying next host: %m", m->current_server_name->string);
|
||||
+ return manager_connect(m);
|
||||
+ }
|
||||
+
|
||||
+ /* Only link-local addresses need a scope, setting it on a global one pins us to one interface. */
|
||||
+ if (entry->family == AF_INET6 && in6_addr_is_link_local(&entry->in_addr.address.in6))
|
||||
+ sa.in6.sin6_scope_id = entry->ifindex;
|
||||
+
|
||||
+ r = server_address_new(m->current_server_name, &a, &sa, sockaddr_len(&sa));
|
||||
+ if (r < 0) {
|
||||
+ log_warning_errno(r, "Failed to add server address, trying next host: %m");
|
||||
+ return manager_connect(m);
|
||||
+ }
|
||||
+
|
||||
+ (void) server_address_pretty(a, &pretty);
|
||||
+ log_debug("Resolved address %s for %s.", strna(pretty), m->current_server_name->string);
|
||||
+ }
|
||||
+
|
||||
+ if (!m->current_server_name->addresses) {
|
||||
+ log_error("Failed to find suitable address for host %s.", m->current_server_name->string);
|
||||
+
|
||||
+ /* Try next host */
|
||||
+ return manager_connect(m);
|
||||
+ }
|
||||
+
|
||||
+ manager_set_server_address(m, m->current_server_name->addresses);
|
||||
+
|
||||
+ return manager_begin(m);
|
||||
+}
|
||||
+
|
||||
+/* Resolve the current server name through resolved's Varlink interface. This returns 0 if resolved is
|
||||
+ * unavailable */
|
||||
+static int manager_resolve_varlink(Manager *m) {
|
||||
+ _cleanup_(sd_varlink_close_unrefp) sd_varlink *link = NULL;
|
||||
+ int r;
|
||||
+
|
||||
+ assert(m);
|
||||
+ assert(m->current_server_name);
|
||||
+
|
||||
+ r = sd_varlink_connect_address(&link, "/run/systemd/resolve/io.systemd.Resolve");
|
||||
+ if (r < 0) {
|
||||
+ log_debug_errno(r, "Failed to connect to systemd-resolved, using getaddrinfo(): %m");
|
||||
+ return 0;
|
||||
+ }
|
||||
+
|
||||
+ (void) sd_varlink_set_description(link, "timesyncd-resolve");
|
||||
+ (void) sd_varlink_set_relative_timeout(link, SD_RESOLVED_QUERY_TIMEOUT_USEC);
|
||||
+
|
||||
+ r = sd_varlink_attach_event(link, m->event, SD_EVENT_PRIORITY_NORMAL);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to attach Varlink connection to event loop: %m");
|
||||
+
|
||||
+ r = sd_varlink_bind_reply(link, manager_resolve_varlink_reply);
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to bind Varlink reply callback: %m");
|
||||
+
|
||||
+ sd_varlink_set_userdata(link, m);
|
||||
+
|
||||
+ /* Ask resolved to skip DNSSEC validation as long as our clock is not synchronized yet. */
|
||||
+ r = sd_varlink_invokebo(
|
||||
+ link,
|
||||
+ "io.systemd.Resolve.ResolveHostname",
|
||||
+ SD_JSON_BUILD_PAIR_STRING("name", m->current_server_name->string),
|
||||
+ SD_JSON_BUILD_PAIR_CONDITION(!socket_ipv6_is_enabled(), "family", SD_JSON_BUILD_INTEGER(AF_INET)),
|
||||
+ SD_JSON_BUILD_PAIR_UNSIGNED("flags", m->synchronized ? 0 : SD_RESOLVED_NO_VALIDATE));
|
||||
+ if (r < 0)
|
||||
+ return log_error_errno(r, "Failed to call ResolveHostname(): %m");
|
||||
+
|
||||
+ m->resolve_varlink = TAKE_PTR(link);
|
||||
+ return 1;
|
||||
+}
|
||||
+
|
||||
static int manager_retry_connect(sd_event_source *source, usec_t usec, void *userdata) {
|
||||
Manager *m = ASSERT_PTR(userdata);
|
||||
|
||||
@@ -868,15 +986,22 @@ int manager_connect(Manager *m) {
|
||||
manager_set_server_name(m, f);
|
||||
}
|
||||
|
||||
- /* Tell the resolver to reread /etc/resolv.conf, in
|
||||
- * case it changed. */
|
||||
- res_init();
|
||||
-
|
||||
/* Flush out any previously resolved addresses */
|
||||
server_name_flush_addresses(m->current_server_name);
|
||||
|
||||
log_debug("Resolving %s...", m->current_server_name->string);
|
||||
|
||||
+ /* Prefer resolved's varlink interface. If that's unavailable, then fall through to getaddrinfo below. */
|
||||
+ r = manager_resolve_varlink(m);
|
||||
+ if (r < 0)
|
||||
+ return r;
|
||||
+ if (r > 0)
|
||||
+ return 1;
|
||||
+
|
||||
+ /* Tell the resolver to reread /etc/resolv.conf, in
|
||||
+ * case it changed. */
|
||||
+ res_init();
|
||||
+
|
||||
struct addrinfo hints = {
|
||||
.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG,
|
||||
.ai_socktype = SOCK_DGRAM,
|
||||
@@ -901,6 +1026,7 @@ void manager_disconnect(Manager *m) {
|
||||
assert(m);
|
||||
|
||||
m->resolve_query = sd_resolve_query_unref(m->resolve_query);
|
||||
+ m->resolve_varlink = sd_varlink_close_unref(m->resolve_varlink);
|
||||
|
||||
m->event_timer = sd_event_source_unref(m->event_timer);
|
||||
|
||||
@@ -1035,7 +1161,7 @@ static bool manager_is_connected(Manager *m) {
|
||||
|
||||
/* Return true when the manager is sending a request, resolving a server name, or
|
||||
* in a poll interval. */
|
||||
- return m->server_socket >= 0 || m->resolve_query || m->event_timer;
|
||||
+ return m->server_socket >= 0 || m->resolve_query || m->resolve_varlink || m->event_timer;
|
||||
}
|
||||
|
||||
static int manager_network_event_handler(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
|
||||
diff --git a/src/timesync/timesyncd-manager.h b/src/timesync/timesyncd-manager.h
|
||||
index 9966b64ac697..8c1e30f48fd5 100644
|
||||
--- a/src/timesync/timesyncd-manager.h
|
||||
+++ b/src/timesync/timesyncd-manager.h
|
||||
@@ -41,6 +41,7 @@ typedef struct Manager {
|
||||
|
||||
/* peer */
|
||||
sd_resolve_query *resolve_query;
|
||||
+ sd_varlink *resolve_varlink;
|
||||
sd_event_source *event_receive;
|
||||
ServerName *current_server_name;
|
||||
ServerAddress *current_server_address;
|
||||
diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in
|
||||
index 560bcee92f4c..bc64e2414007 100644
|
||||
--- a/units/systemd-timesyncd.service.in
|
||||
+++ b/units/systemd-timesyncd.service.in
|
||||
@@ -22,10 +22,6 @@ Wants=time-set.target
|
||||
AmbientCapabilities=CAP_SYS_TIME
|
||||
BusName=org.freedesktop.timesync1
|
||||
CapabilityBoundingSet=CAP_SYS_TIME
|
||||
-# Turn off DNSSEC validation for hostname look-ups, since those need the
|
||||
-# correct time to work, but we likely won't acquire that without NTP. Let's
|
||||
-# break this chicken-and-egg cycle here.
|
||||
-Environment=SYSTEMD_NSS_RESOLVE_VALIDATE=0
|
||||
ExecStart={{LIBEXECDIR}}/systemd-timesyncd
|
||||
LockPersonality=yes
|
||||
MemoryDenyWriteExecute=yes
|
||||
|
||||
From 6279910be7b26239ce7eb442b227a879cb66e24e Mon Sep 17 00:00:00 2001
|
||||
From: Clayton Craft <clayton@craftyguy.net>
|
||||
Date: Thu, 13 Aug 2026 14:01:59 -0700
|
||||
Subject: [PATCH 2/4] timesyncd: order after systemd-resolved
|
||||
|
||||
Our first resolve happens way before sockets.target, and
|
||||
systemd-resolved-varlink.socket has no ordering of its own, so there's
|
||||
nothing making sure the socket is listening by then. Without this the
|
||||
connect fails and we quietly fall back to getaddrinfo(), which is exactly
|
||||
the case the varlink path is there for.
|
||||
|
||||
Order after both the service and the socket since either one is enough
|
||||
on its own but neither covers every install situation. For example
|
||||
resolved binds the socket itself when nothing hands it one, and on
|
||||
systems where only the socket is enabled the service isn't started at
|
||||
boot at all.
|
||||
---
|
||||
units/systemd-timesyncd.service.in | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/units/systemd-timesyncd.service.in b/units/systemd-timesyncd.service.in
|
||||
index bc64e2414007..c1809710477b 100644
|
||||
--- a/units/systemd-timesyncd.service.in
|
||||
+++ b/units/systemd-timesyncd.service.in
|
||||
@@ -13,7 +13,7 @@ Documentation=man:systemd-timesyncd.service(8)
|
||||
ConditionCapability=CAP_SYS_TIME
|
||||
ConditionVirtualization=!container
|
||||
DefaultDependencies=no
|
||||
-After=systemd-sysusers.service
|
||||
+After=systemd-sysusers.service systemd-resolved.service systemd-resolved-varlink.socket
|
||||
Before=time-set.target sysinit.target shutdown.target
|
||||
Conflicts=shutdown.target
|
||||
Wants=time-set.target
|
||||
|
||||
From 8027ff6ecd12058d08e0bb6dce046b86828f7dd4 Mon Sep 17 00:00:00 2001
|
||||
From: Clayton Craft <clayton@craftyguy.net>
|
||||
Date: Fri, 14 Aug 2026 15:19:56 -0700
|
||||
Subject: [PATCH 3/4] timesyncd: don't ask for AAAA when IPv6 is disabled
|
||||
|
||||
ipv6_is_supported only tells us the kernel has IPv6, not that
|
||||
it's usable. ipv6_is_enabled also checks the sysctl that turns
|
||||
it off, so we stop resolving addresses we can't use.
|
||||
---
|
||||
src/timesync/timesyncd-manager.c | 2 +-
|
||||
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||
|
||||
diff --git a/src/timesync/timesyncd-manager.c b/src/timesync/timesyncd-manager.c
|
||||
index 7b2ed4f831a0..4b3978bebc7f 100644
|
||||
--- a/src/timesync/timesyncd-manager.c
|
||||
+++ b/src/timesync/timesyncd-manager.c
|
||||
@@ -1005,7 +1005,7 @@ int manager_connect(Manager *m) {
|
||||
struct addrinfo hints = {
|
||||
.ai_flags = AI_NUMERICSERV|AI_ADDRCONFIG,
|
||||
.ai_socktype = SOCK_DGRAM,
|
||||
- .ai_family = socket_ipv6_is_supported() ? AF_UNSPEC : AF_INET,
|
||||
+ .ai_family = socket_ipv6_is_enabled() ? AF_UNSPEC : AF_INET,
|
||||
};
|
||||
|
||||
r = resolve_getaddrinfo(m->resolve, &m->resolve_query, m->current_server_name->string, "123", &hints, manager_resolve_handler, NULL, m);
|
||||
|
||||
From d52a6931643a384b1184b1c30badb739ff885f78 Mon Sep 17 00:00:00 2001
|
||||
From: Clayton Craft <clayton@craftyguy.net>
|
||||
Date: Fri, 14 Aug 2026 14:25:01 -0700
|
||||
Subject: [PATCH 4/4] test: cover both of timesyncd's resolver paths
|
||||
|
||||
This checks that we resolve through resolved when it's running, and fall back
|
||||
to getaddrinfo when it isn't.
|
||||
---
|
||||
test/units/TEST-45-TIMEDATE.sh | 71 ++++++++++++++++++++++++++++++++++
|
||||
1 file changed, 71 insertions(+)
|
||||
|
||||
diff --git a/test/units/TEST-45-TIMEDATE.sh b/test/units/TEST-45-TIMEDATE.sh
|
||||
index 820c3ae9f52e..0af99fc96ce7 100755
|
||||
--- a/test/units/TEST-45-TIMEDATE.sh
|
||||
+++ b/test/units/TEST-45-TIMEDATE.sh
|
||||
@@ -248,6 +248,19 @@ assert_timesyncd_state() {
|
||||
return 1
|
||||
}
|
||||
|
||||
+assert_timesyncd_log() {
|
||||
+ local cursor="${1:?}"
|
||||
+ local match="${2:?}"
|
||||
+
|
||||
+ for _ in {0..29}; do
|
||||
+ journalctl --sync
|
||||
+ journalctl -q -u systemd-timesyncd.service --after-cursor="$(<"$cursor")" --grep "$match" >/dev/null && return 0
|
||||
+ sleep .5
|
||||
+ done
|
||||
+
|
||||
+ return 1
|
||||
+}
|
||||
+
|
||||
testcase_ntp() {
|
||||
# timesyncd has ConditionVirtualization=!container by default; drop/mock that for testing
|
||||
if systemd-detect-virt --container --quiet; then
|
||||
@@ -409,6 +422,64 @@ EOF
|
||||
rm -f /run/systemd/network/ntp99.*
|
||||
}
|
||||
|
||||
+teardown_timesyncd_resolve() {
|
||||
+ set +eu
|
||||
+
|
||||
+ systemctl start systemd-resolved-varlink.socket
|
||||
+ systemctl start systemd-resolved.service
|
||||
+
|
||||
+ rm -rf /run/systemd/system/systemd-timesyncd.service.d
|
||||
+ systemctl daemon-reload
|
||||
+ systemctl stop systemd-timesyncd
|
||||
+}
|
||||
+
|
||||
+testcase_timesyncd_resolve() {
|
||||
+ local cursor
|
||||
+
|
||||
+ if systemd-detect-virt -cq; then
|
||||
+ echo "This test case requires a VM, skipping..."
|
||||
+ return 0
|
||||
+ fi
|
||||
+
|
||||
+ if ! command -v resolvectl >/dev/null; then
|
||||
+ echo "This test requires systemd-resolved, skipping..."
|
||||
+ return 0
|
||||
+ fi
|
||||
+
|
||||
+ trap teardown_timesyncd_resolve RETURN
|
||||
+
|
||||
+ mkdir -p /run/systemd/system/systemd-timesyncd.service.d
|
||||
+ cat >/run/systemd/system/systemd-timesyncd.service.d/10-debug.conf <<EOF
|
||||
+[Service]
|
||||
+Environment=SYSTEMD_LOG_LEVEL=debug
|
||||
+EOF
|
||||
+ systemctl daemon-reload
|
||||
+
|
||||
+ systemctl unmask systemd-resolved
|
||||
+ systemctl unmask systemd-timesyncd
|
||||
+ systemctl start systemd-resolved-varlink.socket
|
||||
+ systemctl start systemd-resolved.service
|
||||
+ systemctl restart systemd-timesyncd
|
||||
+
|
||||
+ cursor="$(mktemp)"
|
||||
+
|
||||
+ # Should use resolved for resolving names
|
||||
+ journalctl -n0 -q --cursor-file="$cursor"
|
||||
+ busctl call org.freedesktop.timesync1 /org/freedesktop/timesync1 org.freedesktop.timesync1.Manager \
|
||||
+ SetRuntimeNTPServers as 1 foo.localhost
|
||||
+ # Only the varlink path logs this, so it tells us which resolver ran
|
||||
+ assert_timesyncd_log "$cursor" "io.systemd.Resolve.ResolveHostname"
|
||||
+
|
||||
+ # Without resolved, it should fall back to getaddrinfo
|
||||
+ systemctl stop systemd-resolved-varlink.socket systemd-resolved-monitor.socket
|
||||
+ systemctl stop systemd-resolved.service
|
||||
+
|
||||
+ journalctl -n0 -q --cursor-file="$cursor"
|
||||
+ busctl call org.freedesktop.timesync1 /org/freedesktop/timesync1 org.freedesktop.timesync1.Manager \
|
||||
+ SetRuntimeNTPServers as 1 foo.localhost
|
||||
+ assert_timesyncd_log "$cursor" "Failed to connect to systemd-resolved, using getaddrinfo"
|
||||
+}
|
||||
+
|
||||
teardown_timedated_alternate_paths() {
|
||||
set +eu
|
||||
|
||||
@@ -14,10 +14,10 @@
|
||||
|
||||
maintainer="Clayton Craft <craftyguy@postmarketos.org>"
|
||||
pkgname=systemd
|
||||
pkgver=261.2
|
||||
pkgver=262_rc1
|
||||
_pkgver="${pkgver/_/-}"
|
||||
# pkgrel must match systemd-stage0!
|
||||
pkgrel=1
|
||||
pkgrel=0
|
||||
pkgdesc="System and service manager"
|
||||
url="https://github.com/systemd/systemd"
|
||||
# armhf: no linux-stable
|
||||
@@ -44,7 +44,7 @@ triggers="$pkgname.trigger=/usr/lib/systemd/catalog:\
|
||||
/etc/systemd/system:\
|
||||
/etc/systemd/user
|
||||
"
|
||||
checkdepends="grep postmarketos-release"
|
||||
checkdepends="cpio grep postmarketos-release"
|
||||
# clang: used for bpf compilation. this is the default compiler
|
||||
# grep: test-kernel-install requires 'grep -G', which is not supported by BusyBox grep.
|
||||
makedepends="
|
||||
@@ -227,11 +227,6 @@ fi
|
||||
source="
|
||||
$pkgname-$pkgver.tar.gz::https://github.com/systemd/systemd/archive/refs/tags/v$_pkgver.tar.gz
|
||||
wired.network
|
||||
42275.patch
|
||||
43380.patch
|
||||
0001-json-util-generalize-json_dispatch_address_family.patch
|
||||
0001-json-util-introduce-json_dispatch_in_addr_data.patch
|
||||
0001-resolvectl-use-varlink-instead-of-dbus-for-ResolveHo.patch
|
||||
"
|
||||
builddir=${_upstream_srcdir:-"$srcdir/$pkgname-$_pkgver"}
|
||||
_meson_builddir=${_meson_builddir:-build}
|
||||
@@ -644,11 +639,6 @@ _resolve_packages() {
|
||||
|
||||
|
||||
sha512sums="
|
||||
876f043970cb65b39ae15fba39f23bf94c7c3d80569503d6e8ea2c8013c30ee40ce43cb55cbcb1cf14d5c3021aafc09c0f67473bbf742d8964bf9fa30693b971 systemd-261.2.tar.gz
|
||||
5bd4ed38246de1ea17b46fcc6f921f94a53047cec4dc53b005afd4ca75cd50d631b92c6662204871ad2c0808694244ec15d90732b1251d15bf5f9d74b6a2a7f0 systemd-262_rc1.tar.gz
|
||||
81c897fed8a3fbfb67ec591b2398a5d65e4af1b3ef379376c157c98d71f085b707f8ebc896d5571a94f99f8fc84fd6b43e3b879ca9b0d57fc6c4596034c7a777 wired.network
|
||||
3e01f711f68e565f37e590e10f55ce9dfd371cc1f8d124f3a0fad47747449d92053d9701216eac96bb6203cf952a22dc8215bc9dff74c1866ce9a07f1cb84b3c 42275.patch
|
||||
2991d3c38e7f78715970a964ece27c56c591e6e1daab5d41772c86023c3d66a07a4f89c22619a1da6422ff5447a8aee906c7862aeb4788274b66c807313ddbf1 43380.patch
|
||||
ce7f4aa7a490da7e469f2e09fac4128d2dbab69a3c0c1384ec85c46a8b9f1d5074b75462f08ac60d4a09fb8cdea36d22850d634c8f7db434632497f47bae142f 0001-json-util-generalize-json_dispatch_address_family.patch
|
||||
1267f3a25d9a242ed9a3027aeacb2b6adb38864ca316215c7db2edee8f8c66d2448f58c1754e3f08be1ba70cf68b3cc503aec67d170de64a378c09f18260e32b 0001-json-util-introduce-json_dispatch_in_addr_data.patch
|
||||
8d9436dc5c150c9b8c3b1b19512fbea5fa1f0953a4261f4fb089a90878768156db5d47feb41450594bd9547d40ef14c50ca751c5a046cdd253bb5b72cf1fd54c 0001-resolvectl-use-varlink-instead-of-dbus-for-ResolveHo.patch
|
||||
"
|
||||
|
||||
Reference in New Issue
Block a user