From 74a0b1d9d1432f72fe7ed60d00e1e99aad562f8d Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Mon, 28 Mar 2011 10:40:38 -0500 Subject: [PATCH] libnm-util: verify connection's 'type' setting is actually a base type By 'base type' I mean a hardware-related type that can actually be used to activate the connection, like wifi, wired, gsm, cdma, wimax, bluetooth, etc, but not ipv4, ipv6, 8021x, etc. --- libnm-util/nm-connection.c | 108 ++++++++++++---- libnm-util/nm-connection.h | 7 +- libnm-util/tests/test-general.c | 219 ++++++++++++++++++++++++++++++++ 3 files changed, 306 insertions(+), 28 deletions(-) diff --git a/libnm-util/nm-connection.c b/libnm-util/nm-connection.c index 2e5669cd2e..f5dd166119 100644 --- a/libnm-util/nm-connection.c +++ b/libnm-util/nm-connection.c @@ -98,6 +98,7 @@ nm_connection_error_get_type (void) static const GEnumValue values[] = { ENUM_ENTRY (NM_CONNECTION_ERROR_UNKNOWN, "UnknownError"), ENUM_ENTRY (NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND, "ConnectionSettingNotFound"), + ENUM_ENTRY (NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID, "ConnectionTypeInvalid"), { 0, 0, 0 } }; etype = g_enum_register_static ("NMConnectionError", values); @@ -139,6 +140,7 @@ static struct SettingInfo { const char *name; GType type; guint32 priority; + gboolean base_type; GQuark error_quark; } default_map[DEFAULT_MAP_SIZE] = { { NULL } }; @@ -170,7 +172,11 @@ setting_unregister (const char *name) #endif static void -register_one_setting (const char *name, GType type, GQuark error_quark, guint32 priority) +register_one_setting (const char *name, + GType type, + GQuark error_quark, + guint32 priority, + gboolean base_type) { static guint32 i = 0; @@ -181,6 +187,7 @@ register_one_setting (const char *name, GType type, GQuark error_quark, guint32 default_map[i].type = type; default_map[i].error_quark = error_quark; default_map[i].priority = priority; + default_map[i].base_type = base_type; i++; setting_register (name, type); @@ -197,82 +204,82 @@ register_default_settings (void) register_one_setting (NM_SETTING_CONNECTION_SETTING_NAME, NM_TYPE_SETTING_CONNECTION, NM_SETTING_CONNECTION_ERROR, - 0); + 0, FALSE); register_one_setting (NM_SETTING_WIRED_SETTING_NAME, NM_TYPE_SETTING_WIRED, NM_SETTING_WIRED_ERROR, - 1); + 1, TRUE); register_one_setting (NM_SETTING_WIRELESS_SETTING_NAME, NM_TYPE_SETTING_WIRELESS, NM_SETTING_WIRELESS_ERROR, - 1); + 1, TRUE); register_one_setting (NM_SETTING_OLPC_MESH_SETTING_NAME, NM_TYPE_SETTING_OLPC_MESH, NM_SETTING_OLPC_MESH_ERROR, - 1); + 1, TRUE); register_one_setting (NM_SETTING_GSM_SETTING_NAME, NM_TYPE_SETTING_GSM, NM_SETTING_GSM_ERROR, - 1); + 1, TRUE); register_one_setting (NM_SETTING_CDMA_SETTING_NAME, NM_TYPE_SETTING_CDMA, NM_SETTING_CDMA_ERROR, - 1); + 1, TRUE); register_one_setting (NM_SETTING_BLUETOOTH_SETTING_NAME, NM_TYPE_SETTING_BLUETOOTH, NM_SETTING_BLUETOOTH_ERROR, - 1); + 1, TRUE); register_one_setting (NM_SETTING_WIMAX_SETTING_NAME, NM_TYPE_SETTING_WIMAX, NM_SETTING_WIMAX_ERROR, - 1); + 1, TRUE); register_one_setting (NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, NM_TYPE_SETTING_WIRELESS_SECURITY, NM_SETTING_WIRELESS_SECURITY_ERROR, - 2); + 2, FALSE); register_one_setting (NM_SETTING_SERIAL_SETTING_NAME, NM_TYPE_SETTING_SERIAL, NM_SETTING_SERIAL_ERROR, - 2); + 2, FALSE); register_one_setting (NM_SETTING_PPP_SETTING_NAME, NM_TYPE_SETTING_PPP, NM_SETTING_PPP_ERROR, - 3); + 3, FALSE); register_one_setting (NM_SETTING_PPPOE_SETTING_NAME, NM_TYPE_SETTING_PPPOE, NM_SETTING_PPPOE_ERROR, - 3); + 3, TRUE); register_one_setting (NM_SETTING_802_1X_SETTING_NAME, NM_TYPE_SETTING_802_1X, NM_SETTING_802_1X_ERROR, - 3); + 3, FALSE); register_one_setting (NM_SETTING_VPN_SETTING_NAME, NM_TYPE_SETTING_VPN, NM_SETTING_VPN_ERROR, - 4); + 4, TRUE); register_one_setting (NM_SETTING_IP4_CONFIG_SETTING_NAME, NM_TYPE_SETTING_IP4_CONFIG, NM_SETTING_IP4_CONFIG_ERROR, - 6); + 6, FALSE); register_one_setting (NM_SETTING_IP6_CONFIG_SETTING_NAME, NM_TYPE_SETTING_IP6_CONFIG, NM_SETTING_IP6_CONFIG_ERROR, - 6); + 6, FALSE); /* Be sure to update DEFAULT_MAP_SIZE if you add another setting!! */ } @@ -290,6 +297,18 @@ get_priority_for_setting_type (GType type) return G_MAXUINT32; } +static gboolean +get_base_type_for_setting_type (GType type) +{ + int i; + + for (i = 0; default_map[i].name; i++) { + if (default_map[i].type == type) + return default_map[i].base_type; + } + return FALSE; +} + /** * nm_connection_lookup_setting_type: * @name: a setting name @@ -693,15 +712,17 @@ nm_connection_verify (NMConnection *connection, GError **error) gpointer value; GSList *all_settings = NULL; gboolean success = TRUE; + const char *ctype; + GType base_type; if (error) g_return_val_if_fail (*error == NULL, FALSE); if (!NM_IS_CONNECTION (connection)) { - g_set_error (error, - NM_SETTING_CONNECTION_ERROR, - NM_SETTING_CONNECTION_ERROR_UNKNOWN, - "invalid connection; failed verification"); + g_set_error_literal (error, + NM_SETTING_CONNECTION_ERROR, + NM_SETTING_CONNECTION_ERROR_UNKNOWN, + "invalid connection; failed verification"); g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); } @@ -710,10 +731,10 @@ nm_connection_verify (NMConnection *connection, GError **error) /* First, make sure there's at least 'connection' setting */ s_con = nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); if (!s_con) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND, - "connection setting not found"); + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND, + "connection setting not found"); return FALSE; } @@ -726,9 +747,42 @@ nm_connection_verify (NMConnection *connection, GError **error) g_hash_table_iter_init (&iter, priv->settings); while (g_hash_table_iter_next (&iter, NULL, &value) && success) success = nm_setting_verify (NM_SETTING (value), all_settings, error); - g_slist_free (all_settings); - return success; + + if (success == FALSE) + return FALSE; + + /* Now make sure the given 'type' setting can actually be the base setting + * of the connection. Can't have type=ppp for example. + */ + ctype = nm_setting_connection_get_connection_type (NM_SETTING_CONNECTION (s_con)); + if (!ctype) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID, + "connection type missing"); + return FALSE; + } + + base_type = nm_connection_lookup_setting_type (ctype); + if (base_type == 0) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID, + "base setting GType not found"); + return FALSE; + } + + if (!get_base_type_for_setting_type (base_type)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID, + "connection type '%s' is not a base type", + ctype); + return FALSE; + } + + return TRUE; } /** diff --git a/libnm-util/nm-connection.h b/libnm-util/nm-connection.h index 3386f7bef3..87b053c101 100644 --- a/libnm-util/nm-connection.h +++ b/libnm-util/nm-connection.h @@ -62,6 +62,10 @@ G_BEGIN_DECLS * @NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND: the #NMConnection object * did not contain the required #NMSettingConnection object, which must be * present for all connections + * @NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID: the 'type' property of the + * 'connection' setting did not point to a valid connection base type; ie + * it was not a hardware-related setting like #NMSettingWired or + * #NMSettingWireless. * * Describes errors that may result from operations involving a #NMConnection. * @@ -69,7 +73,8 @@ G_BEGIN_DECLS typedef enum { NM_CONNECTION_ERROR_UNKNOWN = 0, - NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND + NM_CONNECTION_ERROR_CONNECTION_SETTING_NOT_FOUND, + NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID } NMConnectionError; #define NM_TYPE_CONNECTION_ERROR (nm_connection_error_get_type ()) diff --git a/libnm-util/tests/test-general.c b/libnm-util/tests/test-general.c index 653dd26800..1ce80622ac 100644 --- a/libnm-util/tests/test-general.c +++ b/libnm-util/tests/test-general.c @@ -29,11 +29,13 @@ #include "nm-setting-connection.h" #include "nm-setting-vpn.h" #include "nm-setting-gsm.h" +#include "nm-setting-cdma.h" #include "nm-setting-wired.h" #include "nm-setting-wireless-security.h" #include "nm-setting-ip6-config.h" #include "nm-setting-ip4-config.h" #include "nm-setting-pppoe.h" +#include "nm-setting-serial.h" #include "nm-dbus-glib-types.h" static void @@ -900,6 +902,221 @@ test_connection_diff_no_secrets (void) g_object_unref (b); } +static void +add_generic_settings (NMConnection *connection, const char *ctype) +{ + NMSetting *setting; + char *uuid; + + uuid = nm_utils_uuid_generate (); + + setting = nm_setting_connection_new (); + g_object_set (setting, + NM_SETTING_CONNECTION_ID, "asdfasdfadf", + NM_SETTING_CONNECTION_TYPE, ctype, + NM_SETTING_CONNECTION_UUID, uuid, + NULL); + nm_connection_add_setting (connection, setting); + + g_free (uuid); + + setting = nm_setting_ip4_config_new (); + g_object_set (setting, NM_SETTING_IP4_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, setting); + + setting = nm_setting_ip6_config_new (); + g_object_set (setting, NM_SETTING_IP6_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_AUTO, NULL); + nm_connection_add_setting (connection, setting); +} + +static void +test_connection_good_base_types (void) +{ + NMConnection *connection; + NMSetting *setting; + gboolean success; + GError *error = NULL; + GByteArray *array; + const guint8 bdaddr[] = { 0x11, 0x22, 0x33, 0x44, 0x55, 0x66 }; + + /* Try a basic wired connection */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_WIRED_SETTING_NAME); + setting = nm_setting_wired_new (); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + g_object_unref (connection); + + /* Try a wired PPPoE connection */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_PPPOE_SETTING_NAME); + setting = nm_setting_pppoe_new (); + g_object_set (setting, NM_SETTING_PPPOE_USERNAME, "bob smith", NULL); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + g_object_unref (connection); + + /* Wifi connection */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_WIRELESS_SETTING_NAME); + + setting = nm_setting_wireless_new (); + array = g_byte_array_new (); + g_byte_array_append (array, (const guint8 *) "1234567", 7); + g_object_set (setting, + NM_SETTING_WIRELESS_SSID, array, + NM_SETTING_WIRELESS_MODE, "infrastructure", + NULL); + g_byte_array_free (array, TRUE); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + g_object_unref (connection); + + /* Bluetooth connection */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_BLUETOOTH_SETTING_NAME); + + setting = nm_setting_bluetooth_new (); + array = g_byte_array_new (); + g_byte_array_append (array, bdaddr, sizeof (bdaddr)); + g_object_set (setting, + NM_SETTING_BLUETOOTH_BDADDR, array, + NM_SETTING_CONNECTION_TYPE, NM_SETTING_BLUETOOTH_TYPE_PANU, + NULL); + g_byte_array_free (array, TRUE); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + g_object_unref (connection); + + /* WiMAX connection */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_WIMAX_SETTING_NAME); + setting = nm_setting_wimax_new (); + g_object_set (setting, NM_SETTING_WIMAX_NETWORK_NAME, "CLEAR", NULL); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + g_object_unref (connection); + + /* GSM connection */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_GSM_SETTING_NAME); + + setting = nm_setting_gsm_new (); + g_object_set (setting, + NM_SETTING_GSM_NUMBER, "*99#", + NM_SETTING_GSM_APN, "metered.billing.sucks", + NULL); + nm_connection_add_setting (connection, setting); + + /* CDMA connection */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_CDMA_SETTING_NAME); + + setting = nm_setting_cdma_new (); + g_object_set (setting, + NM_SETTING_CDMA_NUMBER, "#777", + NM_SETTING_CDMA_USERNAME, "foobar@vzw.com", + NULL); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_no_error (error); + g_assert (success); + g_object_unref (connection); +} + +static void +test_connection_bad_base_types (void) +{ + NMConnection *connection; + NMSetting *setting; + gboolean success; + GError *error = NULL; + + /* Test various non-base connection types to make sure they are rejected; + * using a fake 'wired' connection so the rest of it verifies + */ + + /* Connection setting */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_CONNECTION_SETTING_NAME); + setting = nm_setting_wired_new (); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID); + g_assert (success == FALSE); + g_object_unref (connection); + g_clear_error (&error); + + /* PPP setting */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_PPP_SETTING_NAME); + setting = nm_setting_wired_new (); + nm_connection_add_setting (connection, setting); + setting = nm_setting_ppp_new (); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID); + g_assert (success == FALSE); + g_object_unref (connection); + g_clear_error (&error); + + /* Serial setting */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_SERIAL_SETTING_NAME); + setting = nm_setting_wired_new (); + nm_connection_add_setting (connection, setting); + setting = nm_setting_serial_new (); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID); + g_assert (success == FALSE); + g_object_unref (connection); + g_clear_error (&error); + + /* IP4 setting */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_IP4_CONFIG_SETTING_NAME); + setting = nm_setting_wired_new (); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID); + g_assert (success == FALSE); + g_object_unref (connection); + g_clear_error (&error); + + /* IP6 setting */ + connection = nm_connection_new (); + add_generic_settings (connection, NM_SETTING_IP6_CONFIG_SETTING_NAME); + setting = nm_setting_wired_new (); + nm_connection_add_setting (connection, setting); + + success = nm_connection_verify (connection, &error); + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_CONNECTION_TYPE_INVALID); + g_assert (success == FALSE); + g_object_unref (connection); + g_clear_error (&error); +} + int main (int argc, char **argv) { GError *error = NULL; @@ -928,6 +1145,8 @@ int main (int argc, char **argv) test_connection_diff_same (); test_connection_diff_different (); test_connection_diff_no_secrets (); + test_connection_good_base_types (); + test_connection_bad_base_types (); base = g_path_get_basename (argv[0]); fprintf (stdout, "%s: SUCCESS\n", base);