summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2016-04-26 12:56:01 +0200
committerThomas Haller <thaller@redhat.com>2016-04-26 12:56:01 +0200
commitc17b4ba6c750c375e80ae37759d9a4c9caa5bf08 (patch)
treedca2d57a4fa4be4983637aaa85d09d27c90d6040
parentdd4d8b24da29abfc786ce0b3030c74559b93d034 (diff)
parent89cf9429a76d8230bde8d2ca169e42bfb8803634 (diff)
downloadNetworkManager-c17b4ba6c750c375e80ae37759d9a4c9caa5bf08.tar.gz
device: merge branch 'th/default-wired-connection-stable-uuid-bgo765464'
https://bugzilla.gnome.org/show_bug.cgi?id=765464
-rw-r--r--src/Makefile.am1
-rw-r--r--src/devices/nm-device-ethernet.c20
-rw-r--r--src/dhcp-manager/nm-dhcp-client.c58
-rw-r--r--src/nm-core-utils.c168
-rw-r--r--src/nm-core-utils.h5
-rw-r--r--src/settings/nm-settings.c8
-rw-r--r--src/tests/Makefile.am1
-rw-r--r--src/tests/test-utils.c6
8 files changed, 163 insertions, 104 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index e567fe0a7c..4ec7b40156 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -209,6 +209,7 @@ libNetworkManager_base_la_CPPFLAGS = \
-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_INSIDE_DAEMON \
-DNO_SYSTEMD_JOURNAL \
-DPREFIX=\"$(prefix)\" \
+ -DLOCALSTATEDIR=\"$(localstatedir)\" \
-DNMSTATEDIR=\"$(nmstatedir)\" \
$(GLIB_CFLAGS)
diff --git a/src/devices/nm-device-ethernet.c b/src/devices/nm-device-ethernet.c
index 6225ae7bf6..acf822a2e5 100644
--- a/src/devices/nm-device-ethernet.c
+++ b/src/devices/nm-device-ethernet.c
@@ -1433,7 +1433,9 @@ new_default_connection (NMDevice *self)
const GSList *connections;
NMSetting *setting;
const char *hw_address;
- char *defname, *uuid;
+ gs_free char *defname = NULL;
+ gs_free char *uuid = NULL;
+ gs_free char *machine_id = NULL;
if (nm_config_get_no_auto_default_for_device (nm_config_get (), self))
return NULL;
@@ -1448,7 +1450,19 @@ new_default_connection (NMDevice *self)
connections = nm_connection_provider_get_connections (nm_connection_provider_get ());
defname = nm_device_ethernet_utils_get_default_wired_name (connections);
- uuid = nm_utils_uuid_generate ();
+ if (!defname)
+ return NULL;
+
+ machine_id = nm_utils_machine_id_read ();
+
+ /* Create a stable UUID. The UUID is also the Network_ID for stable-privacy addr-gen-mode,
+ * thus when it changes we will also generate different IPv6 addresses. */
+ uuid = _nm_utils_uuid_generate_from_strings ("default-wired",
+ machine_id ?: "",
+ defname,
+ hw_address,
+ NULL);
+
g_object_set (setting,
NM_SETTING_CONNECTION_ID, defname,
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME,
@@ -1457,8 +1471,6 @@ new_default_connection (NMDevice *self)
NM_SETTING_CONNECTION_UUID, uuid,
NM_SETTING_CONNECTION_TIMESTAMP, (guint64) time (NULL),
NULL);
- g_free (uuid);
- g_free (defname);
/* Lock the connection to the device */
setting = nm_setting_wired_new ();
diff --git a/src/dhcp-manager/nm-dhcp-client.c b/src/dhcp-manager/nm-dhcp-client.c
index 7e72233670..3490c0d235 100644
--- a/src/dhcp-manager/nm-dhcp-client.c
+++ b/src/dhcp-manager/nm-dhcp-client.c
@@ -436,37 +436,10 @@ nm_dhcp_client_start_ip4 (NMDhcpClient *self,
return NM_DHCP_CLIENT_GET_CLASS (self)->ip4_start (self, dhcp_anycast_addr, last_ip4_address);
}
-/* uuid_parse does not work for machine-id, so we use our own converter */
-static gboolean
-machine_id_parse (const char *in, uuid_t uu)
-{
- const char *cp;
- int i;
- char buf[3];
-
- g_return_val_if_fail (in != NULL, FALSE);
- g_return_val_if_fail (strlen (in) == 32, FALSE);
-
- for (i = 0; i < 32; i++) {
- if (!g_ascii_isxdigit (in[i]))
- return FALSE;
- }
-
- buf[2] = 0;
- cp = in;
- for (i = 0; i < 16; i++) {
- buf[0] = *cp++;
- buf[1] = *cp++;
- uu[i] = ((unsigned char) strtoul (buf, NULL, 16)) & 0xFF;
- }
- return TRUE;
-}
-
static GByteArray *
generate_duid_from_machine_id (void)
{
GByteArray *duid;
- char *contents = NULL;
GChecksum *sum;
guint8 buffer[32]; /* SHA256 digest size */
gsize sumlen = sizeof (buffer);
@@ -474,27 +447,16 @@ generate_duid_from_machine_id (void)
uuid_t uuid;
GRand *generator;
guint i;
- gboolean success = FALSE;
-
- /* Get the machine ID from /etc/machine-id; it's always in /etc no matter
- * where our configured SYSCONFDIR is. Alternatively, it might be in
- * LOCALSTATEDIR /lib/dbus/machine-id.
- */
- if ( g_file_get_contents ("/etc/machine-id", &contents, NULL, NULL)
- || g_file_get_contents (LOCALSTATEDIR "/lib/dbus/machine-id", &contents, NULL, NULL)) {
- contents = g_strstrip (contents);
- success = machine_id_parse (contents, uuid);
- if (success) {
- /* Hash the machine ID so it's not leaked to the network */
- sum = g_checksum_new (G_CHECKSUM_SHA256);
- g_checksum_update (sum, (const guchar *) &uuid, sizeof (uuid));
- g_checksum_get_digest (sum, buffer, &sumlen);
- g_checksum_free (sum);
- }
- g_free (contents);
- }
-
- if (!success) {
+ gs_free char *machine_id_s = NULL;
+
+ machine_id_s = nm_utils_machine_id_read ();
+ if (nm_utils_machine_id_parse (machine_id_s, uuid)) {
+ /* Hash the machine ID so it's not leaked to the network */
+ sum = g_checksum_new (G_CHECKSUM_SHA256);
+ g_checksum_update (sum, (const guchar *) &uuid, sizeof (uuid));
+ g_checksum_get_digest (sum, buffer, &sumlen);
+ g_checksum_free (sum);
+ } else {
nm_log_warn (LOGD_DHCP6, "dhcp6: failed to read " SYSCONFDIR "/machine-id "
"or " LOCALSTATEDIR "/lib/dbus/machine-id to generate "
"DHCPv6 DUID; creating non-persistent random DUID.");
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 188e4737af..6581d6b711 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -2588,6 +2588,121 @@ nm_utils_is_specific_hostname (const char *name)
/******************************************************************/
+gboolean
+nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_uuid)
+{
+ int i;
+ guint8 v0, v1;
+
+ if (!id_str)
+ return FALSE;
+
+ for (i = 0; i < 32; i++) {
+ if (!g_ascii_isxdigit (id_str[i]))
+ return FALSE;
+ }
+ if (id_str[i] != '\0')
+ return FALSE;
+
+ if (out_uuid) {
+ for (i = 0; i < 16; i++) {
+ v0 = g_ascii_xdigit_value (*(id_str++));
+ v1 = g_ascii_xdigit_value (*(id_str++));
+ out_uuid[i] = (v0 << 4) + v1;
+ }
+ }
+ return TRUE;
+}
+
+char *
+nm_utils_machine_id_read (void)
+{
+ gs_free char *contents = NULL;
+ int i;
+
+ /* Get the machine ID from /etc/machine-id; it's always in /etc no matter
+ * where our configured SYSCONFDIR is. Alternatively, it might be in
+ * LOCALSTATEDIR /lib/dbus/machine-id.
+ */
+ if ( !g_file_get_contents ("/etc/machine-id", &contents, NULL, NULL)
+ && !g_file_get_contents (LOCALSTATEDIR "/lib/dbus/machine-id", &contents, NULL, NULL))
+ return FALSE;
+
+ contents = g_strstrip (contents);
+
+ for (i = 0; i < 32; i++) {
+ if (!g_ascii_isxdigit (contents[i]))
+ return FALSE;
+ if (contents[i] >= 'A' && contents[i] <= 'F') {
+ /* canonicalize to lower-case */
+ contents[i] = 'a' + (contents[i] - 'A');
+ }
+ }
+ if (contents[i] != '\0')
+ return FALSE;
+
+ return nm_unauto (&contents);
+}
+
+/*****************************************************************************/
+
+guint8 *
+nm_utils_secret_key_read (gsize *out_key_len, GError **error)
+{
+ guint8 *secret_key = NULL;
+ gsize key_len;
+
+ /* out_key_len is not optional, because without it you cannot safely
+ * access the returned memory. */
+ *out_key_len = 0;
+
+ /* Let's try to load a saved secret key first. */
+ if (g_file_get_contents (NMSTATEDIR "/secret_key", (char **) &secret_key, &key_len, NULL)) {
+ if (key_len < 16) {
+ g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ "Key is too short to be usable");
+ key_len = 0;
+ }
+ } else {
+ int urandom = open ("/dev/urandom", O_RDONLY);
+ mode_t key_mask;
+
+ if (urandom == -1) {
+ g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ "Can't open /dev/urandom: %s", strerror (errno));
+ key_len = 0;
+ goto out;
+ }
+
+ /* RFC7217 mandates the key SHOULD be at least 128 bits.
+ * Let's use twice as much. */
+ key_len = 32;
+ secret_key = g_malloc (key_len);
+
+ key_mask = umask (0077);
+ if (read (urandom, secret_key, key_len) == key_len) {
+ if (!g_file_set_contents (NMSTATEDIR "/secret_key", (char *) secret_key, key_len, error)) {
+ g_prefix_error (error, "Can't write " NMSTATEDIR "/secret_key: ");
+ key_len = 0;
+ }
+ } else {
+ g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+ "Could not obtain a secret");
+ key_len = 0;
+ }
+ umask (key_mask);
+ close (urandom);
+ }
+
+out:
+ if (key_len) {
+ *out_key_len = key_len;
+ return secret_key;
+ }
+ g_free (secret_key);
+ return NULL;
+}
+
/* Returns the "u" (universal/local) bit value for a Modified EUI-64 */
static gboolean
get_gre_eui64_u_bit (guint32 addr)
@@ -2715,7 +2830,7 @@ _set_stable_privacy (struct in6_addr *addr,
const char *ifname,
const char *uuid,
guint dad_counter,
- gchar *secret_key,
+ guint8 *secret_key,
gsize key_len,
GError **error)
{
@@ -2773,9 +2888,8 @@ nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr,
guint dad_counter,
GError **error)
{
- gchar *secret_key = NULL;
+ gs_free guint8 *secret_key = NULL;
gsize key_len = 0;
- gboolean success = FALSE;
if (dad_counter >= RFC7217_IDGEN_RETRIES) {
g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
@@ -2783,50 +2897,12 @@ nm_utils_ipv6_addr_set_stable_privacy (struct in6_addr *addr,
return FALSE;
}
- /* Let's try to load a saved secret key first. */
- if (g_file_get_contents (NMSTATEDIR "/secret_key", &secret_key, &key_len, NULL)) {
- if (key_len < 16) {
- g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
- "Key is too short to be usable");
- key_len = 0;
- }
- } else {
- int urandom = open ("/dev/urandom", O_RDONLY);
- mode_t key_mask;
-
- if (urandom == -1) {
- g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
- "Can't open /dev/urandom: %s", strerror (errno));
- return FALSE;
- }
-
- /* RFC7217 mandates the key SHOULD be at least 128 bits.
- * Let's use twice as much. */
- key_len = 32;
- secret_key = g_malloc (key_len);
-
- key_mask = umask (0077);
- if (read (urandom, secret_key, key_len) == key_len) {
- if (!g_file_set_contents (NMSTATEDIR "/secret_key", secret_key, key_len, error)) {
- g_prefix_error (error, "Can't write " NMSTATEDIR "/secret_key: ");
- key_len = 0;
- }
- } else {
- g_set_error_literal (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
- "Could not obtain a secret");
- key_len = 0;
- }
- umask (key_mask);
- close (urandom);
- }
-
- if (key_len) {
- success = _set_stable_privacy (addr, ifname, uuid, dad_counter,
- secret_key, key_len, error);
- }
+ secret_key = nm_utils_secret_key_read (&key_len, error);
+ if (!secret_key)
+ return FALSE;
- g_free (secret_key);
- return success;
+ return _set_stable_privacy (addr, ifname, uuid, dad_counter,
+ secret_key, key_len, error);
}
/**
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
index 486942a22a..3033c33a5f 100644
--- a/src/nm-core-utils.h
+++ b/src/nm-core-utils.h
@@ -307,6 +307,11 @@ const char *nm_utils_ip4_property_path (const char *ifname, const char *property
gboolean nm_utils_is_specific_hostname (const char *name);
+char *nm_utils_machine_id_read (void);
+gboolean nm_utils_machine_id_parse (const char *id_str, /*uuid_t*/ guchar *out_uuid);
+
+guint8 *nm_utils_secret_key_read (gsize *out_key_len, GError **error);
+
/* IPv6 Interface Identifer helpers */
/**
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 281f299f1f..3b8ac5b5df 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -1982,9 +1982,11 @@ device_realized (NMDevice *device, GParamSpec *pspec, NMSettings *self)
g_object_unref (connection);
if (!added) {
- _LOGW ("(%s) couldn't create default wired connection: %s",
- nm_device_get_iface (device),
- error->message);
+ if (!g_error_matches (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_UUID_EXISTS)) {
+ _LOGW ("(%s) couldn't create default wired connection: %s",
+ nm_device_get_iface (device),
+ error->message);
+ }
g_clear_error (&error);
return;
}
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index b93d4da3b9..5b4e6b729f 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -142,6 +142,7 @@ test_utils_DEPENDENCIES = \
test_utils_CPPFLAGS = \
$(AM_CPPFLAGS) \
-DPREFIX=\"/nonexistent\" \
+ -DLOCALSTATEDIR=\"$(localstatedir)\" \
-DNMSTATEDIR=\"/nonsense\"
test_utils_LDADD = \
diff --git a/src/tests/test-utils.c b/src/tests/test-utils.c
index c8c82aefe4..6fc3978b9c 100644
--- a/src/tests/test-utils.c
+++ b/src/tests/test-utils.c
@@ -34,17 +34,17 @@ test_stable_privacy (void)
struct in6_addr addr1;
inet_pton (AF_INET6, "1234::", &addr1);
- _set_stable_privacy (&addr1, "eth666", "6b138152-9f3e-4b97-aaf7-e6e553f2a24e", 0, "key", 3, NULL);
+ _set_stable_privacy (&addr1, "eth666", "6b138152-9f3e-4b97-aaf7-e6e553f2a24e", 0, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "1234::4ceb:14cd:3d54:793f");
/* We get an address without the UUID. */
inet_pton (AF_INET6, "1::", &addr1);
- _set_stable_privacy (&addr1, "eth666", NULL, 384, "key", 3, NULL);
+ _set_stable_privacy (&addr1, "eth666", NULL, 384, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "1::11aa:2530:9144:dafa");
/* We get a different address in a different network. */
inet_pton (AF_INET6, "2::", &addr1);
- _set_stable_privacy (&addr1, "eth666", NULL, 384, "key", 3, NULL);
+ _set_stable_privacy (&addr1, "eth666", NULL, 384, (guint8 *) "key", 3, NULL);
nmtst_assert_ip6_address (&addr1, "2::338e:8d:c11:8726");
}