diff --git a/shared/nm-glib-aux/nm-shared-utils.c b/shared/nm-glib-aux/nm-shared-utils.c index be9fbdc4ae..8e1c8b5806 100644 --- a/shared/nm-glib-aux/nm-shared-utils.c +++ b/shared/nm-glib-aux/nm-shared-utils.c @@ -683,11 +683,80 @@ nm_utils_ip_is_site_local (int addr_family, /*****************************************************************************/ +static gboolean +_parse_legacy_addr4 (const char *text, in_addr_t *out_addr) +{ + gs_free char *s_free = NULL; + struct in_addr a1; + guint8 bin[sizeof (a1)]; + char *s; + int i; + + if (inet_aton (text, &a1) != 1) + return FALSE; + + /* OK, inet_aton() accepted the format. That's good, because we want + * to accept IPv4 addresses in octal format, like 255.255.000.000. + * That's what "legacy" means here. inet_pton() doesn't accept those. + * + * But inet_aton() also ignores trailing garbage and formats with fewer than + * 4 digits. That is just too crazy and we don't do that. Perform additional checks + * and reject some forms that inet_aton() accepted. + * + * Note that we still should (of course) accept everything that inet_pton() + * accepts. However this code never gets called if inet_pton() succeeds + * (see below, aside the assertion code). */ + + if (NM_STRCHAR_ANY (text, ch, ( !(ch >= '0' && ch <= '9') + && !NM_IN_SET (ch, '.', 'x')))) { + /* We only accepts '.', digits, and 'x' for "0x". */ + return FALSE; + } + + s = nm_memdup_maybe_a (300, text, strlen (text) + 1, &s_free); + + for (i = 0; i < G_N_ELEMENTS (bin); i++) { + char *current_token = s; + gint32 v; + + s = strchr (s, '.'); + if (s) { + s[0] = '\0'; + s++; + } + + if ((i == G_N_ELEMENTS (bin) - 1) != (s == NULL)) { + /* Exactly for the last digit, we expect to have no more following token. + * But this isn't the case. Abort. */ + return FALSE; + } + + v = _nm_utils_ascii_str_to_int64 (current_token, 0, 0, 0xFF, -1); + if (v == -1) { + /* we do accept octal and hex (even with leading "0x"). But something + * about this token is wrong. */ + return FALSE; + } + + bin[i] = v; + } + + if (memcmp (bin, &a1, sizeof (bin)) != 0) { + /* our parsing did not agree with what inet_aton() gave. Something + * is wrong. Abort. */ + return FALSE; + } + + *out_addr = a1.s_addr; + return TRUE; +} + gboolean -nm_utils_parse_inaddr_bin (int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr) +nm_utils_parse_inaddr_bin_full (int addr_family, + gboolean accept_legacy, + const char *text, + int *out_addr_family, + gpointer out_addr) { NMIPAddr addrbin; @@ -699,8 +768,26 @@ nm_utils_parse_inaddr_bin (int addr_family, } else g_return_val_if_fail (NM_IN_SET (addr_family, AF_INET, AF_INET6), FALSE); - if (inet_pton (addr_family, text, &addrbin) != 1) - return FALSE; + if (inet_pton (addr_family, text, &addrbin) != 1) { + if ( accept_legacy + && addr_family == AF_INET + && _parse_legacy_addr4 (text, &addrbin.addr4)) { + /* The address is in some legacy format which inet_aton() accepts, but not inet_pton(). + * Most likely octal digits (leading zeros). We accept the address. */ + } else + return FALSE; + } + +#if NM_MORE_ASSERTS > 10 + if (addr_family == AF_INET) { + in_addr_t a; + + /* The legacy parser should accept everything that inet_pton() accepts too. Meaning, + * it should strictly parse *more* formats. And of course, parse it the same way. */ + nm_assert (_parse_legacy_addr4 (text, &a)); + nm_assert (addrbin.addr4 == a); + } +#endif NM_SET_OUT (out_addr_family, addr_family); if (out_addr) diff --git a/shared/nm-glib-aux/nm-shared-utils.h b/shared/nm-glib-aux/nm-shared-utils.h index bbbb9b64be..3bd1afaea3 100644 --- a/shared/nm-glib-aux/nm-shared-utils.h +++ b/shared/nm-glib-aux/nm-shared-utils.h @@ -89,6 +89,16 @@ nm_utils_addr_family_to_size (int addr_family) g_return_val_if_reached (0); } +static inline int +nm_utils_addr_family_from_size (gsize len) +{ + switch (len) { + case sizeof (in_addr_t): return AF_INET; + case sizeof (struct in6_addr): return AF_INET6; + } + return AF_UNSPEC; +} + #define nm_assert_addr_family(addr_family) \ nm_assert (NM_IN_SET ((addr_family), AF_INET, AF_INET6)) @@ -532,10 +542,19 @@ gboolean nm_utils_ip_is_site_local (int addr_family, /*****************************************************************************/ -gboolean nm_utils_parse_inaddr_bin (int addr_family, - const char *text, - int *out_addr_family, - gpointer out_addr); +gboolean nm_utils_parse_inaddr_bin_full (int addr_family, + gboolean accept_legacy, + const char *text, + int *out_addr_family, + gpointer out_addr); +static inline gboolean +nm_utils_parse_inaddr_bin (int addr_family, + const char *text, + int *out_addr_family, + gpointer out_addr) +{ + return nm_utils_parse_inaddr_bin_full (addr_family, FALSE, text, out_addr_family, out_addr); +} gboolean nm_utils_parse_inaddr (int addr_family, const char *text, diff --git a/src/initrd/nmi-dt-reader.c b/src/initrd/nmi-dt-reader.c index d2e571d7a8..a8677ed9c3 100644 --- a/src/initrd/nmi-dt-reader.c +++ b/src/initrd/nmi-dt-reader.c @@ -51,40 +51,24 @@ dt_get_ipaddr_property (const char *base, const char *prop, int *family) { - NMIPAddress *addr; gs_free char *buf = NULL; size_t len; - gs_free_error GError *error = NULL; + int f; if (!dt_get_property (base, dev, prop, &buf, &len)) return NULL; - switch (len) { - case 4: - if (*family == AF_UNSPEC) - *family = AF_INET; - break; - case 16: - if (*family == AF_UNSPEC) - *family = AF_INET6; - break; - default: - break; - } - - if (*family == AF_UNSPEC) { + f = nm_utils_addr_family_from_size (len); + if ( f == AF_UNSPEC + || ( *family != AF_UNSPEC + && *family != f)) { _LOGW (LOGD_CORE, "%s: Address %s has unrecognized length (%zd)", dev, prop, len); return NULL; } - addr = nm_ip_address_new_binary (*family, buf, 0, &error); - if (!addr) { - _LOGW (LOGD_CORE, "%s: Address %s is malformed: %s", - dev, prop, error->message); - } - - return addr; + *family = f; + return nm_ip_address_new_binary (f, buf, 0, NULL); } static char * @@ -112,30 +96,23 @@ dt_get_hwaddr_property (const char *base, static NMIPAddress * str_addr (const char *str, int *family) { - struct in_addr inp; + NMIPAddr addr_bin; - if (*family == AF_UNSPEC) - *family = guess_ip_address_family (str); - - if (*family == AF_UNSPEC) { + if (!nm_utils_parse_inaddr_bin_full (*family, + TRUE, + str, + family, + &addr_bin)) { _LOGW (LOGD_CORE, "Malformed IP address: '%s'", str); return NULL; } - - if (*family == AF_INET && inet_aton (str, &inp)) { - /* For IPv4, we need to be more tolerant than - * nm_ip_address_new(), to recognize things like - * the extra zeroes in "255.255.255.000" */ - return nm_ip_address_new_binary (*family, &inp, 0, NULL); - } - - return nm_ip_address_new (*family, str, 0, NULL); + return nm_ip_address_new_binary (*family, &addr_bin, 0, NULL); } NMConnection * nmi_dt_reader_parse (const char *sysfs_dir) { - NMConnection *connection; + gs_unref_object NMConnection *connection = NULL; gs_free char *base = NULL; gs_free char *bootpath = NULL; gs_strfreev char **tokens = NULL; @@ -144,9 +121,8 @@ nmi_dt_reader_parse (const char *sysfs_dir) const char *s_ipaddr = NULL; const char *s_netmask = NULL; const char *s_gateway = NULL; - NMIPAddress *ipaddr = NULL; - NMIPAddress *netmask = NULL; - NMIPAddress *gateway = NULL; + nm_auto_unref_ip_address NMIPAddress *ipaddr = NULL; + nm_auto_unref_ip_address NMIPAddress *gateway = NULL; const char *duplex = NULL; gs_free char *hwaddr = NULL; gs_free char *local_hwaddr = NULL; @@ -279,10 +255,10 @@ nmi_dt_reader_parse (const char *sysfs_dir) connection = nm_simple_connection_new (); nm_connection_add_setting (connection, - g_object_new (NM_TYPE_SETTING_CONNECTION, - NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, - NM_SETTING_CONNECTION_ID, "OpenFirmware Connection", - NULL)); + g_object_new (NM_TYPE_SETTING_CONNECTION, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, + NM_SETTING_CONNECTION_ID, "OpenFirmware Connection", + NULL)); s_ip4 = nm_setting_ip4_config_new (); nm_connection_add_setting (connection, s_ip4); @@ -298,6 +274,8 @@ nmi_dt_reader_parse (const char *sysfs_dir) bootp = TRUE; if (!bootp) { + nm_auto_unref_ip_address NMIPAddress *netmask = NULL; + netmask = dt_get_ipaddr_property (base, "chosen", "netmask-ip", &family); gateway = dt_get_ipaddr_property (base, "chosen", "gateway-ip", &family); if (gateway) @@ -305,9 +283,9 @@ nmi_dt_reader_parse (const char *sysfs_dir) ipaddr = dt_get_ipaddr_property (base, "chosen", "client-ip", &family); if (family == AF_UNSPEC) { - g_warn_if_fail (netmask == NULL); - g_warn_if_fail (ipaddr == NULL); - g_warn_if_fail (gateway == NULL); + nm_assert (netmask == NULL); + nm_assert (gateway == NULL); + nm_assert (ipaddr == NULL); netmask = str_addr (s_netmask, &family); ipaddr = str_addr (s_ipaddr, &family); @@ -326,11 +304,6 @@ nmi_dt_reader_parse (const char *sysfs_dir) _LOGW (LOGD_CORE, "Unable to determine the network prefix"); else nm_ip_address_set_prefix (ipaddr, prefix); - - if (netmask) - nm_ip_address_unref (netmask); - if (gateway) - nm_ip_address_unref (gateway); } if (!ipaddr) { @@ -375,9 +348,6 @@ nmi_dt_reader_parse (const char *sysfs_dir) g_object_set (s_ip, NM_SETTING_IP_CONFIG_GATEWAY, s_gateway, NULL); } - if (ipaddr) - nm_ip_address_unref (ipaddr); - if (duplex || speed || hwaddr || local_hwaddr) { s_wired = nm_setting_wired_new (); nm_connection_add_setting (connection, s_wired); @@ -390,11 +360,11 @@ nmi_dt_reader_parse (const char *sysfs_dir) NULL); } - if (!nm_connection_normalize (connection, NULL, NULL, &error)) { + if (!nm_connection_normalize (connection, NULL, NULL, &error)) { _LOGW (LOGD_CORE, "Generated an invalid connection: %s", error->message); g_clear_pointer (&connection, g_object_unref); } - return connection; + return g_steal_pointer (&connection); }