]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: implement DBus methods to set DNS related properties
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sun, 26 May 2019 23:52:27 +0000 (08:52 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 16 Jul 2019 21:59:12 +0000 (06:59 +0900)
src/network/meson.build
src/network/networkd-link-bus.c
src/network/networkd-link-bus.h
src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-manager-bus.c
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/org.freedesktop.network1.conf
src/network/org.freedesktop.network1.policy [new file with mode: 0644]

index 387cf0a0b7633916d381aa85752e8884931187bd..6bed37a1704c7d3c75f447d48b18b58d5e7f4997 100644 (file)
@@ -156,6 +156,8 @@ if conf.get('ENABLE_NETWORKD') == 1
                      install_dir : dbuspolicydir)
         install_data('org.freedesktop.network1.service',
                      install_dir : dbussystemservicedir)
+        install_data('org.freedesktop.network1.policy',
+                     install_dir : polkitpolicydir)
         if install_polkit
                 install_data('systemd-networkd.rules',
                              install_dir : polkitrulesdir)
index eda0325c2b94ff2c2560e2e52185fc874d5a1f14..03552725ed3663710cdf31a74a8a490d33fb3919 100644 (file)
@@ -1,13 +1,20 @@
 /* SPDX-License-Identifier: LGPL-2.1+ */
 
+#include <net/if.h>
+#include <netinet/in.h>
+#include <sys/capability.h>
+
 #include "alloc-util.h"
 #include "bus-common-errors.h"
 #include "bus-util.h"
+#include "dns-domain.h"
 #include "networkd-link-bus.h"
 #include "networkd-link.h"
 #include "networkd-manager.h"
 #include "parse-util.h"
+#include "resolve-util.h"
 #include "strv.h"
+#include "user-util.h"
 
 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_carrier_state, link_carrier_state, LinkCarrierState);
@@ -59,6 +66,515 @@ static int property_get_bit_rates(
         return sd_bus_message_append(reply, "(tt)", tx, rx);
 }
 
