diff options
Diffstat (limited to 'src/nm-core-utils.c')
| -rw-r--r-- | src/nm-core-utils.c | 168 |
1 files changed, 122 insertions, 46 deletions
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index bbe46654..ef44a139 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -2559,6 +2559,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) @@ -2686,7 +2801,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 +2859,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 +2868,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); } /** |