diff options
Diffstat (limited to 'src/nm-core-utils.c')
| -rw-r--r-- | src/nm-core-utils.c | 178 |
1 files changed, 124 insertions, 54 deletions
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index b97be0b8..b1a4cc25 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -2044,8 +2044,8 @@ _log_connection_sort_hashes_fcn (gconstpointer a, gconstpointer b) NMSettingPriority p1, p2; NMSetting *s1, *s2; - s1 = v1->setting ? v1->setting : v1->diff_base_setting; - s2 = v2->setting ? v2->setting : v2->diff_base_setting; + s1 = v1->setting ?: v1->diff_base_setting; + s2 = v2->setting ?: v2->diff_base_setting; g_assert (s1 && s2); @@ -2279,13 +2279,13 @@ nm_utils_log_connection_diff (NMConnection *connection, g_string_printf (str1, "%s.%s", setting_data->name, item->item_name); switch (item->diff_result & (NM_SETTING_DIFF_RESULT_IN_A | NM_SETTING_DIFF_RESULT_IN_B)) { case NM_SETTING_DIFF_RESULT_IN_B: - nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s < %s", prefix, str1->str, str_diff ? str_diff : "NULL"); + nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s < %s", prefix, str1->str, str_diff ?: "NULL"); break; case NM_SETTING_DIFF_RESULT_IN_A: - nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s = %s", prefix, str1->str, str_conn ? str_conn : "NULL"); + nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s = %s", prefix, str1->str, str_conn ?: "NULL"); break; default: - nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s = %s < %s", prefix, str1->str, str_conn ? str_conn : "NULL", str_diff ? str_diff : "NULL"); + nm_log (level, domain, NULL, NULL, "%s%"_NM_LOG_ALIGN"s = %s < %s", prefix, str1->str, str_conn ?: "NULL", str_diff ?: "NULL"); break; #undef _NM_LOG_ALIGN } @@ -2344,7 +2344,6 @@ nm_utils_monotonic_timestamp_as_boottime (gint64 timestamp, gint64 timestamp_ns_ return timestamp - offset; } - #define IPV6_PROPERTY_DIR "/proc/sys/net/ipv6/conf/" #define IPV4_PROPERTY_DIR "/proc/sys/net/ipv4/conf/" G_STATIC_ASSERT (sizeof (IPV4_PROPERTY_DIR) == sizeof (IPV6_PROPERTY_DIR)); @@ -2798,53 +2797,103 @@ nm_utils_file_get_contents (int dirfd, /*****************************************************************************/ -guint8 * -nm_utils_secret_key_read (gsize *out_key_len, GError **error) +static gboolean +_secret_key_read (guint8 **out_secret_key, + gsize *out_key_len) { - guint8 *secret_key = NULL; + guint8 *secret_key; + gboolean success = TRUE; gsize key_len; - - /* out_key_len is not optional, because without it you cannot safely - * access the returned memory. */ - *out_key_len = 0; + gs_free_error GError *error = NULL; /* 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; - } + if (g_file_get_contents (NMSTATEDIR "/secret_key", (char **) &secret_key, &key_len, &error)) { + if (key_len >= 16) + goto out; + + /* the secret key is borked. Log a warning, but proceed below to generate + * a new one. */ + nm_log_warn (LOGD_CORE, "secret-key: too short secret key in \"%s\" (generate new key)", NMSTATEDIR "/secret_key"); + nm_clear_g_free (&secret_key); } else { - mode_t key_mask; + if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { + nm_log_warn (LOGD_CORE, "secret-key: failure reading secret key in \"%s\": %s (generate new key)", + NMSTATEDIR "/secret_key", error->message); + } + g_clear_error (&error); + } - /* 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); + /* 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 + 1); - if (!nm_utils_random_bytes (secret_key, key_len)) { - g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN, - "Can't get random data to generate secret key"); - key_len = 0; - goto out; - } + /* the secret-key is binary. Still, ensure that it's NULL terminated, just like + * g_file_set_contents() does. */ + secret_key[32] = '\0'; - key_mask = umask (0077); - 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; - } - umask (key_mask); + if (!nm_utils_random_bytes (secret_key, key_len)) { + nm_log_warn (LOGD_CORE, "secret-key: failure to generate good random data for secret-key (use non-persistent key)"); + success = FALSE; + goto out; + } + + if (!nm_utils_file_set_contents (NMSTATEDIR "/secret_key", (char *) secret_key, key_len, 0077, &error)) { + nm_log_warn (LOGD_CORE, "secret-key: failure to persist secret key in \"%s\" (%s) (use non-persistent key)", + NMSTATEDIR "/secret_key", error->message); + success = FALSE; + goto out; } out: - if (key_len) { - *out_key_len = key_len; - return secret_key; + /* regardless of success or failue, we always return a secret-key. The + * caller may choose to ignore the error and proceed. */ + *out_key_len = key_len; + *out_secret_key = secret_key; + return success; +} + +typedef struct { + const guint8 *secret_key; + gsize key_len; + bool is_good:1; +} SecretKeyData; + +gboolean +nm_utils_secret_key_get (const guint8 **out_secret_key, + gsize *out_key_len) +{ + static volatile const SecretKeyData *secret_key_static; + const SecretKeyData *secret_key; + + secret_key = g_atomic_pointer_get (&secret_key_static); + if (G_UNLIKELY (!secret_key)) { + static gsize init_value = 0; + static SecretKeyData secret_key_data; + gboolean tmp_success; + gs_free guint8 *tmp_secret_key = NULL; + gsize tmp_key_len; + + tmp_success = _secret_key_read (&tmp_secret_key, &tmp_key_len); + if (g_once_init_enter (&init_value)) { + secret_key_data.secret_key = tmp_secret_key; + secret_key_data.key_len = tmp_key_len; + secret_key_data.is_good = tmp_success; + + if (g_atomic_pointer_compare_and_exchange (&secret_key_static, NULL, &secret_key_data)) { + g_steal_pointer (&tmp_secret_key); + secret_key = &secret_key_data; + } + + g_once_init_leave (&init_value, 1); + } + if (!secret_key) + secret_key = g_atomic_pointer_get (&secret_key_static); } - g_free (secret_key); - return NULL; + + *out_secret_key = secret_key->secret_key; + *out_key_len = secret_key->key_len; + return secret_key->is_good; } /*****************************************************************************/ @@ -3132,8 +3181,9 @@ _stable_id_append (GString *str, NMUtilsStableType nm_utils_stable_id_parse (const char *stable_id, - const char *uuid, + const char *deviceid, const char *bootid, + const char *uuid, char **out_generated) { gsize i, idx_start; @@ -3208,6 +3258,8 @@ nm_utils_stable_id_parse (const char *stable_id, _stable_id_append (str, uuid); else if (CHECK_PREFIX ("${BOOT}")) _stable_id_append (str, bootid ?: nm_utils_get_boot_id ()); + else if (CHECK_PREFIX ("${DEVICE}")) + _stable_id_append (str, deviceid); else if (g_str_has_prefix (&stable_id[i], "${RANDOM}")) { /* RANDOM makes not so much sense for cloned-mac-address * as the result is simmilar to specyifing "cloned-mac-address=random". @@ -3284,7 +3336,7 @@ _set_stable_privacy (NMUtilsStableType stable_type, const char *ifname, const char *network_id, guint32 dad_counter, - guint8 *secret_key, + const guint8 *secret_key, gsize key_len, GError **error) { @@ -3383,8 +3435,8 @@ nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType stable_type, guint32 dad_counter, GError **error) { - gs_free guint8 *secret_key = NULL; - gsize key_len = 0; + const guint8 *secret_key; + gsize key_len; g_return_val_if_fail (network_id, FALSE); @@ -3394,9 +3446,7 @@ nm_utils_ipv6_addr_set_stable_privacy (NMUtilsStableType stable_type, return FALSE; } - secret_key = nm_utils_secret_key_read (&key_len, error); - if (!secret_key) - return FALSE; + nm_utils_secret_key_get (&secret_key, &key_len); return _set_stable_privacy (stable_type, addr, ifname, network_id, dad_counter, secret_key, key_len, error); @@ -3532,14 +3582,12 @@ nm_utils_hw_addr_gen_stable_eth (NMUtilsStableType stable_type, const char *current_mac_address, const char *generate_mac_address_mask) { - gs_free guint8 *secret_key = NULL; - gsize key_len = 0; + const guint8 *secret_key; + gsize key_len; g_return_val_if_fail (stable_id, NULL); - secret_key = nm_utils_secret_key_read (&key_len, NULL); - if (!secret_key) - return NULL; + nm_utils_secret_key_get (&secret_key, &key_len); return _hw_addr_gen_stable_eth (stable_type, stable_id, @@ -4087,7 +4135,7 @@ nm_utils_read_plugin_paths (const char *dirname, const char *prefix) if (!g_str_has_prefix (item, prefix)) continue; - if (g_str_has_suffix (item, ".la")) + if (!g_str_has_suffix (item, ".so")) continue; data.path = g_build_filename (dirname, item, NULL); @@ -4173,6 +4221,28 @@ nm_utils_parse_dns_domain (const char *domain, gboolean *is_routing) /*****************************************************************************/ +GVariant * +nm_utils_strdict_to_variant (GHashTable *options) +{ + GVariantBuilder builder; + gs_free const char **keys = NULL; + guint i; + guint nkeys; + + keys = nm_utils_strdict_get_keys (options, TRUE, &nkeys); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + for (i = 0; i < nkeys; i++) { + g_variant_builder_add (&builder, + "{sv}", + keys[i], + g_variant_new_string (g_hash_table_lookup (options, keys[i]))); + } + return g_variant_builder_end (&builder); +} + +/*****************************************************************************/ + NM_UTILS_ENUM2STR_DEFINE (nm_icmpv6_router_pref_to_string, NMIcmpv6RouterPref, NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_LOW, "low"), NM_UTILS_ENUM2STR (NM_ICMPV6_ROUTER_PREF_MEDIUM, "medium"), |