+static int verify_managed_link(Link *l, sd_bus_error *error) {
+        assert(l);
+
+        if (l->flags & IFF_LOOPBACK)
+                return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->ifname);
+
+        return 0;
+}
+
+int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_strv_free_ char **ntp = NULL;
+        Link *l = userdata;
+        int r;
+        char **i;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_strv(message, &ntp);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, ntp) {
+                r = dns_name_is_valid_or_address(*i);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NTP server: %s", *i);
+        }
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.set-ntp-servers",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        strv_free_and_replace(l->ntp, ntp);
+
+        (void) link_dirty(l);
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_free_ struct in_addr_data *dns = NULL;
+        size_t allocated = 0, n = 0;
+        Link *l = userdata;
+        int r;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_enter_container(message, 'a', "(iay)");
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                int family;
+                size_t sz;
+                const void *d;
+
+                assert_cc(sizeof(int) == sizeof(int32_t));
+
+                r = sd_bus_message_enter_container(message, 'r', "iay");
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                r = sd_bus_message_read(message, "i", &family);
+                if (r < 0)
+                        return r;
+
+                if (!IN_SET(family, AF_INET, AF_INET6))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown address family %i", family);
+
+                r = sd_bus_message_read_array(message, 'y', &d, &sz);
+                if (r < 0)
+                        return r;
+                if (sz != FAMILY_ADDRESS_SIZE(family))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid address size");
+
+                if (!dns_server_address_valid(family, d))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNS server address");
+
+                r = sd_bus_message_exit_container(message);
+                if (r < 0)
+                        return r;
+
+                if (!GREEDY_REALLOC(dns, allocated, n+1))
+                        return -ENOMEM;
+
+                dns[n].family = family;
+                memcpy(&dns[n].address, d, sz);
+                n++;
+        }
+
+        r = sd_bus_message_exit_container(message);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.set-dns-servers",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        free_and_replace(l->dns, dns);
+        l->n_dns = n;
+
+        (void) link_dirty(l);
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_(ordered_set_freep) OrderedSet *search_domains = NULL, *route_domains = NULL;
+        Link *l = userdata;
+        int r;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_enter_container(message, 'a', "(sb)");
+        if (r < 0)
+                return r;
+
+        for (;;) {
+                _cleanup_free_ char *str = NULL;
+                OrderedSet **domains;
+                const char *name;
+                int route_only;
+
+                r = sd_bus_message_read(message, "(sb)", &name, &route_only);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                r = dns_name_is_valid(name);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
+                if (!route_only && dns_name_is_root(name))
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
+
+                r = dns_name_normalize(name, 0, &str);
+                if (r < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
+
+                domains = route_only ? &route_domains : &search_domains;
+                r = ordered_set_ensure_allocated(domains, &string_hash_ops);
+                if (r < 0)
+                        return r;
+
+                r = ordered_set_put(*domains, str);
+                if (r < 0)
+                        return r;
+
+                TAKE_PTR(str);
+        }
+
+        r = sd_bus_message_exit_container(message);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.set-domains",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        ordered_set_free_free(l->search_domains);
+        ordered_set_free_free(l->route_domains);
+        l->search_domains = TAKE_PTR(search_domains);
+        l->route_domains = TAKE_PTR(route_domains);
+
+        (void) link_dirty(l);
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Link *l = userdata;
+        int r, b;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(message, "b", &b);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.set-default-route",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        if (l->dns_default_route != b) {
+                l->dns_default_route = b;
+                (void) link_dirty(l);
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Link *l = userdata;
+        ResolveSupport mode;
+        const char *llmnr;
+        int r;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(message, "s", &llmnr);
+        if (r < 0)
+                return r;
+
+        if (isempty(llmnr))
+                mode = RESOLVE_SUPPORT_YES;
+        else {
+                mode = resolve_support_from_string(llmnr);
+                if (mode < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
+        }
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.set-llmnr",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        if (l->llmnr != mode) {
+                l->llmnr = mode;
+                (void) link_dirty(l);
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Link *l = userdata;
+        ResolveSupport mode;
+        const char *mdns;
+        int r;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(message, "s", &mdns);
+        if (r < 0)
+                return r;
+
+        if (isempty(mdns))
+                mode = RESOLVE_SUPPORT_NO;
+        else {
+                mode = resolve_support_from_string(mdns);
+                if (mode < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
+        }
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.set-mdns",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        if (l->mdns != mode) {
+                l->mdns = mode;
+                (void) link_dirty(l);
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Link *l = userdata;
+        const char *dns_over_tls;
+        DnsOverTlsMode mode;
+        int r;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(message, "s", &dns_over_tls);
+        if (r < 0)
+                return r;
+
+        if (isempty(dns_over_tls))
+                mode = _DNS_OVER_TLS_MODE_INVALID;
+        else {
+                mode = dns_over_tls_mode_from_string(dns_over_tls);
+                if (mode < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSOverTLS setting: %s", dns_over_tls);
+        }
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.set-dns-over-tls",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        if (l->dns_over_tls_mode != mode) {
+                l->dns_over_tls_mode = mode;
+                (void) link_dirty(l);
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Link *l = userdata;
+        const char *dnssec;
+        DnssecMode mode;
+        int r;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read(message, "s", &dnssec);
+        if (r < 0)
+                return r;
+
+        if (isempty(dnssec))
+                mode = _DNSSEC_MODE_INVALID;
+        else {
+                mode = dnssec_mode_from_string(dnssec);
+                if (mode < 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
+        }
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.set-dnssec",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        if (l->dnssec_mode != mode) {
+                l->dnssec_mode = mode;
+                (void) link_dirty(l);
+        }
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        _cleanup_set_free_free_ Set *ns = NULL;
+        _cleanup_strv_free_ char **ntas = NULL;
+        Link *l = userdata;
+        int r;
+        char **i;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = sd_bus_message_read_strv(message, &ntas);
+        if (r < 0)
+                return r;
+
+        STRV_FOREACH(i, ntas) {
+                r = dns_name_is_valid(*i);
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
+        }
+
+        ns = set_new(&dns_name_hash_ops);
+        if (!ns)
+                return -ENOMEM;
+
+        STRV_FOREACH(i, ntas) {
+                r = set_put_strdup(ns, *i);
+                if (r < 0)
+                        return r;
+        }
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.set-dnssec-negative-trust-anchors",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        set_free_free(l->dnssec_negative_trust_anchors);
+        l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
+
+        (void) link_dirty(l);
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Link *l = userdata;
+        int r;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.revert-ntp",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        link_ntp_settings_clear(l);
+        (void) link_dirty(l);
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
+int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        Link *l = userdata;
+        int r;
+
+        assert(message);
+        assert(l);
+
+        r = verify_managed_link(l, error);
+        if (r < 0)
+                return r;
+
+        r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
+                                    "org.freedesktop.network1.revert-dns",
+                                    NULL, true, UID_INVALID,
+                                    &l->manager->polkit_registry, error);
+        if (r < 0)
+                return r;
+        if (r == 0)
+                return 1; /* Polkit will call us back */
+
+        link_dns_settings_clear(l);
+        (void) link_dirty(l);
+
+        return sd_bus_reply_method_return(message, NULL);
+}
+
 const sd_bus_vtable link_vtable[] = {
         SD_BUS_VTABLE_START(0),
 
@@ -68,6 +584,18 @@ const sd_bus_vtable link_vtable[] = {
         SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
         SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0),
 
+        SD_BUS_METHOD("SetNTP", "as", NULL, bus_link_method_set_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetDNS", "a(iay)", NULL, bus_link_method_set_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetDomains", "a(sb)", NULL, bus_link_method_set_domains, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetDefaultRoute", "b", NULL, bus_link_method_set_default_route, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLLMNR", "s", NULL, bus_link_method_set_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetMulticastDNS", "s", NULL, bus_link_method_set_mdns, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetDNSOverTLS", "s", NULL, bus_link_method_set_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetDNSSEC", "s", NULL, bus_link_method_set_dnssec, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetDNSSECNegativeTrustAnchors", "as", NULL, bus_link_method_set_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("RevertNTP", NULL, NULL, bus_link_method_revert_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("RevertDNS", NULL, NULL, bus_link_method_revert_dns, SD_BUS_VTABLE_UNPRIVILEGED),
+
         SD_BUS_VTABLE_END
 };
 
index 58005a4bbe6aa4d1d44867318118b9bd70db411d..2a653f5058ae00af463cf643d0c03ed10517cf20 100644 (file)
@@ -18,3 +18,15 @@ int link_send_changed(Link *link, const char *property, ...) _sentinel_;
 int property_get_operational_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
 int property_get_carrier_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
 int property_get_address_state(sd_bus *bus, const char *path, const char *interface, const char *property, sd_bus_message *reply, void *userdata, sd_bus_error *error);
+
+int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error);
+int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error);
index 46830290c6391debdfb44f3dd004fac51bb3635f..a08ad80f15aa9ce652bf580e4897ba80fb85e1be 100644 (file)
@@ -609,6 +609,13 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
                 .ifindex = ifindex,
                 .iftype = iftype,
                 .sysctl_ipv6_enabled = -1,
+
+                .n_dns = (unsigned) -1,
+                .dns_default_route = -1,
+                .llmnr = _RESOLVE_SUPPORT_INVALID,
+                .mdns = _RESOLVE_SUPPORT_INVALID,
+                .dnssec_mode = _DNSSEC_MODE_INVALID,
+                .dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID,
         };
 
         link->ifname = strdup(ifname);
@@ -655,11 +662,34 @@ static int link_new(Manager *manager, sd_netlink_message *message, Link **ret) {
         return 0;
 }
 
+void link_ntp_settings_clear(Link *link) {
+        link->ntp = strv_free(link->ntp);
+}
+
+void link_dns_settings_clear(Link *link) {
+        link->dns = mfree(link->dns);
+        link->n_dns = (unsigned) -1;
+
+        link->search_domains = ordered_set_free_free(link->search_domains);
+        link->route_domains = ordered_set_free_free(link->route_domains);
+
+        link->dns_default_route = -1;
+        link->llmnr = _RESOLVE_SUPPORT_INVALID;
+        link->mdns = _RESOLVE_SUPPORT_INVALID;
+        link->dnssec_mode = _DNSSEC_MODE_INVALID;
+        link->dns_over_tls_mode = _DNS_OVER_TLS_MODE_INVALID;
+
+        link->dnssec_negative_trust_anchors = set_free_free(link->dnssec_negative_trust_anchors);
+}
+
 static Link *link_free(Link *link) {
         Address *address;
 
         assert(link);
 
+        link_ntp_settings_clear(link);
+        link_dns_settings_clear(link);
+
         link->routes = set_free_with_destructor(link->routes, route_free);
         link->routes_foreign = set_free_with_destructor(link->routes_foreign, route_free);
 
@@ -3386,6 +3416,26 @@ static void print_link_hashmap(FILE *f, const char *prefix, Hashmap* h) {
         fputc('\n', f);
 }
 
+static void link_save_dns(FILE *f, struct in_addr_data *dns, unsigned n_dns, bool *space) {
+        unsigned j;
+        int r;
+
+        for (j = 0; j < n_dns; j++) {
+                _cleanup_free_ char *b = NULL;
+
+                r = in_addr_to_string(dns[j].family, &dns[j].address, &b);
+                if (r < 0) {
+                        log_debug_errno(r, "Failed to format address, ignoring: %m");
+                        continue;
+                }
+
+                if (*space)
+                        fputc(' ', f);
+                fputs(b, f);
+                *space = true;
+        }
+}
+
 int link_save(Link *link) {
         _cleanup_free_ char *temp_path = NULL;
         _cleanup_fclose_ FILE *f = NULL;
@@ -3437,7 +3487,6 @@ int link_save(Link *link) {
                 char **dhcp6_domains = NULL, **dhcp_domains = NULL;
                 const char *dhcp_domainname = NULL, *p;
                 sd_dhcp6_lease *dhcp6_lease = NULL;
-                unsigned j;
                 bool space;
 
                 fprintf(f, "REQUIRED_FOR_ONLINE=%s\n",
@@ -3457,21 +3506,10 @@ int link_save(Link *link) {
                 fputs("DNS=", f);
                 space = false;
 
-                for (j = 0; j < link->network->n_dns; j++) {
-                        _cleanup_free_ char *b = NULL;
-
-                        r = in_addr_to_string(link->network->dns[j].family,
-                                              &link->network->dns[j].address,  &b);
-                        if (r < 0) {
-                                log_debug_errno(r, "Failed to format address, ignoring: %m");
-                                continue;
-                        }
-
-                        if (space)
-                                fputc(' ', f);
-                        fputs(b, f);
-                        space = true;
-                }
+                if (link->n_dns != (unsigned) -1)
+                        link_save_dns(f, link->dns, link->n_dns, &space);
+                else
+                        link_save_dns(f, link->network->dns, link->network->n_dns, &space);
 
                 if (link->network->dhcp_use_dns &&
                     link->dhcp_lease) {
@@ -3514,7 +3552,7 @@ int link_save(Link *link) {
 
                 fputs("NTP=", f);
                 space = false;
-                fputstrv(f, link->network->ntp, NULL, &space);
+                fputstrv(f, link->ntp ?: link->network->ntp, NULL, &space);
 
                 if (link->network->dhcp_use_ntp &&
                     link->dhcp_lease) {
@@ -3557,7 +3595,7 @@ int link_save(Link *link) {
 
                 fputs("DOMAINS=", f);
                 space = false;
-                ORDERED_SET_FOREACH(p, link->network->search_domains, i)
+                ORDERED_SET_FOREACH(p, link->search_domains ?: link->network->search_domains, i)
                         fputs_with_space(f, p, NULL, &space);
 
                 if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
@@ -3580,7 +3618,7 @@ int link_save(Link *link) {
 
                 fputs("ROUTE_DOMAINS=", f);
                 space = false;
-                ORDERED_SET_FOREACH(p, link->network->route_domains, i)
+                ORDERED_SET_FOREACH(p, link->route_domains ?: link->network->route_domains, i)
                         fputs_with_space(f, p, NULL, &space);
 
                 if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
@@ -3602,21 +3640,37 @@ int link_save(Link *link) {
                 fputc('\n', f);
 
                 fprintf(f, "LLMNR=%s\n",
-                        resolve_support_to_string(link->network->llmnr));
+                        resolve_support_to_string(link->llmnr >= 0 ? link->llmnr : link->network->llmnr));
                 fprintf(f, "MDNS=%s\n",
-                        resolve_support_to_string(link->network->mdns));
-                if (link->network->dns_default_route >= 0)
+                        resolve_support_to_string(link->mdns >= 0 ? link->mdns : link->network->mdns));
+                if (link->dns_default_route >= 0)
+                        fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(link->dns_default_route));
+                else if (link->network->dns_default_route >= 0)
                         fprintf(f, "DNS_DEFAULT_ROUTE=%s\n", yes_no(link->network->dns_default_route));
 
-                if (link->network->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
+                if (link->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
+                        fprintf(f, "DNS_OVER_TLS=%s\n",
+                                dns_over_tls_mode_to_string(link->dns_over_tls_mode));
+                else if (link->network->dns_over_tls_mode != _DNS_OVER_TLS_MODE_INVALID)
                         fprintf(f, "DNS_OVER_TLS=%s\n",
                                 dns_over_tls_mode_to_string(link->network->dns_over_tls_mode));
 
-                if (link->network->dnssec_mode != _DNSSEC_MODE_INVALID)
+                if (link->dnssec_mode != _DNSSEC_MODE_INVALID)
+                        fprintf(f, "DNSSEC=%s\n",
+                                dnssec_mode_to_string(link->dnssec_mode));
+                else if (link->network->dnssec_mode != _DNSSEC_MODE_INVALID)
                         fprintf(f, "DNSSEC=%s\n",
                                 dnssec_mode_to_string(link->network->dnssec_mode));
 
-                if (!set_isempty(link->network->dnssec_negative_trust_anchors)) {
+                if (!set_isempty(link->dnssec_negative_trust_anchors)) {
+                        const char *n;
+
+                        fputs("DNSSEC_NTA=", f);
+                        space = false;
+                        SET_FOREACH(n, link->dnssec_negative_trust_anchors, i)
+                                fputs_with_space(f, n, NULL, &space);
+                        fputc('\n', f);
+                } else if (!set_isempty(link->network->dnssec_negative_trust_anchors)) {
                         const char *n;
 
                         fputs("DNSSEC_NTA=", f);
index 43efa42312412ede531cc4c299f64746fc0d915c..e8680bbb1f6b1c6b4ad78b830b70885cad2b05f5 100644 (file)
@@ -18,6 +18,8 @@
 #include "log-link.h"
 #include "network-util.h"
 #include "networkd-util.h"
+#include "ordered-set.h"
+#include "resolve-util.h"
 #include "set.h"
 
 typedef enum LinkState {
@@ -130,6 +132,20 @@ typedef struct Link {
         bool stats_updated;
 
         int sysctl_ipv6_enabled;
+
+        /* All kinds of DNS configuration */
+        struct in_addr_data *dns;
+        unsigned n_dns;
+        OrderedSet *search_domains, *route_domains;
+
+        int dns_default_route;
+        ResolveSupport llmnr;
+        ResolveSupport mdns;
+        DnssecMode dnssec_mode;
+        DnsOverTlsMode dns_over_tls_mode;
+        Set *dnssec_negative_trust_anchors;
+
+        char **ntp;
 } Link;
 
 typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*, Link*);
@@ -137,6 +153,8 @@ typedef int (*link_netlink_message_handler_t)(sd_netlink*, sd_netlink_message*,
 DUID *link_get_duid(Link *link);
 int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
 
+void link_ntp_settings_clear(Link *link);
+void link_dns_settings_clear(Link *link);
 Link *link_unref(Link *link);
 Link *link_ref(Link *link);
 DEFINE_TRIVIAL_CLEANUP_FUNC(Link*, link_unref);
index 6174104f5eb754688830c1c1a3f1b73d302a07f0..37b04ce55660c40f96583933ef5bca540f32dcab 100644 (file)
@@ -116,6 +116,73 @@ static int method_get_link_by_index(sd_bus_message *message, void *userdata, sd_
         return sd_bus_send(NULL, reply, NULL);
 }
 
+static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
+        int ifindex, r;
+        Link *l;
+
+        assert(m);
+        assert(message);
+        assert(handler);
+
+        assert_cc(sizeof(int) == sizeof(int32_t));
+        r = sd_bus_message_read(message, "i", &ifindex);
+        if (r < 0)
+                return r;
+
+        if (ifindex <= 0)
+                return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid interface index");
+
+        l = hashmap_get(m->links, INT_TO_PTR(ifindex));
+        if (!l)
+                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
+
+        return handler(message, l, error);
+}
+
+static int bus_method_set_link_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_ntp_servers, error);
+}
+
+static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
+}
+
+static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_domains, error);
+}
+
+static int bus_method_set_link_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_default_route, error);
+}
+
+static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_llmnr, error);
+}
+
+static int bus_method_set_link_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_mdns, error);
+}
+
+static int bus_method_set_link_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_dns_over_tls, error);
+}
+
+static int bus_method_set_link_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_dnssec, error);
+}
+
+static int bus_method_set_link_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_set_dnssec_negative_trust_anchors, error);
+}
+
+static int bus_method_revert_link_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_revert_ntp, error);
+}
+
+static int bus_method_revert_link_dns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
+        return call_link_method(userdata, message, bus_link_method_revert_dns, error);
+}
+
 const sd_bus_vtable manager_vtable[] = {
         SD_BUS_VTABLE_START(0),
 
@@ -126,6 +193,17 @@ const sd_bus_vtable manager_vtable[] = {
         SD_BUS_METHOD("ListLinks", NULL, "a(iso)", method_list_links, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetLinkByName", "s", "io", method_get_link_by_name, SD_BUS_VTABLE_UNPRIVILEGED),
         SD_BUS_METHOD("GetLinkByIndex", "i", "so", method_get_link_by_index, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkNTP", "ias", NULL, bus_method_set_link_ntp_servers, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkDNS", "ia(iay)", NULL, bus_method_set_link_dns_servers, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkDomains", "ia(sb)", NULL, bus_method_set_link_domains, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkDefaultRoute", "ib", NULL, bus_method_set_link_default_route, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkLLMNR", "is", NULL, bus_method_set_link_llmnr, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkMulticastDNS", "is", NULL, bus_method_set_link_mdns, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkDNSOverTLS", "is", NULL, bus_method_set_link_dns_over_tls, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkDNSSEC", "is", NULL, bus_method_set_link_dnssec, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("SetLinkDNSSECNegativeTrustAnchors", "ias", NULL, bus_method_set_link_dnssec_negative_trust_anchors, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("RevertLinkNTP", "i", NULL, bus_method_revert_link_ntp, SD_BUS_VTABLE_UNPRIVILEGED),
+        SD_BUS_METHOD("RevertLinkDNS", "i", NULL, bus_method_revert_link_dns, SD_BUS_VTABLE_UNPRIVILEGED),
 
         SD_BUS_VTABLE_END
 };
index 8d72d290a0f1a6af5ef7ad4b1497a0980a3d736d..51cc8f654bb20ce4eb4828122bad1eab3a5dc1c1 100644 (file)
@@ -1164,15 +1164,15 @@ static int manager_save(Manager *m) {
                 if (r < 0)
                         return r;
 
-                r = ordered_set_put_strdupv(ntp, link->network->ntp);
+                r = ordered_set_put_strdupv(ntp, link->ntp ?: link->network->ntp);
                 if (r < 0)
                         return r;
 
-                r = ordered_set_put_string_set(search_domains, link->network->search_domains);
+                r = ordered_set_put_string_set(search_domains, link->search_domains ?: link->network->search_domains);
                 if (r < 0)
                         return r;
 
-                r = ordered_set_put_string_set(route_domains, link->network->route_domains);
+                r = ordered_set_put_string_set(route_domains, link->route_domains ?: link->network->route_domains);
                 if (r < 0)
                         return r;
 
@@ -1433,6 +1433,7 @@ void manager_free(Manager *m) {
 
         sd_device_monitor_unref(m->device_monitor);
 
+        bus_verify_polkit_async_registry_free(m->polkit_registry);
         sd_bus_flush_close_unref(m->bus);
 
         free(m->dynamic_timezone);
index e5bf7ac9f7ae060c9191babdf58033306bb542b4..5422b56dc265892c095c782941a6891b7e2f9248 100644 (file)
@@ -25,6 +25,7 @@ struct Manager {
         sd_resolve *resolve;
         sd_bus *bus;
         sd_device_monitor *device_monitor;
+        Hashmap *polkit_registry;
 
         bool enumerating:1;
         bool dirty:1;
index 56a78ee7dcaa96c539cdf025992d863e45889efb..366c630702d37b34de21bc380a760c4abaccf641 100644 (file)
         </policy>
 
         <policy context="default">
-                <deny send_destination="org.freedesktop.network1"/>
-
-                <allow send_destination="org.freedesktop.network1"
-                       send_interface="org.freedesktop.DBus.Introspectable"/>
-
-                <allow send_destination="org.freedesktop.network1"
-                       send_interface="org.freedesktop.DBus.Peer"/>
-
-                <allow send_destination="org.freedesktop.network1"
-                       send_interface="org.freedesktop.DBus.Properties"
-                       send_member="Get"/>
-
-                <allow send_destination="org.freedesktop.network1"
-                       send_interface="org.freedesktop.DBus.Properties"
-                       send_member="GetAll"/>
-
-                <allow send_destination="org.freedesktop.network1"
-                       send_interface="org.freedesktop.network1.Manager"
-                       send_member="ListLinks"/>
-
-                <allow send_destination="org.freedesktop.network1"
-                       send_interface="org.freedesktop.network1.Manager"
-                       send_member="GetLinkByName"/>
-
-                <allow send_destination="org.freedesktop.network1"
-                       send_interface="org.freedesktop.network1.Manager"
-                       send_member="GetLinkByIndex"/>
-
+                <allow send_destination="org.freedesktop.network1"/>
                 <allow receive_sender="org.freedesktop.network1"/>
         </policy>
 
diff --git a/src/network/org.freedesktop.network1.policy b/src/network/org.freedesktop.network1.policy
new file mode 100644 (file)
index 0000000..07091bf
--- /dev/null
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?> <!--*-nxml-*-->
+<!DOCTYPE policyconfig PUBLIC "-//freedesktop//DTD PolicyKit Policy Configuration 1.0//EN"
+        "http://www.freedesktop.org/standards/PolicyKit/1/policyconfig.dtd">
+
+<!--
+  SPDX-License-Identifier: LGPL-2.1+
+
+  This file is part of systemd.
+
+  systemd is free software; you can redistribute it and/or modify it
+  under the terms of the GNU Lesser General Public License as published by
+  the Free Software Foundation; either version 2.1 of the License, or
+  (at your option) any later version.
+-->
+
+<policyconfig>
+
+        <vendor>The systemd Project</vendor>
+        <vendor_url>http://www.freedesktop.org/wiki/Software/systemd</vendor_url>
+
+        <action id="org.freedesktop.network1.set-ntp-servers">
+                <description gettext-domain="systemd">Set NTP servers</description>
+                <message gettext-domain="systemd">Authentication is required to set NTP servers.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.set-dns-servers">
+                <description gettext-domain="systemd">Set DNS servers</description>
+                <message gettext-domain="systemd">Authentication is required to set DNS servers.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.set-domains">
+                <description gettext-domain="systemd">Set domains</description>
+                <message gettext-domain="systemd">Authentication is required to set domains.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.set-default-route">
+                <description gettext-domain="systemd">Set default route</description>
+                <message gettext-domain="systemd">Authentication is required to set default route.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.set-llmnr">
+                <description gettext-domain="systemd">Enable/disable LLMNR</description>
+                <message gettext-domain="systemd">Authentication is required to enable or disable LLMNR.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.set-mdns">
+                <description gettext-domain="systemd">Enable/disable multicast DNS</description>
+                <message gettext-domain="systemd">Authentication is required to enable or disable multicast DNS.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.set-dns-over-tls">
+                <description gettext-domain="systemd">Enable/disable DNS over TLS</description>
+                <message gettext-domain="systemd">Authentication is required to enable or disable DNS over TLS.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.set-dnssec">
+                <description gettext-domain="systemd">Enable/disable DNSSEC</description>
+                <message gettext-domain="systemd">Authentication is required to enable or disable DNSSEC.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.set-dnssec-negative-trust-anchors">
+                <description gettext-domain="systemd">Set DNSSEC Negative Trust Anchors</description>
+                <message gettext-domain="systemd">Authentication is required to set DNSSEC Negative Trust Anchros.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.revert-ntp">
+                <description gettext-domain="systemd">Revert NTP settings</description>
+                <message gettext-domain="systemd">Authentication is required to revert NTP settings.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+        <action id="org.freedesktop.network1.revert-dns">
+                <description gettext-domain="systemd">Revert DNS settings</description>
+                <message gettext-domain="systemd">Authentication is required to revert DNS settings.</message>
+                <defaults>
+                        <allow_any>auth_admin</allow_any>
+                        <allow_inactive>auth_admin</allow_inactive>
+                        <allow_active>auth_admin_keep</allow_active>
+                </defaults>
+                <annotate key="org.freedesktop.policykit.owner">unix-user:systemd-network</annotate>
+        </action>
+
+</policyconfig>