diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index bbe466545d..f095413dad 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -2559,6 +2559,63 @@ nm_utils_is_specific_hostname (const char *name) /******************************************************************/ +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) @@ -2686,7 +2743,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) { @@ -2744,9 +2801,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, @@ -2754,50 +2810,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; + secret_key = nm_utils_secret_key_read (&key_len, error); + if (!secret_key) + return FALSE; - 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); - } - - 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 528288c34c..dd21e82aec 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -306,6 +306,8 @@ const char *nm_utils_ip4_property_path (const char *ifname, const char *property gboolean nm_utils_is_specific_hostname (const char *name); +guint8 *nm_utils_secret_key_read (gsize *out_key_len, GError **error); + /* IPv6 Interface Identifer helpers */ /** 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"); }