summary refs log tree commit diff
path: root/libnm-core/nm-utils.c
diff options
context:
space:
mode:
Diffstat (limited to 'libnm-core/nm-utils.c')
-rw-r--r--libnm-core/nm-utils.c267
1 files changed, 188 insertions, 79 deletions
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index 8f2b4018..4659734b 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -1,20 +1,6 @@
+// SPDX-License-Identifier: LGPL-2.1+
 /*
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301 USA.
- *
- * Copyright 2005 - 2017 Red Hat, Inc.
+ * Copyright (C) 2005 - 2017 Red Hat, Inc.
  */
 
 #include "nm-default.h"
@@ -814,7 +800,7 @@ _nm_utils_hash_values_to_slist (GHashTable *hash)
 	return list;
 }
 
-GVariant *
+static GVariant *
 _nm_utils_strdict_to_dbus (const GValue *prop_value)
 {
 	GHashTable *hash;
@@ -839,9 +825,15 @@ _nm_utils_strdict_to_dbus (const GValue *prop_value)
 	if (len == 1)
 		g_variant_builder_add (&builder, "{ss}", key, value);
 	else {
-		gs_free NMUtilsNamedValue *idx = NULL;
+		gs_free NMUtilsNamedValue *idx_free = NULL;
+		NMUtilsNamedValue *idx;
+
+		if (len > 300 / sizeof (NMUtilsNamedValue)) {
+			idx_free = g_new (NMUtilsNamedValue, len);
+			idx = idx_free;
+		} else
+			idx = g_alloca (sizeof (NMUtilsNamedValue) * len);
 
-		idx = g_new (NMUtilsNamedValue, len);
 		i = 0;
 		do {
 			idx[i].name = key;
@@ -876,6 +868,12 @@ _nm_utils_strdict_from_dbus (GVariant *dbus_value,
 	g_value_take_boxed (prop_value, hash);
 }
 
+const NMSettInfoPropertType nm_sett_info_propert_type_strdict = {
+	.dbus_type           = NM_G_VARIANT_TYPE ("a{ss}"),
+	.gprop_to_dbus_fcn   = _nm_utils_strdict_to_dbus,
+	.gprop_from_dbus_fcn = _nm_utils_strdict_from_dbus,
+};
+
 GHashTable *
 _nm_utils_copy_strdict (GHashTable *strdict)
 {
@@ -1215,46 +1213,30 @@ nm_utils_security_valid (NMUtilsSecurityType type,
 		break;
 	case NMU_SEC_WPA_PSK:
 		if (adhoc)
-			return FALSE;  /* FIXME: Kernel WPA Ad-Hoc support is buggy */
+			return FALSE;
 		if (!(wifi_caps & NM_WIFI_DEVICE_CAP_WPA))
 			return FALSE;
 		if (have_ap) {
-			/* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
-			 * they don't have any pairwise ciphers. */
-			if (adhoc) {
-				/* coverity[dead_error_line] */
-				if (   (ap_wpa & NM_802_11_AP_SEC_GROUP_TKIP)
+			if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
+				if (   (ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
 				    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
 					return TRUE;
-				if (   (ap_wpa & NM_802_11_AP_SEC_GROUP_CCMP)
+				if (   (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
 				    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
 					return TRUE;
-			} else {
-				if (ap_wpa & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
-					if (   (ap_wpa & NM_802_11_AP_SEC_PAIR_TKIP)
-					    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
-						return TRUE;
-					if (   (ap_wpa & NM_802_11_AP_SEC_PAIR_CCMP)
-					    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
-						return TRUE;
-				}
 			}
 			return FALSE;
 		}
 		break;
 	case NMU_SEC_WPA2_PSK:
-		if (adhoc)
-			return FALSE;  /* FIXME: Kernel WPA Ad-Hoc support is buggy */
 		if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
 			return FALSE;
 		if (have_ap) {
-			/* Ad-Hoc WPA APs won't necessarily have the PSK flag set, and
-			 * they don't have any pairwise ciphers, nor any RSA flags yet. */
 			if (adhoc) {
-				/* coverity[dead_error_line] */
-				if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP)
-					return TRUE;
-				if (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP)
+				if (!(wifi_caps & NM_WIFI_DEVICE_CAP_IBSS_RSN))
+					return FALSE;
+				if (   (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
+				    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
 					return TRUE;
 			} else {
 				if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_PSK) {
@@ -1296,18 +1278,24 @@ nm_utils_security_valid (NMUtilsSecurityType type,
 		}
 		break;
 	case NMU_SEC_SAE:
-		if (adhoc)
-			return FALSE;
 		if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN))
 			return FALSE;
 		if (have_ap) {
-			if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_SAE) {
-				if (   (ap_rsn & NM_802_11_AP_SEC_PAIR_TKIP)
-				    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
-					return TRUE;
+			if (adhoc) {
+				if (!(wifi_caps & NM_WIFI_DEVICE_CAP_IBSS_RSN))
+					return FALSE;
 				if (   (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
 				    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
 					return TRUE;
+			} else {
+				if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_SAE) {
+					if (   (ap_rsn & NM_802_11_AP_SEC_PAIR_TKIP)
+					    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_TKIP))
+						return TRUE;
+					if (   (ap_rsn & NM_802_11_AP_SEC_PAIR_CCMP)
+					    && (wifi_caps & NM_WIFI_DEVICE_CAP_CIPHER_CCMP))
+						return TRUE;
+				}
 			}
 			return FALSE;
 		}
@@ -1740,7 +1728,9 @@ nm_utils_ip6_dns_to_variant (char **dns)
  * @value: a #GVariant of type 'aay'
  *
  * Utility function to convert a #GVariant of type 'aay' representing a list of
- * IPv6 addresses into an array of IP address strings.
+ * IPv6 addresses into an array of IP address strings. Each "ay" entry must be
+ * a IPv6 address in binary form (16 bytes long). Invalid entries are silently
+ * ignored.
  *
  * Returns: (transfer full) (type utf8): a %NULL-terminated array of IP address strings.
  **/
@@ -1762,14 +1752,9 @@ nm_utils_ip6_dns_from_variant (GVariant *value)
 		gsize length;
 		const struct in6_addr *ip = g_variant_get_fixed_array (ip_var, &length, 1);
 
-		if (length != sizeof (struct in6_addr)) {
-			g_warning ("%s: ignoring invalid IP6 address of length %d",
-			           __func__, (int) length);
-			g_variant_unref (ip_var);
-			continue;
-		}
+		if (length == sizeof (struct in6_addr))
+			dns[i++] = nm_utils_inet6_ntop_dup (ip);
 
-		dns[i++] = nm_utils_inet6_ntop_dup (ip);
 		g_variant_unref (ip_var);
 	}
 	dns[i] = NULL;
@@ -4354,7 +4339,7 @@ _nm_utils_hwaddr_to_dbus_impl (const char *str)
 	return g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, buf, len, 1);
 }
 
-GVariant *
+static GVariant *
 _nm_utils_hwaddr_cloned_get (const NMSettInfoSetting *sett_info,
                              guint property_idx,
                              NMConnection *connection,
@@ -4370,7 +4355,7 @@ _nm_utils_hwaddr_cloned_get (const NMSettInfoSetting *sett_info,
 	return _nm_utils_hwaddr_to_dbus_impl (addr);
 }
 
-gboolean
+static gboolean
 _nm_utils_hwaddr_cloned_set (NMSetting     *setting,
                              GVariant      *connection_dict,
                              const char    *property,
@@ -4402,7 +4387,7 @@ _nm_utils_hwaddr_cloned_set (NMSetting     *setting,
 	return TRUE;
 }
 
-gboolean
+static gboolean
 _nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
                                  GVariant      *connection_dict,
                                  const char    *property,
@@ -4413,7 +4398,14 @@ _nm_utils_hwaddr_cloned_not_set (NMSetting *setting,
 	return TRUE;
 }
 
-GVariant *
+const NMSettInfoPropertType nm_sett_info_propert_type_cloned_mac_address = {
+	.dbus_type             = G_VARIANT_TYPE_BYTESTRING,
+	.to_dbus_fcn           = _nm_utils_hwaddr_cloned_get,
+	.from_dbus_fcn         = _nm_utils_hwaddr_cloned_set,
+	.missing_from_dbus_fcn = _nm_utils_hwaddr_cloned_not_set,
+};
+
+static GVariant *
 _nm_utils_hwaddr_cloned_data_synth (const NMSettInfoSetting *sett_info,
                                     guint property_idx,
                                     NMConnection *connection,
@@ -4452,7 +4444,7 @@ _nm_utils_hwaddr_cloned_data_synth (const NMSettInfoSetting *sett_info,
 	       : NULL;
 }
 
-gboolean
+static gboolean
 _nm_utils_hwaddr_cloned_data_set (NMSetting *setting,
                                   GVariant *connection_dict,
                                   const char *property,
@@ -4472,13 +4464,19 @@ _nm_utils_hwaddr_cloned_data_set (NMSetting *setting,
 	return TRUE;
 }
 
-GVariant *
+const NMSettInfoPropertType nm_sett_info_propert_type_assigned_mac_address = {
+	.dbus_type     = G_VARIANT_TYPE_STRING,
+	.to_dbus_fcn   = _nm_utils_hwaddr_cloned_data_synth,
+	.from_dbus_fcn = _nm_utils_hwaddr_cloned_data_set,
+};
+
+static GVariant *
 _nm_utils_hwaddr_to_dbus (const GValue *prop_value)
 {
 	return _nm_utils_hwaddr_to_dbus_impl (g_value_get_string (prop_value));
 }
 
-void
+static void
 _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
                             GValue *prop_value)
 {
@@ -4490,6 +4488,12 @@ _nm_utils_hwaddr_from_dbus (GVariant *dbus_value,
 	g_value_take_string (prop_value, str);
 }
 
+const NMSettInfoPropertType nm_sett_info_propert_type_mac_addrees = {
+	.dbus_type           = G_VARIANT_TYPE_BYTESTRING,
+	.gprop_to_dbus_fcn   = _nm_utils_hwaddr_to_dbus,
+	.gprop_from_dbus_fcn = _nm_utils_hwaddr_from_dbus,
+};
+
 /*****************************************************************************/
 
 /* Validate secret-flags. Most settings don't validate them, which is a bug.
@@ -5551,6 +5555,48 @@ attribute_unescape (const char *start, const char *end)
 	return ret;
 }
 
+gboolean
+_nmtst_variant_attribute_spec_assert_sorted (const NMVariantAttributeSpec *const*array,
+                                             gsize len)
+{
+	gsize i;
+
+	g_assert (array);
+	g_assert (len > 0);
+	g_assert_cmpint(len, ==, NM_PTRARRAY_LEN (array));
+
+	for (i = 0; i < len; i++) {
+		nm_assert (array[i]->name);
+		nm_assert (array[i]->name[0]);
+		if (i > 0)
+			nm_assert (strcmp (array[i - 1]->name, array[i]->name) < 0);
+	}
+	nm_assert (!array[i]);
+
+	return TRUE;
+}
+
+const NMVariantAttributeSpec *
+_nm_variant_attribute_spec_find_binary_search (const NMVariantAttributeSpec *const*array,
+                                               gsize len,
+                                               const char *name)
+{
+	gssize idx;
+
+	G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMVariantAttributeSpec, name) == 0);
+
+	idx = nm_utils_ptrarray_find_binary_search ((gconstpointer *) array,
+	                                            len,
+	                                            &name,
+	                                            nm_strcmp_p_with_data,
+	                                            NULL,
+	                                            NULL,
+	                                            NULL);
+	if (idx < 0)
+		return NULL;
+	return array[idx];
+}
+
 /**
  * nm_utils_parse_variant_attributes:
  * @string: the input string
@@ -5861,6 +5907,14 @@ nm_utils_version (void)
 
 /*****************************************************************************/
 
+NM_UTILS_FLAGS2STR_DEFINE (nm_bluetooth_capability_to_string, NMBluetoothCapabilities,
+	NM_UTILS_FLAGS2STR (NM_BT_CAPABILITY_NONE, "NONE"),
+	NM_UTILS_FLAGS2STR (NM_BT_CAPABILITY_DUN, "DUN"),
+	NM_UTILS_FLAGS2STR (NM_BT_CAPABILITY_NAP, "NAP"),
+)
+
+/*****************************************************************************/
+
 /**
  * nm_utils_base64secret_decode:
  * @base64_key: the (possibly invalid) base64 encode key.
@@ -5930,7 +5984,7 @@ nm_utils_base64secret_normalize (const char *base64_key,
 	return TRUE;
 }
 
-GVariant *
+static GVariant *
 _nm_utils_bridge_vlans_to_dbus (const NMSettInfoSetting *sett_info,
                                 guint property_idx,
                                 NMConnection *connection,
@@ -5972,7 +6026,7 @@ _nm_utils_bridge_vlans_to_dbus (const NMSettInfoSetting *sett_info,
 	return g_variant_builder_end (&builder);
 }
 
-gboolean
+static gboolean
 _nm_utils_bridge_vlans_from_dbus (NMSetting *setting,
                                   GVariant *connection_dict,
                                   const char *property,
@@ -6026,6 +6080,12 @@ _nm_utils_bridge_vlans_from_dbus (NMSetting *setting,
 	return TRUE;
 }
 
+const NMSettInfoPropertType nm_sett_info_propert_type_bridge_vlans = {
+	.dbus_type     = NM_G_VARIANT_TYPE ("aa{sv}"),
+	.to_dbus_fcn   = _nm_utils_bridge_vlans_to_dbus,
+	.from_dbus_fcn = _nm_utils_bridge_vlans_from_dbus,
+};
+
 gboolean
 _nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
                                    gboolean check_normalizable,
@@ -6104,28 +6164,77 @@ _nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
 }
 
 gboolean
-nm_utils_connection_is_adhoc_wpa (NMConnection *connection)
+_nm_utils_iaid_verify (const char *str, gint64 *out_value)
 {
-	NMSettingWireless *s_wifi;
-	NMSettingWirelessSecurity *s_wsec;
-	const char *key_mgmt;
-	const char *mode;
+	gint64 iaid;
+
+	NM_SET_OUT (out_value, -1);
 
-	s_wifi = nm_connection_get_setting_wireless (connection);
-	if (!s_wifi)
+	if (!str || !str[0])
 		return FALSE;
 
-	mode = nm_setting_wireless_get_mode (s_wifi);
-	if (!nm_streq0 (mode, NM_SETTING_WIRELESS_MODE_ADHOC))
+	if (NM_IAID_IS_SPECIAL (str))
+		return TRUE;
+
+	if (   NM_STRCHAR_ALL (str, ch, ch >= '0' && ch <= '9')
+	    && (str[0] != '0' || str[1] == '\0')
+	    && (iaid = _nm_utils_ascii_str_to_int64 (str, 10, 0, G_MAXUINT32, -1)) != -1) {
+		NM_SET_OUT (out_value, iaid);
+		return TRUE;
+	}
+
+	return FALSE;
+}
+
+gboolean
+_nm_utils_validate_dhcp_hostname_flags (NMDhcpHostnameFlags flags,
+                                        int addr_family,
+                                        GError **error)
+{
+	NMDhcpHostnameFlags unknown;
+
+	unknown = flags;
+	unknown &= ~(  NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED
+	             | NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE
+	             | NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE
+	             | NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS);
+	if (unknown) {
+		g_set_error (error,
+		             NM_CONNECTION_ERROR,
+		             NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		             _("unknown flags 0x%x"), (guint) unknown);
 		return FALSE;
+	}
 
-	s_wsec = nm_connection_get_setting_wireless_security (connection);
-	if (!s_wsec)
+	if (NM_FLAGS_ALL (flags,
+	                    NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE
+	                  | NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("'fqdn-no-update' and 'fqdn-serv-update' flags cannot be set at the same time"));
 		return FALSE;
+	}
 
-	key_mgmt = nm_setting_wireless_security_get_key_mgmt (s_wsec);
-	if (!nm_streq0 (key_mgmt, "wpa-none"))
+	if (   NM_FLAGS_HAS (flags, NM_DHCP_HOSTNAME_FLAG_FQDN_CLEAR_FLAGS)
+	    && NM_FLAGS_ANY (flags,  NM_DHCP_HOSTNAME_FLAG_FQDN_SERV_UPDATE
+	                           | NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED
+	                           | NM_DHCP_HOSTNAME_FLAG_FQDN_NO_UPDATE)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("'fqdn-clear-flags' flag is incompatible with other FQDN flags"));
 		return FALSE;
+	}
+
+	if (   addr_family == AF_INET6
+	    && (flags & NM_DHCP_HOSTNAME_FLAG_FQDN_ENCODED)) {
+		g_set_error_literal (error,
+		                     NM_CONNECTION_ERROR,
+		                     NM_CONNECTION_ERROR_INVALID_PROPERTY,
+		                     _("DHCPv6 does not support the E (encoded) FQDN flag"));
+		return FALSE;
+	}
 
 	return TRUE;
 }