diff options
Diffstat (limited to 'src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c')
| -rw-r--r-- | src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 652 |
1 files changed, 372 insertions, 280 deletions
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 66add713..b9900eec 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -15,7 +15,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * - * Copyright 2008 - 2015 Red Hat, Inc. + * Copyright 2008 - 2017 Red Hat, Inc. */ #include "nm-default.h" @@ -77,18 +77,6 @@ /*****************************************************************************/ -static gboolean -get_uint (const char *str, guint32 *value) -{ - gint64 tmp; - - tmp = _nm_utils_ascii_str_to_int64 (str, 0, 0, G_MAXUINT32, -1); - if (tmp == -1) - return FALSE; - *value = tmp; - return TRUE; -} - static void check_if_bond_slave (shvarFile *ifcfg, NMSettingConnection *s_con) @@ -512,13 +500,13 @@ typedef struct { bool int_base_16:1; - /* the type, one of PARSE_LINE_TYPE_* */ - char type; - /* whether the command line option was found, and @v is * initialized. */ bool has:1; + /* the type, one of PARSE_LINE_TYPE_* */ + char type; + union { guint8 uint8; guint32 uint32; @@ -541,6 +529,7 @@ enum { PARSE_LINE_ATTR_ROUTE_SRC, PARSE_LINE_ATTR_ROUTE_FROM, PARSE_LINE_ATTR_ROUTE_TOS, + PARSE_LINE_ATTR_ROUTE_ONLINK, PARSE_LINE_ATTR_ROUTE_WINDOW, PARSE_LINE_ATTR_ROUTE_CWND, PARSE_LINE_ATTR_ROUTE_INITCWND, @@ -562,6 +551,7 @@ enum { #define PARSE_LINE_TYPE_ADDR 'a' #define PARSE_LINE_TYPE_ADDR_WITH_PREFIX 'p' #define PARSE_LINE_TYPE_IFNAME 'i' +#define PARSE_LINE_TYPE_FLAG 'f' /** * parse_route_line: @@ -601,42 +591,45 @@ parse_route_line (const char *line, char buf1[256]; char buf2[256]; ParseLineInfo infos[] = { - [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, - .type = PARSE_LINE_TYPE_UINT32, }, - [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, - .type = PARSE_LINE_TYPE_ADDR, }, - [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, - .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (addr_family != AF_INET6), }, - [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, - .type = PARSE_LINE_TYPE_UINT8, - .int_base_16 = TRUE, - .ignore = (addr_family != AF_INET), }, - [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, - .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, - - [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", - .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, - .disabled = (options_route != NULL), }, - [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", - .type = PARSE_LINE_TYPE_ADDR, - .disabled = (options_route != NULL), }, - [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", - .type = PARSE_LINE_TYPE_UINT32, - .disabled = (options_route != NULL), }, - - [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", - .type = PARSE_LINE_TYPE_IFNAME, - .ignore = TRUE, - .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_TABLE] = { .key = NM_IP_ROUTE_ATTRIBUTE_TABLE, + .type = PARSE_LINE_TYPE_UINT32, }, + [PARSE_LINE_ATTR_ROUTE_SRC] = { .key = NM_IP_ROUTE_ATTRIBUTE_SRC, + .type = PARSE_LINE_TYPE_ADDR, }, + [PARSE_LINE_ATTR_ROUTE_FROM] = { .key = NM_IP_ROUTE_ATTRIBUTE_FROM, + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (addr_family != AF_INET6), }, + [PARSE_LINE_ATTR_ROUTE_TOS] = { .key = NM_IP_ROUTE_ATTRIBUTE_TOS, + .type = PARSE_LINE_TYPE_UINT8, + .int_base_16 = TRUE, + .ignore = (addr_family != AF_INET), }, + [PARSE_LINE_ATTR_ROUTE_ONLINK] = { .key = NM_IP_ROUTE_ATTRIBUTE_ONLINK, + .type = PARSE_LINE_TYPE_FLAG, + .ignore = (addr_family != AF_INET), }, + [PARSE_LINE_ATTR_ROUTE_WINDOW] = { .key = NM_IP_ROUTE_ATTRIBUTE_WINDOW, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_CWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_CWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITCWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITCWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_INITRWND] = { .key = NM_IP_ROUTE_ATTRIBUTE_INITRWND, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + [PARSE_LINE_ATTR_ROUTE_MTU] = { .key = NM_IP_ROUTE_ATTRIBUTE_MTU, + .type = PARSE_LINE_TYPE_UINT32_WITH_LOCK, }, + + [PARSE_LINE_ATTR_ROUTE_TO] = { .key = "to", + .type = PARSE_LINE_TYPE_ADDR_WITH_PREFIX, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_VIA] = { .key = "via", + .type = PARSE_LINE_TYPE_ADDR, + .disabled = (options_route != NULL), }, + [PARSE_LINE_ATTR_ROUTE_METRIC] = { .key = "metric", + .type = PARSE_LINE_TYPE_UINT32, + .disabled = (options_route != NULL), }, + + [PARSE_LINE_ATTR_ROUTE_DEV] = { .key = "dev", + .type = PARSE_LINE_TYPE_IFNAME, + .ignore = TRUE, + .disabled = (options_route != NULL), }, }; nm_assert (line); @@ -705,6 +698,9 @@ parse_route_line (const char *line, case PARSE_LINE_TYPE_IFNAME: i_words++; goto parse_line_type_ifname; + case PARSE_LINE_TYPE_FLAG: + i_words++; + goto next; default: nm_assert_not_reached (); } @@ -913,6 +909,15 @@ next: ? nm_sprintf_buf (buf2, "/%u", (unsigned) info->v.addr.plen) : "")); break; + case PARSE_LINE_TYPE_FLAG: + /* XXX: the flag (for "onlink") only allows to explictly set "TRUE". + * There is no way to express an explicit "FALSE" setting + * of this attribute, hence, the file format cannot encode + * that configuration. */ + nm_ip_route_set_attribute (route, + info->key, + g_variant_new_boolean (TRUE)); + break; default: nm_assert_not_reached (); break; @@ -1141,7 +1146,7 @@ error: } static NMSetting * -make_user_setting (shvarFile *ifcfg, GError **error) +make_user_setting (shvarFile *ifcfg) { gboolean has_user_data = FALSE; gs_unref_object NMSettingUser *s_user = NULL; @@ -1189,7 +1194,7 @@ make_user_setting (shvarFile *ifcfg, GError **error) } static NMSetting * -make_proxy_setting (shvarFile *ifcfg, GError **error) +make_proxy_setting (shvarFile *ifcfg) { NMSettingProxy *s_proxy = NULL; gs_free char *value = NULL; @@ -1239,7 +1244,7 @@ make_proxy_setting (shvarFile *ifcfg, GError **error) static NMSetting * make_ip4_setting (shvarFile *ifcfg, - const char *network_file, + shvarFile *network_ifcfg, gboolean routes_read, gboolean *out_has_defroute, GError **error) @@ -1255,7 +1260,6 @@ make_ip4_setting (shvarFile *ifcfg, int i; guint32 a; gboolean has_key; - shvarFile *network_ifcfg; shvarFile *route_ifcfg; gboolean never_default; gint64 timeout; @@ -1282,7 +1286,6 @@ make_ip4_setting (shvarFile *ifcfg, } /* Then check if GATEWAYDEV; it's global and overrides DEFROUTE */ - network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { gs_free char *gatewaydev_value = NULL; const char *gatewaydev; @@ -1299,7 +1302,6 @@ make_ip4_setting (shvarFile *ifcfg, never_default = !!strcmp (v, gatewaydev); nm_clear_g_free (&value); - svCloseFile (network_ifcfg); } v = svGetValueStr (ifcfg, "BOOTPROTO", &value); @@ -1424,12 +1426,10 @@ make_ip4_setting (shvarFile *ifcfg, /* Gateway */ if (!gateway) { - network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { gboolean read_success; read_success = read_ip4_address (network_ifcfg, "GATEWAY", &has_key, &a, error); - svCloseFile (network_ifcfg); if (!read_success) return NULL; if (has_key) { @@ -1665,16 +1665,15 @@ read_aliases (NMSettingIPConfig *s_ip4, gboolean read_defroute, const char *file static NMSetting * make_ip6_setting (shvarFile *ifcfg, - const char *network_file, + shvarFile *network_ifcfg, gboolean routes_read, GError **error) { NMSettingIPConfig *s_ip6 = NULL; + const char *v; char *value = NULL; char *str_value; char *route6_path = NULL; - gs_free char *dns_options_free = NULL; - const char *dns_options = NULL; gboolean ipv6init, ipv6forwarding, dhcp6 = FALSE; char *method = NM_SETTING_IP6_CONFIG_METHOD_MANUAL; char *ipv6addr, *ipv6addr_secondaries; @@ -1684,7 +1683,6 @@ make_ip6_setting (shvarFile *ifcfg, int i_val; GError *local = NULL; gint priority; - shvarFile *network_ifcfg; gboolean never_default = FALSE; gboolean ip6_privacy = FALSE, ip6_privacy_prefer_public_ip; NMSettingIP6ConfigPrivacy ip6_privacy_val; @@ -1703,7 +1701,6 @@ make_ip6_setting (shvarFile *ifcfg, * they are global and override IPV6_DEFROUTE * When both are set, the device specified in IPV6_DEFAULTGW takes preference. */ - network_ifcfg = svOpenFile (network_file, NULL); if (network_ifcfg) { char *ipv6_defaultgw, *ipv6_defaultdev; char *default_dev = NULL; @@ -1712,7 +1709,6 @@ make_ip6_setting (shvarFile *ifcfg, value = svGetValueStr_cp (ifcfg, "DEVICE"); ipv6_defaultgw = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); ipv6_defaultdev = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTDEV"); - dns_options = svGetValue (network_ifcfg, "RES_OPTIONS", &dns_options_free); if (ipv6_defaultgw) { default_dev = strchr (ipv6_defaultgw, '%'); @@ -1731,7 +1727,6 @@ make_ip6_setting (shvarFile *ifcfg, g_free (ipv6_defaultgw); g_free (ipv6_defaultdev); g_free (value); - svCloseFile (network_ifcfg); } /* Find out method property */ @@ -1739,11 +1734,8 @@ make_ip6_setting (shvarFile *ifcfg, str_value = svGetValueStr_cp (ifcfg, "IPV6INIT"); ipv6init = svGetValueBoolean (ifcfg, "IPV6INIT", FALSE); if (!str_value) { - network_ifcfg = svOpenFile (network_file, NULL); - if (network_ifcfg) { + if (network_ifcfg) ipv6init = svGetValueBoolean (network_ifcfg, "IPV6INIT", FALSE); - svCloseFile (network_ifcfg); - } } g_free (str_value); @@ -1865,11 +1857,8 @@ make_ip6_setting (shvarFile *ifcfg, value = svGetValueStr_cp (ifcfg, "IPV6_DEFAULTGW"); if (!value) { /* If no gateway in the ifcfg, try global /etc/sysconfig/network instead */ - network_ifcfg = svOpenFile (network_file, NULL); - if (network_ifcfg) { + if (network_ifcfg) value = svGetValueStr_cp (network_ifcfg, "IPV6_DEFAULTGW"); - svCloseFile (network_ifcfg); - } } if (value) { char *ptr; @@ -1930,8 +1919,6 @@ make_ip6_setting (shvarFile *ifcfg, g_free (value); } - /* DNS searches ('DOMAIN' key) are read by make_ip4_setting() and included in NMSettingIPConfig */ - if (!routes_read) { /* NOP */ } else { @@ -1942,9 +1929,24 @@ make_ip6_setting (shvarFile *ifcfg, g_free (route6_path); } + /* DNS searches */ + nm_clear_g_free (&value); + v = svGetValueStr (ifcfg, "IPV6_DOMAIN", &value); + if (v) { + gs_free const char **searches = NULL; + + searches = nm_utils_strsplit_set (v, " "); + if (searches) { + for (iter = searches; *iter; iter++) { + if (!nm_setting_ip_config_add_dns_search (s_ip6, *iter)) + PARSE_WARNING ("duplicate DNS domain '%s'", *iter); + } + } + } + /* DNS options */ - parse_dns_options (s_ip6, svGetValue (ifcfg, "RES_OPTIONS", &value)); - parse_dns_options (s_ip6, dns_options); + nm_clear_g_free (&value); + parse_dns_options (s_ip6, svGetValue (ifcfg, "IPV6_RES_OPTIONS", &value)); g_free (value); /* DNS priority */ @@ -1962,6 +1964,59 @@ error: return NULL; } +static NMSetting * +make_tc_setting (shvarFile *ifcfg) +{ + NMSettingTCConfig *s_tc = NULL; + char tag[256]; + int i; + + s_tc = (NMSettingTCConfig *) nm_setting_tc_config_new (); + + for (i = 1;; i++) { + NMTCQdisc *qdisc = NULL; + gs_free char *value_to_free = NULL; + const char *value = NULL; + GError *local = NULL; + + value = svGetValueStr (ifcfg, numbered_tag (tag, "QDISC", i), &value_to_free); + if (!value) + break; + + qdisc = nm_utils_tc_qdisc_from_str (value, &local); + if (!qdisc) + PARSE_WARNING ("ignoring bad qdisc: '%s': %s", value, local->message); + + if (!nm_setting_tc_config_add_qdisc (s_tc, qdisc)) + PARSE_WARNING ("duplicate qdisc"); + } + + for (i = 1;; i++) { + NMTCTfilter *tfilter = NULL; + gs_free char *value_to_free = NULL; + const char *value = NULL; + GError *local = NULL; + + value = svGetValueStr (ifcfg, numbered_tag (tag, "FILTER", i), &value_to_free); + if (!value) + break; + + tfilter = nm_utils_tc_tfilter_from_str (value, &local); + if (!tfilter) + PARSE_WARNING ("ignoring bad tfilter: '%s': %s", value, local->message); + + if (!nm_setting_tc_config_add_tfilter (s_tc, tfilter)) + PARSE_WARNING ("duplicate filter"); + } + + if ( nm_setting_tc_config_get_num_qdiscs (s_tc) > 0 + || nm_setting_tc_config_get_num_tfilters (s_tc) > 0) + return NM_SETTING (s_tc); + + g_object_unref (s_tc); + return NULL; +} + typedef struct { const char *enable_key; const char *advertise_key; @@ -2195,7 +2250,6 @@ read_dcb_percent_array (shvarFile *ifcfg, static gboolean make_dcb_setting (shvarFile *ifcfg, - const char *network_file, NMSetting **out_setting, GError **error) { @@ -2350,54 +2404,39 @@ add_one_wep_key (shvarFile *ifcfg, NMSettingWirelessSecurity *s_wsec, GError **error) { - char *key = NULL; - char *value = NULL; - gboolean success = FALSE; + gs_free char *value_free = NULL; + const char *value; + const char *key = NULL; g_return_val_if_fail (ifcfg != NULL, FALSE); g_return_val_if_fail (shvar_key != NULL, FALSE); g_return_val_if_fail (key_idx <= 3, FALSE); g_return_val_if_fail (s_wsec != NULL, FALSE); - value = svGetValueStr_cp (ifcfg, shvar_key); + value = svGetValueStr (ifcfg, shvar_key, &value_free); if (!value) return TRUE; /* Validate keys */ if (passphrase) { - if (strlen (value) && strlen (value) < 64) { - key = g_strdup (value); - g_object_set (G_OBJECT (s_wsec), - NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, - NM_WEP_KEY_TYPE_PASSPHRASE, - NULL); - } + if (value[0] && strlen (value) < 64) + key = value; } else { - if (strlen (value) == 10 || strlen (value) == 26) { + if (NM_IN_SET (strlen (value), 10, 26)) { /* Hexadecimal WEP key */ - char *p = value; - - while (*p) { - if (!g_ascii_isxdigit (*p)) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid hexadecimal WEP key."); - goto out; - } - p++; + if (NM_STRCHAR_ANY (value, ch, !g_ascii_isxdigit (ch))) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid hexadecimal WEP key."); + return FALSE; } - key = g_strdup (value); + key = value; } else if ( !strncmp (value, "s:", 2) - && (strlen (value) == 7 || strlen (value) == 15)) { + && NM_IN_SET (strlen (value), 7, 15)) { /* ASCII key */ - char *p = value + 2; - - while (*p) { - if (!g_ascii_isprint ((int) (*p))) { - g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, - "Invalid ASCII WEP key."); - goto out; - } - p++; + if (NM_STRCHAR_ANY (value + 2, ch, !g_ascii_isprint (ch))) { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid ASCII WEP key."); + return FALSE; } /* Remove 's:' prefix. @@ -2406,51 +2445,50 @@ add_one_wep_key (shvarFile *ifcfg, * before passing to wpa_supplicant, this prevents two unnecessary conversions. And mainly, * ASCII WEP key doesn't change to HEX WEP key in UI, which could confuse users. */ - key = g_strdup (value + 2); + key = value + 2; } } - if (key) { - nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); - g_free (key); - success = TRUE; - } else { + if (!key) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "Invalid WEP key length."); + return FALSE; } -out: - g_free (value); - return success; + nm_setting_wireless_security_set_wep_key (s_wsec, key_idx, key); + return TRUE; } static gboolean read_wep_keys (shvarFile *ifcfg, + NMWepKeyType key_type, guint8 def_idx, NMSettingWirelessSecurity *s_wsec, GError **error) { - /* Try hex/ascii keys first */ - if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error)) - return FALSE; + if (key_type != NM_WEP_KEY_TYPE_PASSPHRASE) { + if (!add_one_wep_key (ifcfg, "KEY1", 0, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY2", 1, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY3", 2, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY4", 3, FALSE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY", def_idx, FALSE, s_wsec, error)) + return FALSE; + } - /* And then passphrases */ - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error)) - return FALSE; - if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error)) - return FALSE; + if (key_type != NM_WEP_KEY_TYPE_KEY) { + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE1", 0, TRUE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE2", 1, TRUE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE3", 2, TRUE, s_wsec, error)) + return FALSE; + if (!add_one_wep_key (ifcfg, "KEY_PASSPHRASE4", 3, TRUE, s_wsec, error)) + return FALSE; + } return TRUE; } @@ -2515,19 +2553,40 @@ make_wep_setting (shvarFile *ifcfg, /* Read keys in the ifcfg file if they are system-owned */ if (key_flags == NM_SETTING_SECRET_FLAG_NONE) { - if (!read_wep_keys (ifcfg, default_key_idx, s_wsec, error)) + NMWepKeyType key_type; + const char *v; + gs_free char *to_free = NULL; + + v = svGetValueStr (ifcfg, "KEY_TYPE", &to_free); + if (!v) + key_type = NM_WEP_KEY_TYPE_UNKNOWN; + else if (nm_streq (v, "key")) + key_type = NM_WEP_KEY_TYPE_KEY; + else if (nm_streq (v, "passphrase")) + key_type = NM_WEP_KEY_TYPE_PASSPHRASE; + else { + g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, + "Invalid KEY_TYPE value '%s'", v); + return FALSE; + } + + if (!read_wep_keys (ifcfg, key_type, default_key_idx, s_wsec, error)) return NULL; /* Try to get keys from the "shadow" key file */ keys_ifcfg = utils_get_keys_ifcfg (file, FALSE); if (keys_ifcfg) { - if (!read_wep_keys (keys_ifcfg, default_key_idx, s_wsec, error)) { + if (!read_wep_keys (keys_ifcfg, key_type, default_key_idx, s_wsec, error)) { svCloseFile (keys_ifcfg); return NULL; } svCloseFile (keys_ifcfg); g_assert (error == NULL || *error == NULL); } + + g_object_set (G_OBJECT (s_wsec), + NM_SETTING_WIRELESS_SECURITY_WEP_KEY_TYPE, key_type, + NULL); } value = svGetValueStr_cp (ifcfg, "SECURITYMODE"); @@ -3577,25 +3636,25 @@ make_wireless_security_setting (shvarFile *ifcfg, return NULL; /* unencrypted */ } -static char ** +static const char ** transform_hwaddr_blacklist (const char *blacklist) { - char **strv, **iter; - int shift = 0; - - strv = _nm_utils_strsplit_set (blacklist, " \t", 0); - for (iter = strv; iter && *iter; iter++) { - if (shift) { - *(iter - shift) = *iter; - *iter = NULL; - } - if (!nm_utils_hwaddr_valid (*(iter - shift), ETH_ALEN)) { - PARSE_WARNING ("invalid MAC in HWADDR_BLACKLIST '%s'", *(iter - shift)); - g_free (*(iter - shift)); - *(iter - shift) = NULL; - shift++; + const char **strv; + gsize i, j; + + strv = nm_utils_strsplit_set (blacklist, " \t"); + if (!strv) + return NULL; + for (i = 0, j = 0; strv[j]; j++) { + const char *s = strv[j]; + + if (!nm_utils_hwaddr_valid (s, ETH_ALEN)) { + PARSE_WARNING ("invalid MAC in HWADDR_BLACKLIST '%s'", s); + continue; } + strv[i++] = s; } + strv[i] = NULL; return strv; } @@ -3630,13 +3689,12 @@ make_wireless_setting (shvarFile *ifcfg, g_object_set (s_wireless, NM_SETTING_WIRELESS_GENERATE_MAC_ADDRESS_MASK, value, NULL); g_free (value); - value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST"); - if (value) { - char **strv; + cvalue = svGetValueStr (ifcfg, "HWADDR_BLACKLIST", &value); + if (cvalue) { + gs_free const char **strv = NULL; - strv = transform_hwaddr_blacklist (value); + strv = transform_hwaddr_blacklist (cvalue); g_object_set (s_wireless, NM_SETTING_WIRELESS_MAC_ADDRESS_BLACKLIST, strv, NULL); - g_strfreev (strv); g_free (value); } @@ -4096,6 +4154,7 @@ make_wired_setting (shvarFile *ifcfg, GError **error) { gs_unref_object NMSettingWired *s_wired = NULL; + const char *cvalue; gs_free char *value = NULL; char *nettype; @@ -4204,11 +4263,11 @@ make_wired_setting (shvarFile *ifcfg, NULL); nm_clear_g_free (&value); - value = svGetValueStr_cp (ifcfg, "HWADDR_BLACKLIST"); - if (value) { - gs_strfreev char **strv = NULL; + cvalue = svGetValueStr (ifcfg, "HWADDR_BLACKLIST", &value); + if (cvalue) { + gs_free const char **strv = NULL; - strv = transform_hwaddr_blacklist (value); + strv = transform_hwaddr_blacklist (cvalue); g_object_set (s_wired, NM_SETTING_WIRED_MAC_ADDRESS_BLACKLIST, strv, NULL); nm_clear_g_free (&value); } @@ -4633,66 +4692,114 @@ team_connection_from_ifcfg (const char *file, return connection; } +typedef enum { + BRIDGE_OPT_TYPE_MAIN, + BRIDGE_OPT_TYPE_OPTION, + BRIDGE_OPT_TYPE_PORT_MAIN, + BRIDGE_OPT_TYPE_PORT_OPTION, +} BridgeOptType; + typedef void (*BridgeOptFunc) (NMSetting *setting, gboolean stp, const char *key, - const char *value); + const char *value, + BridgeOptType opt_type); static void handle_bridge_option (NMSetting *setting, gboolean stp, const char *key, - const char *value) + const char *value, + BridgeOptType opt_type) { - guint32 u = 0; + static const struct { + const char *key; + const char *property_name; + BridgeOptType opt_type; + gboolean only_with_stp; + gboolean extended_bool; + } m/*etadata*/[] = { + { "DELAY", NM_SETTING_BRIDGE_FORWARD_DELAY, BRIDGE_OPT_TYPE_MAIN, .only_with_stp = TRUE }, + { "priority", NM_SETTING_BRIDGE_PRIORITY, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "hello_time", NM_SETTING_BRIDGE_HELLO_TIME, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "max_age", NM_SETTING_BRIDGE_MAX_AGE, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "ageing_time", NM_SETTING_BRIDGE_AGEING_TIME, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_snooping", NM_SETTING_BRIDGE_MULTICAST_SNOOPING, BRIDGE_OPT_TYPE_OPTION }, + { "group_fwd_mask", NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, BRIDGE_OPT_TYPE_OPTION }, + { "priority", NM_SETTING_BRIDGE_PORT_PRIORITY, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "path_cost", NM_SETTING_BRIDGE_PORT_PATH_COST, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "hairpin_mode", NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, BRIDGE_OPT_TYPE_PORT_OPTION, .extended_bool = TRUE, }, + }; + const char *error_message = NULL; + int i; + gint64 v; - if (!strcmp (key, "priority")) { - if (stp == FALSE) - PARSE_WARNING ("'priority' invalid when STP is disabled"); - else if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_PRIORITY, u, NULL); - else - PARSE_WARNING ("invalid priority value '%s'", value); - } else if (!strcmp (key, "hello_time")) { - if (stp == FALSE) - PARSE_WARNING ("'hello_time' invalid when STP is disabled"); - else if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_HELLO_TIME, u, NULL); - else - PARSE_WARNING ("invalid hello_time value '%s'", value); - } else if (!strcmp (key, "max_age")) { - if (stp == FALSE) - PARSE_WARNING ("'max_age' invalid when STP is disabled"); - else if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_MAX_AGE, u, NULL); - else - PARSE_WARNING ("invalid max_age value '%s'", value); - } else if (!strcmp (key, "ageing_time")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_AGEING_TIME, u, NULL); - else - PARSE_WARNING ("invalid ageing_time value '%s'", value); - } else if (!strcmp (key, "multicast_snooping")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_MULTICAST_SNOOPING, - (gboolean) u, NULL); - else - PARSE_WARNING ("invalid multicast_snooping value '%s'", value); - } else if (!strcmp (key, "group_fwd_mask")) { - if (get_uint (value, &u) && u <= 0xFFFF && !NM_FLAGS_ANY (u, 7)) - g_object_set (setting, NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, - (gboolean) u, NULL); - else - PARSE_WARNING ("invalid group_fwd_mask value '%s'", value); - } else - PARSE_WARNING ("unhandled bridge option '%s'", key); + for (i = 0; i < G_N_ELEMENTS (m); i++) { + GParamSpec *param_spec; + + if (opt_type != m[i].opt_type) + continue; + if (!nm_streq (key, m[i].key)) + continue; + if (m[i].only_with_stp && !stp) { + PARSE_WARNING ("'%s' invalid when STP is disabled", key); + return; + } + + param_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), m[i].property_name); + switch (param_spec->value_type) { + case G_TYPE_BOOLEAN: + if (m[i].extended_bool) { + if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1")) + v = TRUE; + else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) + v = FALSE; + else { + error_message = "is not a boolean"; + goto warn; + } + } else { + v = _nm_utils_ascii_str_to_int64 (value, 10, 0, 1, -1); + if (v == -1) { + error_message = g_strerror (errno); + goto warn; + } + } + if (!nm_g_object_set_property_boolean (G_OBJECT (setting), m[i].property_name, v, NULL)) { + error_message = "number is out of range"; + goto warn; + } + return; + case G_TYPE_UINT: + v = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT, -1); + if (v == -1) { + error_message = g_strerror (errno); + goto warn; + } + if (!nm_g_object_set_property_uint (G_OBJECT (setting), m[i].property_name, v, NULL)) { + error_message = "number is out of range"; + goto warn; + } + return; + default: + nm_assert_not_reached (); + continue; + } + +warn: + PARSE_WARNING ("invalid %s value '%s': %s", key, value, error_message); + return; + } + + PARSE_WARNING ("unhandled bridge option '%s'", key); } static void handle_bridging_opts (NMSetting *setting, gboolean stp, const char *value, - BridgeOptFunc func) + BridgeOptFunc func, + BridgeOptType opt_type) { gs_free const char **items = NULL; const char *const *iter; @@ -4707,7 +4814,7 @@ handle_bridging_opts (NMSetting *setting, key = *keys; val = *(keys + 1); if (val && key[0] && val[0]) - func (setting, stp, key, val); + func (setting, stp, key, val, opt_type); } } } @@ -4717,30 +4824,29 @@ make_bridge_setting (shvarFile *ifcfg, const char *file, GError **error) { - NMSettingBridge *s_bridge; - char *value; - guint32 u; + gs_unref_object NMSettingBridge *s_bridge = NULL; + gs_free char *value_to_free = NULL; + const char *value; gboolean stp = FALSE; gboolean stp_set = FALSE; - value = svGetValueStr_cp (ifcfg, "DEVICE"); + value = svGetValueStr (ifcfg, "DEVICE", &value_to_free); if (!value) { g_set_error (error, NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_CONNECTION, "mandatory DEVICE keyword missing"); return NULL; } - g_free (value); + nm_clear_g_free (&value_to_free); s_bridge = NM_SETTING_BRIDGE (nm_setting_bridge_new ()); - value = svGetValueStr_cp (ifcfg, "MACADDR"); + value = svGetValueStr (ifcfg, "BRIDGE_MACADDR", &value_to_free); if (value) { - value = g_strstrip (value); g_object_set (s_bridge, NM_SETTING_BRIDGE_MAC_ADDRESS, value, NULL); - g_free (value); + nm_clear_g_free (&value_to_free); } - value = svGetValueStr_cp (ifcfg, "STP"); + value = svGetValueStr (ifcfg, "STP", &value_to_free); if (value) { if (!strcasecmp (value, "on") || !strcasecmp (value, "yes")) { g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, TRUE, NULL); @@ -4751,7 +4857,7 @@ make_bridge_setting (shvarFile *ifcfg, stp_set = TRUE; } else PARSE_WARNING ("invalid STP value '%s'", value); - g_free (value); + nm_clear_g_free (&value_to_free); } if (!stp_set) { @@ -4759,25 +4865,19 @@ make_bridge_setting (shvarFile *ifcfg, g_object_set (s_bridge, NM_SETTING_BRIDGE_STP, FALSE, NULL); } - value = svGetValueStr_cp (ifcfg, "DELAY"); + value = svGetValueStr (ifcfg, "DELAY", &value_to_free); if (value) { - if (stp) { - if (get_uint (value, &u)) - g_object_set (s_bridge, NM_SETTING_BRIDGE_FORWARD_DELAY, u, NULL); - else - PARSE_WARNING ("invalid forward delay value '%s'", value); - } else - PARSE_WARNING ("DELAY invalid when STP is disabled"); - g_free (value); + handle_bridge_option (NM_SETTING (s_bridge), stp, "DELAY", value, BRIDGE_OPT_TYPE_MAIN); + nm_clear_g_free (&value_to_free); } - value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS"); + value = svGetValueStr (ifcfg, "BRIDGING_OPTS", &value_to_free); if (value) { - handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option); - g_free (value); + handle_bridging_opts (NM_SETTING (s_bridge), stp, value, handle_bridge_option, BRIDGE_OPT_TYPE_OPTION); + nm_clear_g_free (&value_to_free); } - return (NMSetting *) s_bridge; + return (NMSetting *) g_steal_pointer (&s_bridge); } static NMConnection * @@ -4788,6 +4888,8 @@ bridge_connection_from_ifcfg (const char *file, NMConnection *connection = NULL; NMSetting *con_setting = NULL; NMSetting *bridge_setting = NULL; + NMSetting *wired_setting = NULL; + NMSetting8021x *s_8021x = NULL; g_return_val_if_fail (file != NULL, NULL); g_return_val_if_fail (ifcfg != NULL, NULL); @@ -4810,57 +4912,40 @@ bridge_connection_from_ifcfg (const char *file, } nm_connection_add_setting (connection, bridge_setting); - return connection; -} + wired_setting = make_wired_setting (ifcfg, file, &s_8021x, error); + if (!wired_setting) { + g_object_unref (connection); + return NULL; + } + nm_connection_add_setting (connection, wired_setting); -static void -handle_bridge_port_option (NMSetting *setting, - gboolean stp, - const char *key, - const char *value) -{ - guint32 u = 0; + if (s_8021x) + nm_connection_add_setting (connection, NM_SETTING (s_8021x)); - if (!strcmp (key, "priority")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_PRIORITY, u, NULL); - else - PARSE_WARNING ("invalid priority value '%s'", value); - } else if (!strcmp (key, "path_cost")) { - if (get_uint (value, &u)) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_PATH_COST, u, NULL); - else - PARSE_WARNING ("invalid path_cost value '%s'", value); - } else if (!strcmp (key, "hairpin_mode")) { - if (!strcasecmp (value, "on") || !strcasecmp (value, "yes") || !strcmp (value, "1")) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, TRUE, NULL); - else if (!strcasecmp (value, "off") || !strcasecmp (value, "no")) - g_object_set (setting, NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, FALSE, NULL); - else - PARSE_WARNING ("invalid hairpin_mode value '%s'", value); - } else - PARSE_WARNING ("unhandled bridge port option '%s'", key); + return connection; } static NMSetting * make_bridge_port_setting (shvarFile *ifcfg) { NMSetting *s_port = NULL; - char *value; + gs_free char *value_to_free = NULL; + const char *value; g_return_val_if_fail (ifcfg != NULL, FALSE); - value = svGetValueStr_cp (ifcfg, "BRIDGE_UUID"); + value = svGetValueStr (ifcfg, "BRIDGE_UUID", &value_to_free); if (!value) - value = svGetValueStr_cp (ifcfg, "BRIDGE"); + value = svGetValueStr (ifcfg, "BRIDGE", &value_to_free); if (value) { - g_free (value); + nm_clear_g_free (&value_to_free); s_port = nm_setting_bridge_port_new (); - value = svGetValueStr_cp (ifcfg, "BRIDGING_OPTS"); - if (value) - handle_bridging_opts (s_port, FALSE, value, handle_bridge_port_option); - g_free (value); + value = svGetValueStr (ifcfg, "BRIDGING_OPTS", &value_to_free); + if (value) { + handle_bridging_opts (s_port, FALSE, value, handle_bridge_option, BRIDGE_OPT_TYPE_PORT_OPTION); + nm_clear_g_free (&value_to_free); + } } return s_port; @@ -5206,10 +5291,11 @@ connection_from_file_full (const char *filename, gboolean *out_ignore_error) { nm_auto_shvar_file_close shvarFile *parsed = NULL; + nm_auto_shvar_file_close shvarFile *network_ifcfg = NULL; gs_unref_object NMConnection *connection = NULL; gs_free char *type = NULL; char *devtype, *bootproto; - NMSetting *s_ip4, *s_ip6, *s_proxy, *s_port, *s_dcb = NULL, *s_user; + NMSetting *s_ip4, *s_ip6, *s_tc, *s_proxy, *s_port, *s_dcb = NULL, *s_user; const char *ifcfg_name = NULL; gboolean has_ip4_defroute = FALSE; gboolean has_complex_routes_v4; @@ -5233,6 +5319,8 @@ connection_from_file_full (const char *filename, if (!parsed) return NULL; + network_ifcfg = svOpenFile (network_file, NULL); + if (!svGetValueBoolean (parsed, "NM_CONTROLLED", TRUE)) { connection = create_unhandled_connection (filename, parsed, "unmanaged", out_unhandled); if (!connection) { @@ -5442,7 +5530,7 @@ connection_from_file_full (const char *filename, } s_ip6 = make_ip6_setting (parsed, - network_file, + network_ifcfg, !has_complex_routes_v4 && !has_complex_routes_v6, error); if (!s_ip6) @@ -5451,7 +5539,7 @@ connection_from_file_full (const char *filename, nm_connection_add_setting (connection, s_ip6); s_ip4 = make_ip4_setting (parsed, - network_file, + network_ifcfg, !has_complex_routes_v4 && !has_complex_routes_v6, &has_ip4_defroute, error); @@ -5464,17 +5552,21 @@ connection_from_file_full (const char *filename, nm_connection_add_setting (connection, s_ip4); } - /* There is only one DOMAIN variable and it is read and put to IPv4 config - * But if IPv4 is disabled or the config fails for some reason, we read - * DOMAIN and put the values into IPv6 config instead. + s_tc = make_tc_setting (parsed); + if (s_tc) + nm_connection_add_setting (connection, s_tc); + + /* For backwards compatibility, if IPv4 is disabled or the + * config fails for some reason, we read DOMAIN and put the + * values into IPv6 config instead of IPv4. */ check_dns_search_domains (parsed, s_ip4, s_ip6); - s_proxy = make_proxy_setting (parsed, error); + s_proxy = make_proxy_setting (parsed); if (s_proxy) nm_connection_add_setting (connection, s_proxy); - s_user = make_user_setting (parsed, error); + s_user = make_user_setting (parsed); if (s_user) nm_connection_add_setting (connection, s_user); @@ -5488,7 +5580,7 @@ connection_from_file_full (const char *filename, if (s_port) nm_connection_add_setting (connection, s_port); - if (!make_dcb_setting (parsed, network_file, &s_dcb, error)) + if (!make_dcb_setting (parsed, &s_dcb, error)) return NULL; if (s_dcb) nm_connection_add_setting (connection, s_dcb); |