diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 6f4da1adc..8b36bbd27 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -214,13 +214,25 @@ const char *nm_utils_hwaddr_ntoa_buf (gconstpointer addr, gsize addr_len, gboole char *_nm_utils_bin2hexstr_full (gconstpointer addr, gsize length, const char delimiter, gboolean upper_case, char *out); -guint8 *_nm_utils_hexstr2bin_full (const char *asc, +guint8 *_nm_utils_hexstr2bin_full (const char *hexstr, + gboolean allow_0x_prefix, gboolean delimiter_required, const char *delimiter_candidates, + gsize required_len, guint8 *buffer, - gsize buffer_length, + gsize buffer_len, gsize *out_len); +#define _nm_utils_hexstr2bin_buf(hexstr, allow_0x_prefix, delimiter_required, delimiter_candidates, buffer) \ + _nm_utils_hexstr2bin_full ((hexstr), (allow_0x_prefix), (delimiter_required), (delimiter_candidates), G_N_ELEMENTS (buffer), (buffer), G_N_ELEMENTS (buffer), NULL) + +guint8 *_nm_utils_hexstr2bin_alloc (const char *hexstr, + gboolean allow_0x_prefix, + gboolean delimiter_required, + const char *delimiter_candidates, + gsize required_len, + gsize *out_len); + GSList * _nm_utils_hash_values_to_slist (GHashTable *hash); GHashTable *_nm_utils_copy_strdict (GHashTable *strdict); diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 8b22dffdb..724c1a6c2 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -3527,60 +3527,68 @@ nm_utils_hwaddr_len (int type) } guint8 * -_nm_utils_hexstr2bin_full (const char *asc, +_nm_utils_hexstr2bin_full (const char *hexstr, + gboolean allow_0x_prefix, gboolean delimiter_required, const char *delimiter_candidates, + gsize required_len, guint8 *buffer, - gsize buffer_length, + gsize buffer_len, gsize *out_len) { - const char *in = asc; + const char *in = hexstr; guint8 *out = buffer; gboolean delimiter_has = TRUE; guint8 delimiter = '\0'; + gsize len; - nm_assert (asc); + nm_assert (hexstr); nm_assert (buffer); - nm_assert (buffer_length); - nm_assert (out_len); + nm_assert (required_len > 0 || out_len); + + if ( allow_0x_prefix + && in[0] == '0' + && in[1] == 'x') + in += 2; while (TRUE) { const guint8 d1 = in[0]; guint8 d2; + int i1, i2; - if (!g_ascii_isxdigit (d1)) - return NULL; - -#define HEXVAL(c) ((c) <= '9' ? (c) - '0' : ((c) & 0x4F) - ('A' - 10)) + i1 = nm_utils_hexchar_to_int (d1); + if (i1 < 0) + goto fail; /* If there's no leading zero (ie "aa:b:cc") then fake it */ d2 = in[1]; - if (d2 && g_ascii_isxdigit (d2)) { - *out++ = (HEXVAL (d1) << 4) + HEXVAL (d2); + if ( d2 + && (i2 = nm_utils_hexchar_to_int (d2)) >= 0) { + *out++ = (i1 << 4) + i2; d2 = in[2]; if (!d2) break; in += 2; } else { /* Fake leading zero */ - *out++ = HEXVAL (d1); + *out++ = i1; if (!d2) { if (!delimiter_has) { /* when using no delimiter, there must be pairs of hex chars */ - return NULL; + goto fail; } break; } in += 1; } - if (--buffer_length == 0) - return NULL; + if (--buffer_len == 0) + goto fail; if (delimiter_has) { if (d2 != delimiter) { if (delimiter) - return NULL; + goto fail; if (delimiter_candidates) { while (delimiter_candidates[0]) { if (delimiter_candidates++[0] == d2) @@ -3589,7 +3597,7 @@ _nm_utils_hexstr2bin_full (const char *asc, } if (!delimiter) { if (delimiter_required) - return NULL; + goto fail; delimiter_has = FALSE; continue; } @@ -3598,11 +3606,66 @@ _nm_utils_hexstr2bin_full (const char *asc, } } - *out_len = out - buffer; - return buffer; + len = out - buffer; + if ( required_len == 0 + || len == required_len) { + NM_SET_OUT (out_len, len); + return buffer; + } + +fail: + NM_SET_OUT (out_len, 0); + return NULL; } -#define hwaddr_aton(asc, buffer, buffer_length, out_len) _nm_utils_hexstr2bin_full ((asc), TRUE, ":-", (buffer), (buffer_length), (out_len)) +guint8 * +_nm_utils_hexstr2bin_alloc (const char *hexstr, + gboolean allow_0x_prefix, + gboolean delimiter_required, + const char *delimiter_candidates, + gsize required_len, + gsize *out_len) +{ + guint8 *buffer; + gsize buffer_len, len; + + g_return_val_if_fail (hexstr, NULL); + + nm_assert (required_len > 0 || out_len); + + if ( allow_0x_prefix + && hexstr[0] == '0' + && hexstr[1] == 'x') + hexstr += 2; + + if (!hexstr[0]) + goto fail; + + if (required_len > 0) + buffer_len = required_len; + else + buffer_len = strlen (hexstr) / 2 + 3; + + buffer = g_malloc (buffer_len); + + if (_nm_utils_hexstr2bin_full (hexstr, + FALSE, + delimiter_required, + delimiter_candidates, + required_len, + buffer, + buffer_len, + &len)) { + NM_SET_OUT (out_len, len); + return buffer; + } + + g_free (buffer); + +fail: + NM_SET_OUT (out_len, 0); + return NULL; +} /** * nm_utils_hexstr2bin: @@ -3619,23 +3682,17 @@ GBytes * nm_utils_hexstr2bin (const char *hex) { guint8 *buffer; - gsize buffer_length, len; + gsize len; - g_return_val_if_fail (hex != NULL, NULL); - - if (hex[0] == '0' && hex[1] == 'x') - hex += 2; - - buffer_length = strlen (hex) / 2 + 3; - buffer = g_malloc (buffer_length); - if (!_nm_utils_hexstr2bin_full (hex, FALSE, ":", buffer, buffer_length, &len)) { - g_free (buffer); + buffer = _nm_utils_hexstr2bin_alloc (hex, TRUE, FALSE, ":", 0, &len); + if (!buffer) return NULL; - } buffer = g_realloc (buffer, len); return g_bytes_new_take (buffer, len); } +#define hwaddr_aton(asc, buffer, buffer_len, out_len) _nm_utils_hexstr2bin_full ((asc), FALSE, TRUE, ":-", 0, (buffer), (buffer_len), (out_len)) + /** * nm_utils_hwaddr_atoba: * @asc: the ASCII representation of a hardware address @@ -4514,7 +4571,7 @@ _nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin) return TRUE; } - if (_nm_utils_hexstr2bin_full (duid, FALSE, ":", duid_arr, sizeof (duid_arr), &duid_len)) { + if (_nm_utils_hexstr2bin_full (duid, FALSE, FALSE, ":", 0, duid_arr, sizeof (duid_arr), &duid_len)) { /* MAX DUID length is 128 octects + the type code (2 octects). */ if ( duid_len > 2 && duid_len <= (128 + 2)) { diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 0b9fe95af..a3a878e10 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -189,7 +189,7 @@ _secret_password_raw_to_bytes (const char *ifcfg_key, password_raw += 2; secret = nm_secret_buf_new (strlen (password_raw) / 2 + 3); - if (!_nm_utils_hexstr2bin_full (password_raw, FALSE, ":", secret->bin, secret->len, &len)) { + if (!_nm_utils_hexstr2bin_full (password_raw, FALSE, FALSE, ":", 0, secret->bin, secret->len, &len)) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid hex password in %s", ifcfg_key);