]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: request product UUID when DUIDType=uuid but DUIDRawData= is not set
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 2 Jul 2018 18:19:15 +0000 (03:19 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Wed, 8 Aug 2018 01:15:00 +0000 (10:15 +0900)
Closes #9228.

src/network/networkd-link.c
src/network/networkd-link.h
src/network/networkd-manager.c
src/network/networkd-manager.h
src/network/networkd-network.c
src/network/systemd-networkd.pkla
src/network/systemd-networkd.rules

index 09bc0ac90705fcd2856fb28a3e56a191388080d2..7e4e868d828ba504d72fbd72575b53347b9b1bb8 100644 (file)
@@ -8,6 +8,7 @@
 
 #include "alloc-util.h"
 #include "bus-util.h"
+#include "dhcp-identifier.h"
 #include "dhcp-lease-internal.h"
 #include "fd-util.h"
 #include "fileio.h"
@@ -546,8 +547,10 @@ static void link_free(Link *link) {
         sd_ndisc_unref(link->ndisc);
         sd_radv_unref(link->radv);
 
-        if (link->manager)
+        if (link->manager) {
                 hashmap_remove(link->manager->links, INT_TO_PTR(link->ifindex));
+                set_remove(link->manager->links_requesting_uuid, link);
+        }
 
         free(link->ifname);
 
@@ -2891,6 +2894,134 @@ static int link_configure(Link *link) {
         return link_enter_join_netdev(link);
 }
 
+static int duid_set_uuid(DUID *duid, sd_id128_t uuid) {
+        assert(duid);
+
+        if (duid->raw_data_len > 0)
+                return 0;
+
+        if (duid->type != DUID_TYPE_UUID)
+                return -EINVAL;
+
+        memcpy(&duid->raw_data, &uuid, sizeof(sd_id128_t));
+        duid->raw_data_len = sizeof(sd_id128_t);
+
+        return 1;
+}
+
+int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
+        Manager *manager = userdata;
+        const sd_bus_error *e;
+        const void *a;
+        size_t sz;
+        DUID *duid;
+        Link *link;
+        int r;
+
+        assert(m);
+        assert(manager);
+
+        e = sd_bus_message_get_error(m);
+        if (e) {
+                log_error_errno(sd_bus_error_get_errno(e),
+                                "Could not get product UUID. Fallback to use application specific machine ID as DUID-UUID: %s",
+                                e->message);
+                goto configure;
+        }
+
+        r = sd_bus_message_read_array(m, 'y', &a, &sz);
+        if (r < 0)
+                goto configure;
+
+        if (sz != sizeof(sd_id128_t)) {
+                log_error("Invalid product UUID. Fallback to use application specific machine ID as DUID-UUID.");
+                goto configure;
+        }
+
+        memcpy(&manager->product_uuid, a, sz);
+        while ((duid = set_steal_first(manager->duids_requesting_uuid)))
+                (void) duid_set_uuid(duid, manager->product_uuid);
+
+        manager->duids_requesting_uuid = set_free(manager->duids_requesting_uuid);
+
+configure:
+        while ((link = set_steal_first(manager->links_requesting_uuid))) {
+                r = link_configure(link);
+                if (r < 0)
+                        log_link_error_errno(link, r, "Failed to configure link: %m");
+        }
+
+        manager->links_requesting_uuid = set_free(manager->links_requesting_uuid);
+
+        /* To avoid calling GetProductUUID() bus method so frequently, set the flag below
+         * even if the method fails. */
+        manager->has_product_uuid = true;
+
+        return 1;
+}
+
+static bool link_requires_uuid(Link *link) {
+        const DUID *duid;
+
+        assert(link);
+        assert(link->manager);
+        assert(link->network);
+
+        duid = link_get_duid(link);
+        if (duid->type != DUID_TYPE_UUID || duid->raw_data_len != 0)
+                return false;
+
+        if (link_dhcp4_enabled(link) && IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
+                return true;
+
+        if (link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link))
+                return true;
+
+        return false;
+}
+
+static int link_configure_duid(Link *link) {
+        Manager *m;
+        DUID *duid;
+        int r;
+
+        assert(link);
+        assert(link->manager);
+        assert(link->network);
+
+        m = link->manager;
+        duid = link_get_duid(link);
+
+        if (!link_requires_uuid(link))
+                return 1;
+
+        if (m->has_product_uuid) {
+                (void) duid_set_uuid(duid, m->product_uuid);
+                return 1;
+        }
+
+        if (!m->links_requesting_uuid) {
+                r = manager_request_product_uuid(m, link);
+                if (r < 0) {
+                        if (r == -ENOMEM)
+                                return r;
+
+                        log_link_warning_errno(link, r, "Failed to get product UUID. Fallback to use application specific machine ID as DUID-UUID: %m");
+                        return 1;
+                }
+        } else {
+                r = set_put(m->links_requesting_uuid, link);
+                if (r < 0)
+                        return log_oom();
+
+                r = set_put(m->duids_requesting_uuid, duid);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        return 0;
+}
+
 static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
                                        void *userdata) {
         _cleanup_(link_unrefp) Link *link = userdata;
@@ -2946,6 +3077,12 @@ static int link_initialized_and_synced(sd_netlink *rtnl, sd_netlink_message *m,
         if (r < 0)
                 return r;
 
+        /* link_configure_duid() returns 0 if it requests product UUID. In that case,
+         * link_configure() is called later asynchronously. */
+        r = link_configure_duid(link);
+        if (r <= 0)
+                return r;
+
         r = link_configure(link);
         if (r < 0)
                 return r;
index 6ed11ff51c553ea44b9d4dd2c7d1b9dfa741b627..4c13cc156e4f13fa48cd1713cfdb08c3ab860891 100644 (file)
@@ -125,6 +125,7 @@ typedef struct Link {
 } Link;
 
 DUID *link_get_duid(Link *link);
+int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error);
 
 Link *link_unref(Link *link);
 Link *link_ref(Link *link);
index 3792f3d7002e5b9e86ce265d5230c169c201909c..4e14fab89f9ba568e2e64c00050c7669f4f79c0d 100644 (file)
@@ -114,6 +114,8 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r
                 (void) manager_set_hostname(m, m->dynamic_hostname);
         if (m->dynamic_timezone)
                 (void) manager_set_timezone(m, m->dynamic_timezone);
+        if (m->links_requesting_uuid)
+                (void) manager_request_product_uuid(m, NULL);
 
         return 0;
 }
@@ -1459,6 +1461,9 @@ void manager_free(Manager *m) {
                 link_unref(link);
         hashmap_free(m->links);
 
+        set_free(m->links_requesting_uuid);
+        set_free(m->duids_requesting_uuid);
+
         hashmap_free(m->networks_by_name);
 
         while ((netdev = hashmap_first(m->netdevs)))
@@ -1831,3 +1836,57 @@ int manager_set_timezone(Manager *m, const char *tz) {
 
         return 0;
 }
+
+int manager_request_product_uuid(Manager *m, Link *link) {
+        int r;
+
+        assert(m);
+
+        if (m->has_product_uuid)
+                return 0;
+
+        log_debug("Requesting product UUID");
+
+        if (link) {
+                DUID *duid;
+
+                assert_se(duid = link_get_duid(link));
+
+                r = set_ensure_allocated(&m->links_requesting_uuid, NULL);
+                if (r < 0)
+                        return log_oom();
+
+                r = set_ensure_allocated(&m->duids_requesting_uuid, NULL);
+                if (r < 0)
+                        return log_oom();
+
+                r = set_put(m->links_requesting_uuid, link);
+                if (r < 0)
+                        return log_oom();
+
+                r = set_put(m->duids_requesting_uuid, duid);
+                if (r < 0)
+                        return log_oom();
+        }
+
+        if (!m->bus || sd_bus_is_ready(m->bus) <= 0) {
+                log_debug("Not connected to system bus, requesting product UUID later.");
+                return 0;
+        }
+
+        r = sd_bus_call_method_async(
+                        m->bus,
+                        NULL,
+                        "org.freedesktop.hostname1",
+                        "/org/freedesktop/hostname1",
+                        "org.freedesktop.hostname1",
+                        "GetProductUUID",
+                        get_product_uuid_handler,
+                        m,
+                        "b",
+                        false);
+        if (r < 0)
+                return log_warning_errno(r, "Failed to get product UUID: %m");
+
+        return 0;
+}
index d6e3fe5478181f77725bd2966d6dbbc48a0a0cf2..410e00da63829e432d106a3ac73f2ba9ba45dcde 100644 (file)
@@ -5,6 +5,7 @@
 
 #include "sd-bus.h"
 #include "sd-event.h"
+#include "sd-id128.h"
 #include "sd-netlink.h"
 #include "sd-resolve.h"
 #include "udev.h"
@@ -48,6 +49,11 @@ struct Manager {
         usec_t network_dirs_ts_usec;
 
         DUID duid;
+        sd_id128_t product_uuid;
+        bool has_product_uuid;
+        Set *links_requesting_uuid;
+        Set *duids_requesting_uuid;
+
         char* dynamic_hostname;
         char* dynamic_timezone;
 
@@ -85,6 +91,7 @@ Link* manager_find_uplink(Manager *m, Link *exclude);
 
 int manager_set_hostname(Manager *m, const char *hostname);
 int manager_set_timezone(Manager *m, const char *timezone);
+int manager_request_product_uuid(Manager *m, Link *link);
 
 Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr);
 int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link);
index 77ba8c678ee32dd0a9f5b54fb2144ebdaad45848..2fa067655eb17425bdc675865ca6979fee9721a1 100644 (file)
@@ -415,6 +415,9 @@ void network_free(Network *network) {
 
                 if (network->manager->networks_by_name)
                         hashmap_remove(network->manager->networks_by_name, network->name);
+
+                if (network->manager->duids_requesting_uuid)
+                        set_remove(network->manager->duids_requesting_uuid, &network->duid);
         }
 
         free(network->name);
index fb257d933bca2bcfaa242761fa8f564863a5cfff..4d1bb4585e4736947a40a15b47899be10d593955 100644 (file)
@@ -1,4 +1,4 @@
 [Allow systemd-networkd to set timezone and transient hostname]
 Identity=unix-user:systemd-network
-Action=org.freedesktop.hostname1.set-hostname;org.freedesktop.timedate1.set-timezone;
+Action=org.freedesktop.hostname1.set-hostname;org.freedesktop.hostname1.get-product-uuid;org.freedesktop.timedate1.set-timezone;
 ResultAny=yes
index 2e4bc42bfb307fbff1a612b518e7acaaacf455b4..b9077c1ea2da709943493729e70bbacf1da6f49f 100644 (file)
@@ -1,6 +1,8 @@
-// Allow systemd-networkd to set timezone and transient hostname
+// Allow systemd-networkd to set timezone, get product UUID,
+// and transient hostname
 polkit.addRule(function(action, subject) {
     if ((action.id == "org.freedesktop.hostname1.set-hostname" ||
+         action.id == "org.freedesktop.hostname1.get-product-uuid" ||
          action.id == "org.freedesktop.timedate1.set-timezone") &&
         subject.user == "systemd-network") {
         return polkit.Result.YES;