diff options
Diffstat (limited to 'libnm-core')
77 files changed, 3316 insertions, 444 deletions
diff --git a/libnm-core/crypto_nss.c b/libnm-core/crypto_nss.c index b5d7e630..56e91e26 100644 --- a/libnm-core/crypto_nss.c +++ b/libnm-core/crypto_nss.c @@ -91,7 +91,7 @@ crypto_decrypt (const char *cipher, PK11Context *ctx = NULL; SECStatus s; gboolean success = FALSE; - unsigned int pad_len = 0, extra = 0; + unsigned pad_len = 0, extra = 0; guint32 i, real_iv_len = 0; if (!crypto_init (error)) diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 40322427..ecfb9780 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -73,10 +73,6 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; - -static NMSettingVerifyResult _nm_connection_verify (NMConnection *connection, GError **error); - - /*****************************************************************************/ static void @@ -128,23 +124,15 @@ nm_connection_add_setting (NMConnection *connection, NMSetting *setting) g_signal_emit (connection, signals[CHANGED], 0); } -/** - * nm_connection_remove_setting: - * @connection: a #NMConnection - * @setting_type: the #GType of the setting object to remove - * - * Removes the #NMSetting with the given #GType from the #NMConnection. This - * operation dereferences the #NMSetting object. - **/ -void -nm_connection_remove_setting (NMConnection *connection, GType setting_type) +gboolean +_nm_connection_remove_setting (NMConnection *connection, GType setting_type) { NMConnectionPrivate *priv; NMSetting *setting; const char *setting_name; - g_return_if_fail (NM_IS_CONNECTION (connection)); - g_return_if_fail (g_type_is_a (setting_type, NM_TYPE_SETTING)); + g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE); + g_return_val_if_fail (g_type_is_a (setting_type, NM_TYPE_SETTING), FALSE); priv = NM_CONNECTION_GET_PRIVATE (connection); setting_name = g_type_name (setting_type); @@ -153,7 +141,23 @@ nm_connection_remove_setting (NMConnection *connection, GType setting_type) g_signal_handlers_disconnect_by_func (setting, setting_changed_cb, connection); g_hash_table_remove (priv->settings, setting_name); g_signal_emit (connection, signals[CHANGED], 0); + return TRUE; } + return FALSE; +} + +/** + * nm_connection_remove_setting: + * @connection: a #NMConnection + * @setting_type: the #GType of the setting object to remove + * + * Removes the #NMSetting with the given #GType from the #NMConnection. This + * operation dereferences the #NMSetting object. + **/ +void +nm_connection_remove_setting (NMConnection *connection, GType setting_type) +{ + _nm_connection_remove_setting (connection, setting_type); } /** @@ -602,17 +606,17 @@ static gboolean _normalize_connection_uuid (NMConnection *self) { NMSettingConnection *s_con = nm_connection_get_setting_connection (self); - char *uuid; + char uuid[37]; - g_assert (s_con); + nm_assert (s_con); if (nm_setting_connection_get_uuid (s_con)) return FALSE; - uuid = nm_utils_uuid_generate (); - g_object_set (s_con, NM_SETTING_CONNECTION_UUID, uuid, NULL); - g_free (uuid); - + g_object_set (s_con, + NM_SETTING_CONNECTION_UUID, + nm_utils_uuid_generate_buf (uuid), + NULL); return TRUE; } @@ -986,6 +990,38 @@ _normalize_team_port_config (NMConnection *self, GHashTable *parameters) return FALSE; } +static gboolean +_normalize_required_settings (NMConnection *self, GHashTable *parameters) +{ + if (nm_connection_get_setting_vlan (self)) { + if (!nm_connection_get_setting_wired (self)) { + nm_connection_add_setting (self, nm_setting_wired_new ()); + return TRUE; + } + } + return FALSE; +} + +static gboolean +_normalize_invalid_slave_port_settings (NMConnection *self, GHashTable *parameters) +{ + NMSettingConnection *s_con = nm_connection_get_setting_connection (self); + const char *slave_type; + gboolean changed = FALSE; + + slave_type = nm_setting_connection_get_slave_type (s_con); + + if ( !nm_streq0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME) + && _nm_connection_remove_setting (self, NM_TYPE_SETTING_BRIDGE_PORT)) + changed = TRUE; + + if ( !nm_streq0 (slave_type, NM_SETTING_TEAM_SETTING_NAME) + && _nm_connection_remove_setting (self, NM_TYPE_SETTING_TEAM_PORT)) + changed = TRUE; + + return changed; +} + /** * nm_connection_verify: * @connection: the #NMConnection to verify @@ -1017,7 +1053,7 @@ nm_connection_verify (NMConnection *connection, GError **error) return result == NM_SETTING_VERIFY_SUCCESS || result == NM_SETTING_VERIFY_NORMALIZABLE; } -static NMSettingVerifyResult +NMSettingVerifyResult _nm_connection_verify (NMConnection *connection, GError **error) { NMConnectionPrivate *priv; @@ -1233,8 +1269,10 @@ nm_connection_normalize (NMConnection *connection, was_modified |= _normalize_connection_uuid (connection); was_modified |= _normalize_connection_type (connection); was_modified |= _normalize_connection_slave_type (connection); - was_modified |= _normalize_ethernet_link_neg (connection); + was_modified |= _normalize_required_settings (connection, parameters); + was_modified |= _normalize_invalid_slave_port_settings (connection, parameters); was_modified |= _normalize_ip_config (connection, parameters); + was_modified |= _normalize_ethernet_link_neg (connection); was_modified |= _normalize_infiniband_mtu (connection, parameters); was_modified |= _normalize_bond_mode (connection, parameters); was_modified |= _normalize_wireless_mac_address_randomization (connection, parameters); @@ -1845,6 +1883,7 @@ nm_connection_is_virtual (NMConnection *connection) g_return_val_if_fail (type != NULL, FALSE); if ( !strcmp (type, NM_SETTING_BOND_SETTING_NAME) + || !strcmp (type, NM_SETTING_DUMMY_SETTING_NAME) || !strcmp (type, NM_SETTING_TEAM_SETTING_NAME) || !strcmp (type, NM_SETTING_BRIDGE_SETTING_NAME) || !strcmp (type, NM_SETTING_VLAN_SETTING_NAME) @@ -2055,6 +2094,24 @@ nm_connection_get_setting_dcb (NMConnection *connection) } /** + * nm_connection_get_setting_dummy: + * @connection: the #NMConnection + * + * A shortcut to return any #NMSettingDummy the connection might contain. + * + * Returns: (transfer none): an #NMSettingDummy if the connection contains one, otherwise %NULL + * + * Since: 1.8 + **/ +NMSettingDummy * +nm_connection_get_setting_dummy (NMConnection *connection) +{ + g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL); + + return (NMSettingDummy *) nm_connection_get_setting (connection, NM_TYPE_SETTING_DUMMY); +} + +/** * nm_connection_get_setting_generic: * @connection: the #NMConnection * @@ -2461,13 +2518,12 @@ nm_connection_private_free (NMConnectionPrivate *priv) static NMConnectionPrivate * nm_connection_get_private (NMConnection *connection) { - static GQuark key = 0; + GQuark key; NMConnectionPrivate *priv; nm_assert (NM_IS_CONNECTION (connection)); - if (G_UNLIKELY (key == 0)) - key = g_quark_from_static_string ("NMConnectionPrivate"); + key = NM_CACHED_QUARK ("NMConnectionPrivate"); priv = g_object_get_qdata ((GObject *) connection, key); if (!priv) { diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index 36ef7b6f..fae9862a 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -27,9 +27,9 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-core-types.h> -#include <nm-setting.h> -#include <nm-errors.h> +#include "nm-core-types.h" +#include "nm-setting.h" +#include "nm-errors.h" G_BEGIN_DECLS @@ -199,6 +199,8 @@ NMSettingBridgePort * nm_connection_get_setting_bridge_port (NMConnec NMSettingCdma * nm_connection_get_setting_cdma (NMConnection *connection); NMSettingConnection * nm_connection_get_setting_connection (NMConnection *connection); NMSettingDcb * nm_connection_get_setting_dcb (NMConnection *connection); +NM_AVAILABLE_IN_1_8 +NMSettingDummy * nm_connection_get_setting_dummy (NMConnection *connection); NMSettingGeneric * nm_connection_get_setting_generic (NMConnection *connection); NMSettingGsm * nm_connection_get_setting_gsm (NMConnection *connection); NMSettingInfiniband * nm_connection_get_setting_infiniband (NMConnection *connection); diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 74f45100..ac292bfc 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -45,6 +45,7 @@ #include "nm-setting-cdma.h" #include "nm-setting-connection.h" #include "nm-setting-dcb.h" +#include "nm-setting-dummy.h" #include "nm-setting-generic.h" #include "nm-setting-gsm.h" #include "nm-setting-infiniband.h" @@ -117,6 +118,26 @@ gboolean _nm_connection_replace_settings (NMConnection *connection, NMSettingParseFlags parse_flags, GError **error); +/** + * NMSettingVerifyResult: + * @NM_SETTING_VERIFY_SUCCESS: the setting verifies successfully + * @NM_SETTING_VERIFY_ERROR: the setting has a serious misconfiguration + * @NM_SETTING_VERIFY_NORMALIZABLE: the setting is valid but has properties + * that should be normalized + * @NM_SETTING_VERIFY_NORMALIZABLE_ERROR: the setting is invalid but the + * errors can be fixed by nm_connection_normalize(). + */ +typedef enum { + NM_SETTING_VERIFY_SUCCESS = TRUE, + NM_SETTING_VERIFY_ERROR = FALSE, + NM_SETTING_VERIFY_NORMALIZABLE = 2, + NM_SETTING_VERIFY_NORMALIZABLE_ERROR = 3, +} NMSettingVerifyResult; + +NMSettingVerifyResult _nm_connection_verify (NMConnection *connection, GError **error); + +gboolean _nm_connection_remove_setting (NMConnection *connection, GType setting_type); + NMConnection *_nm_simple_connection_new_from_dbus (GVariant *dict, NMSettingParseFlags parse_flags, GError **error); @@ -154,8 +175,6 @@ gssize _nm_utils_ptrarray_find_first (gconstpointer *list, gssize len, gconstpoi gssize _nm_utils_ptrarray_find_binary_search (gconstpointer *list, gsize len, gconstpointer needle, GCompareDataFunc cmpfcn, gpointer user_data); gssize _nm_utils_array_find_binary_search (gconstpointer list, gsize elem_size, gsize len, gconstpointer needle, GCompareDataFunc cmpfcn, gpointer user_data); -gssize _nm_utils_strv_find_first (char **list, gssize len, const char *needle); - char **_nm_utils_strv_cleanup (char **strv, gboolean strip_whitespace, gboolean skip_empty, @@ -185,6 +204,8 @@ gboolean _nm_utils_check_module_file (const char *name, gpointer user_data, GError **error); +char *_nm_utils_enum_to_str_full (GType type, int value, const char *sep); + #define NM_UTILS_UUID_TYPE_LEGACY 0 #define NM_UTILS_UUID_TYPE_VARIANT3 1 @@ -344,4 +365,6 @@ gboolean _nm_utils_inet6_is_token (const struct in6_addr *in6addr); gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, gboolean port); +/*****************************************************************************/ + #endif diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index 2948b5f5..3b9ec37b 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -23,9 +23,9 @@ #include <glib-object.h> -#include <nm-version.h> -#include <nm-dbus-interface.h> -#include <nm-core-enum-types.h> +#include "nm-version.h" +#include "nm-dbus-interface.h" +#include "nm-core-enum-types.h" typedef struct _NMConnection NMConnection; typedef struct _NMSetting NMSetting; @@ -38,6 +38,7 @@ typedef struct _NMSettingBridgePort NMSettingBridgePort; typedef struct _NMSettingCdma NMSettingCdma; typedef struct _NMSettingConnection NMSettingConnection; typedef struct _NMSettingDcb NMSettingDcb; +typedef struct _NMSettingDummy NMSettingDummy; typedef struct _NMSettingGeneric NMSettingGeneric; typedef struct _NMSettingGsm NMSettingGsm; typedef struct _NMSettingInfiniband NMSettingInfiniband; @@ -55,6 +56,7 @@ typedef struct _NMSettingSerial NMSettingSerial; typedef struct _NMSettingTeam NMSettingTeam; typedef struct _NMSettingTeamPort NMSettingTeamPort; typedef struct _NMSettingTun NMSettingTun; +typedef struct _NMSettingUser NMSettingUser; typedef struct _NMSettingVlan NMSettingVlan; typedef struct _NMSettingVpn NMSettingVpn; typedef struct _NMSettingVxlan NMSettingVxlan; diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index d2d54f69..8abc91bb 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -30,6 +30,7 @@ #ifndef NM_VERSION_H #define NM_AVAILABLE_IN_1_2 +#define NM_AVAILABLE_IN_1_8 #endif /* @@ -58,6 +59,7 @@ #define NM_DBUS_INTERFACE_DHCP6_CONFIG NM_DBUS_INTERFACE ".DHCP6Config" #define NM_DBUS_INTERFACE_DEVICE_INFINIBAND NM_DBUS_INTERFACE_DEVICE ".Infiniband" #define NM_DBUS_INTERFACE_DEVICE_BOND NM_DBUS_INTERFACE_DEVICE ".Bond" +#define NM_DBUS_INTERFACE_DEVICE_DUMMY NM_DBUS_INTERFACE_DEVICE ".Dummy" #define NM_DBUS_INTERFACE_DEVICE_TEAM NM_DBUS_INTERFACE_DEVICE ".Team" #define NM_DBUS_INTERFACE_DEVICE_VLAN NM_DBUS_INTERFACE_DEVICE ".Vlan" #define NM_DBUS_INTERFACE_DEVICE_BRIDGE NM_DBUS_INTERFACE_DEVICE ".Bridge" @@ -105,14 +107,32 @@ typedef enum { /** * NMState: - * @NM_STATE_UNKNOWN: networking state is unknown - * @NM_STATE_ASLEEP: networking is not enabled - * @NM_STATE_DISCONNECTED: there is no active network connection - * @NM_STATE_DISCONNECTING: network connections are being cleaned up - * @NM_STATE_CONNECTING: a network connection is being started - * @NM_STATE_CONNECTED_LOCAL: there is only local IPv4 and/or IPv6 connectivity - * @NM_STATE_CONNECTED_SITE: there is only site-wide IPv4 and/or IPv6 connectivity - * @NM_STATE_CONNECTED_GLOBAL: there is global IPv4 and/or IPv6 Internet connectivity + * @NM_STATE_UNKNOWN: Networking state is unknown. This indicates a daemon error + * that makes it unable to reasonably assess the state. In such event the + * applications are expected to assume Internet connectivity might be present + * and not disable controls that require network access. + * The graphical shells may hide the network accessibility indicator altogether + * since no meaningful status indication can be provided. + * @NM_STATE_ASLEEP: Networking is not enabled, the system is being suspended or + * resumed from suspend. + * @NM_STATE_DISCONNECTED: There is no active network connection. + * The graphical shell should indicate no network connectivity and the + * applications should not attempt to access the network. + * @NM_STATE_DISCONNECTING: Network connections are being cleaned up. + * The applications should tear down their network sessions. + * @NM_STATE_CONNECTING: A network connection is being started + * The graphical shell should indicate the network is being connected while + * the applications should still make no attempts to connect the network. + * @NM_STATE_CONNECTED_LOCAL: There is only local IPv4 and/or IPv6 connectivity, + * but no default route to access the Internet. The graphical shell should + * indicate no network connectivity. + * @NM_STATE_CONNECTED_SITE: There is only site-wide IPv4 and/or IPv6 connectivity. + * This means a default route is available, but the Internet connectivity check + * (see "Connectivity" property) did not succeed. The graphical shell should + * indicate limited network connectivity. + * @NM_STATE_CONNECTED_GLOBAL: There is global IPv4 and/or IPv6 Internet connectivity + * This means the Internet connectivity check succeeded, the graphical shell should + * indicate full network connectivity. * * #NMState values indicate the current overall networking state. **/ @@ -129,12 +149,23 @@ typedef enum { /** * NMConnectivityState: - * @NM_CONNECTIVITY_UNKNOWN: Network connectivity is unknown. - * @NM_CONNECTIVITY_NONE: The host is not connected to any network. - * @NM_CONNECTIVITY_PORTAL: The host is behind a captive portal and - * cannot reach the full Internet. - * @NM_CONNECTIVITY_LIMITED: The host is connected to a network, but - * does not appear to be able to reach the full Internet. + * @NM_CONNECTIVITY_UNKNOWN: Network connectivity is unknown. This means the + * connectivity checks are disabled (e.g. on server installations) or has + * not run yet. The graphical shell should assume the Internet connection + * might be available and not present a captive portal window. + * @NM_CONNECTIVITY_NONE: The host is not connected to any network. There's + * no active connection that contains a default route to the internet and + * thus it makes no sense to even attempt a connectivity check. The graphical + * shell should use this state to indicate the network connection is unavailable. + * @NM_CONNECTIVITY_PORTAL: The Internet connection is hijacked by a captive + * portal gateway. The graphical shell may open a sandboxed web browser window + * (because the captive portals typically attempt a man-in-the-middle attacks + * agains the https connections) for the purpose of authenticating to a gateway + * and retrigger the connectivity check with CheckConnectivity() when the + * browser window is dismissed. + * @NM_CONNECTIVITY_LIMITED: The host is connected to a network, does not appear + * to be able to reach the full Internet, but a captive portal has not been + * detected. * @NM_CONNECTIVITY_FULL: The host is connected to a network, and * appears to be able to reach the full Internet. */ @@ -171,6 +202,7 @@ typedef enum { * @NM_DEVICE_TYPE_VXLAN: a VXLAN interface * @NM_DEVICE_TYPE_VETH: a VETH interface * @NM_DEVICE_TYPE_MACSEC: a MACsec interface + * @NM_DEVICE_TYPE_DUMMY: a dummy interface * * #NMDeviceType values indicate the type of hardware represented by a * device object. @@ -198,6 +230,7 @@ typedef enum { NM_DEVICE_TYPE_VXLAN = 19, NM_DEVICE_TYPE_VETH = 20, NM_DEVICE_TYPE_MACSEC = 21, + NM_DEVICE_TYPE_DUMMY = 22, } NMDeviceType; /** @@ -206,6 +239,7 @@ typedef enum { * @NM_DEVICE_CAP_NM_SUPPORTED: NetworkManager supports this device * @NM_DEVICE_CAP_CARRIER_DETECT: this device can indicate carrier status * @NM_DEVICE_CAP_IS_SOFTWARE: this device is a software device + * @NM_DEVICE_CAP_SRIOV: this device supports single-root I/O virtualization * * General device capability flags. **/ @@ -214,9 +248,9 @@ typedef enum { /*< flags >*/ NM_DEVICE_CAP_NM_SUPPORTED = 0x00000001, NM_DEVICE_CAP_CARRIER_DETECT = 0x00000002, NM_DEVICE_CAP_IS_SOFTWARE = 0x00000004, + NM_DEVICE_CAP_SRIOV = 0x00000008, } NMDeviceCapabilities; - /** * NMDeviceWifiCapabilities: * @NM_WIFI_DEVICE_CAP_NONE: device has no encryption/authentication capabilities @@ -609,6 +643,62 @@ typedef enum { } NMActiveConnectionState; /** + * NMActiveConnectionStateReason: + * @NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN: The reason for the active connection + * state change is unknown. + * @NM_ACTIVE_CONNECTION_STATE_REASON_NONE: No reason was given for the active + * connection state change. + * @NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED: The active connection changed + * state because the user disconnected it. + * @NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED: The active connection + * changed state because the device it was using was disconnected. + * @NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED: The service providing the + * VPN connection was stopped. + * @NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID: The IP config of the active + * connection was invalid. + * @NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT: The connection attempt to + * the VPN service timed out. + * @NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT: A timeout occurred + * while starting the service providing the VPN connection. + * @NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED: Starting the service + * providing the VPN connection failed. + * @NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS: Necessary secrets for the + * connection were not provided. + * @NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED: Authentication to the + * server failed. + * @NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED: The connection was + * deleted from settings. + * @NM_ACTIVE_CONNECTION_STATE_REASON_DEPENDENCY_FAILED: Master connection of this + * connection failed to activate. + * @NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REALIZE_FAILED: Could not create the + * software device link. + * @NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REMOVED: The device this connection + * depended on disappeared. + * + * Active connection state reasons. + * + * Since: 1.8 + */ +NM_AVAILABLE_IN_1_8 +typedef enum { + NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN = 0, + NM_ACTIVE_CONNECTION_STATE_REASON_NONE = 1, + NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED = 2, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED = 3, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED = 4, + NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID = 5, + NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT = 6, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT = 7, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED = 8, + NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS = 9, + NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED = 10, + NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED = 11, + NM_ACTIVE_CONNECTION_STATE_REASON_DEPENDENCY_FAILED = 12, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REALIZE_FAILED = 13, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REMOVED = 14, +} NMActiveConnectionStateReason; + +/** * NMSecretAgentGetSecretsFlags: * @NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE: no special behavior; by default no * user interaction is allowed and requests for secrets are fulfilled from @@ -661,6 +751,7 @@ typedef enum /*< flags >*/ { #ifndef NM_VERSION_H #undef NM_AVAILABLE_IN_1_2 +#undef NM_AVAILABLE_IN_1_8 #endif #define NM_LLDP_ATTR_DESTINATION "destination" diff --git a/libnm-core/nm-dbus-types.xml b/libnm-core/nm-dbus-types.xml index 7c6389d4..4e30034c 100644 --- a/libnm-core/nm-dbus-types.xml +++ b/libnm-core/nm-dbus-types.xml @@ -55,42 +55,42 @@ <row role="constant"> <entry role="enum_member_name"><para>NM_STATE_UNKNOWN</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>0</literal></para><para></para></entry> - <entry role="enum_member_description"><para>networking state is unknown</para><para></para></entry> + <entry role="enum_member_description"><para>Networking state is unknown. This indicates a daemon error that makes it unable to reasonably assess the state. In such event the applications are expected to assume Internet connectivity might be present and not disable controls that require network access. The graphical shells may hide the network accessibility indicator altogether since no meaningful status indication can be provided.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_STATE_ASLEEP</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>10</literal></para><para></para></entry> - <entry role="enum_member_description"><para>networking is not enabled</para><para></para></entry> + <entry role="enum_member_description"><para>Networking is not enabled, the system is being suspended or resumed from suspend.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_STATE_DISCONNECTED</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>20</literal></para><para></para></entry> - <entry role="enum_member_description"><para>there is no active network connection</para><para></para></entry> + <entry role="enum_member_description"><para>There is no active network connection. The graphical shell should indicate no network connectivity and the applications should not attempt to access the network.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_STATE_DISCONNECTING</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>30</literal></para><para></para></entry> - <entry role="enum_member_description"><para>network connections are being cleaned up</para><para></para></entry> + <entry role="enum_member_description"><para>Network connections are being cleaned up. The applications should tear down their network sessions.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_STATE_CONNECTING</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>40</literal></para><para></para></entry> - <entry role="enum_member_description"><para>a network connection is being started</para><para></para></entry> + <entry role="enum_member_description"><para>A network connection is being started The graphical shell should indicate the network is being connected while the applications should still make no attempts to connect the network.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_STATE_CONNECTED_LOCAL</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>50</literal></para><para></para></entry> - <entry role="enum_member_description"><para>there is only local IPv4 and/or IPv6 connectivity</para><para></para></entry> + <entry role="enum_member_description"><para>There is only local IPv4 and/or IPv6 connectivity, but no default route to access the Internet. The graphical shell should indicate no network connectivity.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_STATE_CONNECTED_SITE</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>60</literal></para><para></para></entry> - <entry role="enum_member_description"><para>there is only site-wide IPv4 and/or IPv6 connectivity</para><para></para></entry> + <entry role="enum_member_description"><para>There is only site-wide IPv4 and/or IPv6 connectivity. This means a default route is available, but the Internet connectivity check (see "Connectivity" property) did not succeed. The graphical shell should indicate limited network connectivity.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_STATE_CONNECTED_GLOBAL</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>70</literal></para><para></para></entry> - <entry role="enum_member_description"><para>there is global IPv4 and/or IPv6 Internet connectivity</para><para></para></entry> + <entry role="enum_member_description"><para>There is global IPv4 and/or IPv6 Internet connectivity This means the Internet connectivity check succeeded, the graphical shell should indicate full network connectivity.</para><para></para></entry> </row> </tbody> </tgroup> @@ -115,22 +115,22 @@ <row role="constant"> <entry role="enum_member_name"><para>NM_CONNECTIVITY_UNKNOWN</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>0</literal></para><para></para></entry> - <entry role="enum_member_description"><para>Network connectivity is unknown.</para><para></para></entry> + <entry role="enum_member_description"><para>Network connectivity is unknown. This means the connectivity checks are disabled (e.g. on server installations) or has not run yet. The graphical shell should assume the Internet connection might be available and not present a captive portal window.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_CONNECTIVITY_NONE</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>1</literal></para><para></para></entry> - <entry role="enum_member_description"><para>The host is not connected to any network.</para><para></para></entry> + <entry role="enum_member_description"><para>The host is not connected to any network. There's no active connection that contains a default route to the internet and thus it makes no sense to even attempt a connectivity check. The graphical shell should use this state to indicate the network connection is unavailable.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_CONNECTIVITY_PORTAL</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>2</literal></para><para></para></entry> - <entry role="enum_member_description"><para>The host is behind a captive portal and cannot reach the full Internet.</para><para></para></entry> + <entry role="enum_member_description"><para>The Internet connection is hijacked by a captive portal gateway. The graphical shell may open a sandboxed web browser window (because the captive portals typically attempt a man-in-the-middle attacks agains the https connections) for the purpose of authenticating to a gateway and retrigger the connectivity check with CheckConnectivity() when the browser window is dismissed.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_CONNECTIVITY_LIMITED</para><para></para></entry> <entry role="enum_member_value"><para>= <literal>3</literal></para><para></para></entry> - <entry role="enum_member_description"><para>The host is connected to a network, but does not appear to be able to reach the full Internet.</para><para></para></entry> + <entry role="enum_member_description"><para>The host is connected to a network, does not appear to be able to reach the full Internet, but a captive portal has not been detected.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_CONNECTIVITY_FULL</para><para></para></entry> @@ -267,6 +267,11 @@ <entry role="enum_member_value"><para>= <literal>21</literal></para><para></para></entry> <entry role="enum_member_description"><para>a MACsec interface</para><para></para></entry> </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_DEVICE_TYPE_DUMMY</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>22</literal></para><para></para></entry> + <entry role="enum_member_description"><para>a dummy interface</para><para></para></entry> + </row> </tbody> </tgroup> </informaltable> @@ -307,6 +312,11 @@ <entry role="enum_member_value"><para>= <literal>0x00000004</literal></para><para></para></entry> <entry role="enum_member_description"><para>this device is a software device</para><para></para></entry> </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_DEVICE_CAP_SRIOV</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>0x00000008</literal></para><para></para></entry> + <entry role="enum_member_description"><para>this device supports single-root I/O virtualization</para><para></para></entry> + </row> </tbody> </tgroup> </informaltable> @@ -1168,6 +1178,101 @@ </refsect3> </refsect2> + <refsect2 id="NMActiveConnectionStateReason" role="enum"> + <title>enum NMActiveConnectionStateReason</title> + <indexterm zone="NMActiveConnectionStateReason"> + <primary>NMActiveConnectionStateReason</primary> + </indexterm> + <para><para>Active connection state reasons.</para><para>Since: 1.8</para><para></para></para> + <refsect3 role="enum_members"> + <title>Values</title> + <informaltable role="enum_members_table" pgwide="1" frame="none"> + <tgroup cols="4"> + <colspec colname="enum_members_name" colwidth="300px" /> + <colspec colname="enum_members_value" colwidth="100px"/> + <colspec colname="enum_members_description" /> + <tbody> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>0</literal></para><para></para></entry> + <entry role="enum_member_description"><para>The reason for the active connection state change is unknown.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_NONE</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>1</literal></para><para></para></entry> + <entry role="enum_member_description"><para>No reason was given for the active connection state change.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>2</literal></para><para></para></entry> + <entry role="enum_member_description"><para>The active connection changed state because the user disconnected it.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>3</literal></para><para></para></entry> + <entry role="enum_member_description"><para>The active connection changed state because the device it was using was disconnected.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>4</literal></para><para></para></entry> + <entry role="enum_member_description"><para>The service providing the VPN connection was stopped.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>5</literal></para><para></para></entry> + <entry role="enum_member_description"><para>The IP config of the active connection was invalid.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>6</literal></para><para></para></entry> + <entry role="enum_member_description"><para>The connection attempt to the VPN service timed out.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>7</literal></para><para></para></entry> + <entry role="enum_member_description"><para>A timeout occurred while starting the service providing the VPN connection.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>8</literal></para><para></para></entry> + <entry role="enum_member_description"><para>Starting the service providing the VPN connection failed.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>9</literal></para><para></para></entry> + <entry role="enum_member_description"><para>Necessary secrets for the connection were not provided.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>10</literal></para><para></para></entry> + <entry role="enum_member_description"><para>Authentication to the server failed.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>11</literal></para><para></para></entry> + <entry role="enum_member_description"><para>The connection was deleted from settings.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_DEPENDENCY_FAILED</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>12</literal></para><para></para></entry> + <entry role="enum_member_description"><para>Master connection of this connection failed to activate.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REALIZE_FAILED</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>13</literal></para><para></para></entry> + <entry role="enum_member_description"><para>Could not create the software device link.</para><para></para></entry> + </row> + <row role="constant"> + <entry role="enum_member_name"><para>NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_REMOVED</para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>14</literal></para><para></para></entry> + <entry role="enum_member_description"><para>The device this connection depended on disappeared.</para><para></para></entry> + </row> + </tbody> + </tgroup> + </informaltable> + </refsect3> + </refsect2> + <refsect2 id="NMSecretAgentGetSecretsFlags" role="enum"> <title>enum NMSecretAgentGetSecretsFlags</title> <indexterm zone="NMSecretAgentGetSecretsFlags"> diff --git a/libnm-core/nm-errors.c b/libnm-core/nm-errors.c index e9da8d3f..351bc1d0 100644 --- a/libnm-core/nm-errors.c +++ b/libnm-core/nm-errors.c @@ -26,14 +26,14 @@ #include "nm-vpn-dbus-interface.h" #include "nm-core-internal.h" -G_DEFINE_QUARK (nm-agent-manager-error-quark, nm_agent_manager_error) -G_DEFINE_QUARK (nm-connection-error-quark, nm_connection_error) -G_DEFINE_QUARK (nm-crypto-error-quark, nm_crypto_error) -G_DEFINE_QUARK (nm-device-error-quark, nm_device_error) -G_DEFINE_QUARK (nm-manager-error-quark, nm_manager_error) -G_DEFINE_QUARK (nm-secret-agent-error-quark, nm_secret_agent_error) -G_DEFINE_QUARK (nm-settings-error-quark, nm_settings_error) -G_DEFINE_QUARK (nm-vpn-plugin-error-quark, nm_vpn_plugin_error) +NM_CACHED_QUARK_FCN ("nm-agent-manager-error-quark", nm_agent_manager_error_quark) +NM_CACHED_QUARK_FCN ("nm-connection-error-quark", nm_connection_error_quark) +NM_CACHED_QUARK_FCN ("nm-crypto-error-quark", nm_crypto_error_quark) +NM_CACHED_QUARK_FCN ("nm-device-error-quark", nm_device_error_quark) +NM_CACHED_QUARK_FCN ("nm-manager-error-quark", nm_manager_error_quark) +NM_CACHED_QUARK_FCN ("nm-secret-agent-error-quark", nm_secret_agent_error_quark) +NM_CACHED_QUARK_FCN ("nm-settings-error-quark", nm_settings_error_quark) +NM_CACHED_QUARK_FCN ("nm-vpn-plugin-error-quark", nm_vpn_plugin_error_quark) static void register_error_domain (GQuark domain, diff --git a/libnm-core/nm-keyfile-internal.h b/libnm-core/nm-keyfile-internal.h index 30c6c200..be11a708 100644 --- a/libnm-core/nm-keyfile-internal.h +++ b/libnm-core/nm-keyfile-internal.h @@ -27,6 +27,9 @@ #include "nm-connection.h" #include "nm-setting-8021x.h" +#include "nm-core-internal.h" +#include "nm-setting-metadata.h" + /*****************************************************************************/ #define NM_KEYFILE_CERT_SCHEME_PREFIX_PATH "file://" @@ -138,17 +141,8 @@ typedef gboolean (*NMKeyfileWriteHandler) (NMConnection *connection, * type %NM_KEYFILE_WRITE_TYPE_CERT. */ typedef struct { + const NMSetting8021xSchemeVtable *vtable; NMSetting8021x *setting; - const char *property_name; - - /* The following functions are helpers that simplify the implementation - * of the handler. */ - const char *suffix; - NMSetting8021xCKScheme (*scheme_func) (NMSetting8021x *setting); - NMSetting8021xCKFormat (*format_func) (NMSetting8021x *setting); - const char * (*path_func) (NMSetting8021x *setting); - GBytes * (*blob_func) (NMSetting8021x *setting); - const char * (*uri_func) (NMSetting8021x *setting); } NMKeyfileWriteTypeDataCert; diff --git a/libnm-core/nm-keyfile-reader.c b/libnm-core/nm-keyfile-reader.c index c071264d..eb257eeb 100644 --- a/libnm-core/nm-keyfile-reader.c +++ b/libnm-core/nm-keyfile-reader.c @@ -35,6 +35,8 @@ #include "nm-core-internal.h" #include "nm-keyfile-utils.h" +#include "nm-setting-user.h" + typedef struct { NMConnection *connection; GKeyFile *keyfile; @@ -429,6 +431,31 @@ read_one_ip_address_or_route (KeyfileReaderInfo *info, } static void +fill_route_attributes (GKeyFile *kf, NMIPRoute *route, const char *setting, const char *key, int family) +{ + gs_free char *value = NULL; + gs_unref_hashtable GHashTable *hash = NULL; + GHashTableIter iter; + char *name; + GVariant *variant; + + value = nm_keyfile_plugin_kf_get_string (kf, setting, key, NULL); + if (!value || !value[0]) + return; + + hash = nm_utils_parse_variant_attributes (value, ',', '=', TRUE, + nm_ip_route_get_variant_attribute_spec (), + NULL); + if (hash) { + g_hash_table_iter_init (&iter, hash); + while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &variant)) { + if (nm_ip_route_attribute_validate (name, variant, family, NULL, NULL)) + nm_ip_route_set_attribute (route, name, g_variant_ref (variant)); + } + } +} + +static void ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key) { const char *setting_name = nm_setting_get_name (setting); @@ -454,6 +481,7 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c for (key_basename = key_names; *key_basename; key_basename++) { char *key_name; gpointer item; + char options_key[128]; /* -1 means no suffix */ if (i >= 0) @@ -463,6 +491,11 @@ ip_address_or_route_parser (KeyfileReaderInfo *info, NMSetting *setting, const c item = read_one_ip_address_or_route (info, key, setting_name, key_name, ipv6, routes, gateway ? NULL : &gateway, setting); + if (item && routes) { + nm_sprintf_buf (options_key, "%s_options", key_name); + fill_route_attributes (info->keyfile, item, setting_name, options_key, ipv6 ? AF_INET6 : AF_INET); + } + g_free (key_name); if (info->error) { @@ -637,7 +670,6 @@ mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key buf_arr = g_new (guint8, buf_len); for (i = 0; i < length; i++) { int val = tmp_list[i]; - const guint8 v = (guint8) (val & 0xFF); if (val < 0 || val > 255) { handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN, @@ -645,7 +677,7 @@ mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key val); return; } - buf_arr[i] = v; + buf_arr[i] = (guint8) val; } } } @@ -684,31 +716,59 @@ mac_address_parser_INFINIBAND (KeyfileReaderInfo *info, NMSetting *setting, cons static void read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key) { - char **keys, **iter; - char *value; + gs_strfreev char **keys = NULL; + const char *const*iter; const char *setting_name = nm_setting_get_name (setting); + gboolean is_vpn; keys = nm_keyfile_plugin_kf_get_keys (file, setting_name, NULL, NULL); if (!keys || !*keys) return; - for (iter = keys; *iter; iter++) { - value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL); - if (!value) - continue; - - if (NM_IS_SETTING_VPN (setting)) { - /* Add any item that's not a class property to the data hash */ - if (!g_object_class_find_property (G_OBJECT_GET_CLASS (setting), *iter)) - nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), *iter, value); + if ( (is_vpn = NM_IS_SETTING_VPN (setting)) + || NM_IS_SETTING_BOND (setting)) { + for (iter = (const char *const*) keys; *iter; iter++) { + gs_free char *to_free = NULL; + gs_free char *value = NULL; + const char *name; + + value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL); + if (!value) + continue; + + name = nm_keyfile_key_decode (*iter, &to_free); + + if (is_vpn) { + /* Add any item that's not a class property to the data hash */ + if (!g_object_class_find_property (G_OBJECT_GET_CLASS (setting), name)) + nm_setting_vpn_add_data_item (NM_SETTING_VPN (setting), name, value); + } else { + if (strcmp (name, "interface-name")) + nm_setting_bond_add_option (NM_SETTING_BOND (setting), name, value); + } } - if (NM_IS_SETTING_BOND (setting)) { - if (strcmp (*iter, "interface-name")) - nm_setting_bond_add_option (NM_SETTING_BOND (setting), *iter, value); + return; + } + + if (NM_IS_SETTING_USER (setting)) { + gs_unref_hashtable GHashTable *data = NULL; + + data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + for (iter = (const char *const*) keys; *iter; iter++) { + gs_free char *to_free = NULL; + char *value = NULL; + const char *name; + + value = nm_keyfile_plugin_kf_get_string (file, setting_name, *iter, NULL); + if (!value) + continue; + name = nm_keyfile_key_decode (*iter, &to_free); + g_hash_table_insert (data, + g_steal_pointer (&to_free) ?: g_strdup (name), + value); } - g_free (value); + g_object_set (setting, NM_SETTING_USER_DATA, data, NULL); } - g_strfreev (keys); } static gsize @@ -1425,6 +1485,9 @@ read_one_setting_value (NMSetting *setting, if (NM_IS_SETTING_VPN (setting)) check_for_key = FALSE; + if (NM_IS_SETTING_USER (setting)) + check_for_key = FALSE; + /* Bonding 'options' don't have the exact key name. The options are right under [bond] group. */ if (NM_IS_SETTING_BOND (setting)) check_for_key = FALSE; @@ -1574,7 +1637,7 @@ read_one_setting_value (NMSetting *setting, else { if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("too large FLAGS property '%s' (%llu)"), - G_VALUE_TYPE_NAME (value), (long long unsigned) uint_val)) + G_VALUE_TYPE_NAME (value), (unsigned long long) uint_val)) goto out_error; } } diff --git a/libnm-core/nm-keyfile-utils.c b/libnm-core/nm-keyfile-utils.c index 13cf6161..1b7860d8 100644 --- a/libnm-core/nm-keyfile-utils.c +++ b/libnm-core/nm-keyfile-utils.c @@ -361,3 +361,205 @@ _nm_keyfile_has_values (GKeyFile *keyfile) groups = g_key_file_get_groups (keyfile, NULL); return groups && groups[0]; } + +/*****************************************************************************/ + +static const char * +_keyfile_key_encode (const char *name, + char **out_to_free) +{ + gsize len, i; + GString *str; + + nm_assert (name); + nm_assert (out_to_free && !*out_to_free); + + /* See g_key_file_is_key_name(). + * + * GKeyfile allows all UTF-8 characters (even non-well formed sequences), + * except: + * - no empty keys + * - no leading/trailing ' ' + * - no '=', '[', ']' + * + * We do something more strict here. All non-ASCII characters, all non-printable + * characters, and all invalid characters are escaped with "\\XX". + * + * We don't escape \\, unless it is followed by two hex digits. + */ + + if (!name[0]) { + /* empty keys are are backslash encoded. Note that usually + * \\00 is not a valid encode, the only exception is the empty + * word. */ + return "\\00"; + } + + /* find the first character that needs escaping. */ + i = 0; + if (name[0] != ' ') { + for (;; i++) { + const guchar ch = (guchar) name[i]; + + if (ch == '\0') + return name; + + if ( ch < 0x20 + || ch >= 127 + || NM_IN_SET (ch, '=', '[', ']') + || ( ch == '\\' + && g_ascii_isxdigit (name[i + 1]) + && g_ascii_isxdigit (name[i + 2])) + || ( ch == ' ' + && name[i + 1] == '\0')) + break; + } + } else if (name[1] == '\0') + return "\\20"; + + len = i + strlen (&name[i]); + nm_assert (len == strlen (name)); + str = g_string_sized_new (len + 15); + + if (name[0] == ' ') { + nm_assert (i == 0); + g_string_append (str, "\\20"); + i = 1; + } else + g_string_append_len (str, name, i); + + for (;; i++) { + const guchar ch = (guchar) name[i]; + + if (ch == '\0') + break; + + if ( ch < 0x20 + || ch >= 127 + || NM_IN_SET (ch, '=', '[', ']') + || ( ch == '\\' + && g_ascii_isxdigit (name[i + 1]) + && g_ascii_isxdigit (name[i + 2])) + || ( ch == ' ' + && name[i + 1] == '\0')) + g_string_append_printf (str, "\\%2X", ch); + else + g_string_append_c (str, (char) ch); + } + + return (*out_to_free = g_string_free (str, FALSE)); +} + +static const char * +_keyfile_key_decode (const char *key, + char **out_to_free) +{ + gsize i, len; + GString *str; + + nm_assert (key); + nm_assert (out_to_free && !*out_to_free); + + if (!key[0]) + return ""; + + for (i = 0; TRUE; i++) { + const char ch = key[i]; + + if (ch == '\0') + return key; + if ( ch == '\\' + && g_ascii_isxdigit (key[i + 1]) + && g_ascii_isxdigit (key[i + 2])) + break; + } + + len = i + strlen (&key[i]); + + if ( len == 3 + && nm_streq (key, "\\00")) + return ""; + + nm_assert (len == strlen (key)); + str = g_string_sized_new (len + 3); + + g_string_append_len (str, key, i); + for (;;) { + const char ch = key[i]; + char ch1, ch2; + unsigned v; + + if (ch == '\0') + break; + + if ( ch == '\\' + && g_ascii_isxdigit ((ch1 = key[i + 1])) + && g_ascii_isxdigit ((ch2 = key[i + 2]))) { + v = (g_ascii_xdigit_value (ch1) << 4) + g_ascii_xdigit_value (ch2); + if (v != 0) { + g_string_append_c (str, (char) v); + i += 3; + continue; + } + } + g_string_append_c (str, ch); + i++; + } + + return (*out_to_free = g_string_free (str, FALSE)); +} + +/*****************************************************************************/ + +const char * +nm_keyfile_key_encode (const char *name, + char **out_to_free) +{ + const char *key; + + key = _keyfile_key_encode (name, out_to_free); +#if NM_MORE_ASSERTS > 5 + nm_assert (key); + nm_assert (!*out_to_free || key == *out_to_free); + nm_assert (!*out_to_free || !nm_streq0 (name, key)); + { + gs_free char *to_free2 = NULL; + const char *name2; + + name2 = _keyfile_key_decode (key, &to_free2); + /* name2, the result of encode()+decode() is identical to name. + * That is because + * - encode() is a injective function. + * - decode() is a surjective function, however for output + * values of encode() is behaves injective too. */ + nm_assert (nm_streq0 (name2, name)); + } +#endif + return key; +} + +const char * +nm_keyfile_key_decode (const char *key, + char **out_to_free) +{ + const char *name; + + name = _keyfile_key_decode (key, out_to_free); +#if NM_MORE_ASSERTS > 5 + nm_assert (name); + nm_assert (!*out_to_free || name == *out_to_free); + { + gs_free char *to_free2 = NULL; + const char *key2; + + key2 = _keyfile_key_encode (name, &to_free2); + /* key2, the result of decode+encode may not be idential + * to the original key. That is, decode() is a surjective + * function mapping different keys to the same name. + * However, decode() behaves injective for input that + * are valid output of encode(). */ + nm_assert (key2); + } +#endif + return name; +} diff --git a/libnm-core/nm-keyfile-utils.h b/libnm-core/nm-keyfile-utils.h index 89fd3041..1f63af8c 100644 --- a/libnm-core/nm-keyfile-utils.h +++ b/libnm-core/nm-keyfile-utils.h @@ -81,5 +81,11 @@ gboolean nm_keyfile_plugin_kf_has_key (GKeyFile *kf, const char *key, GError **error); +const char *nm_keyfile_key_encode (const char *name, + char **out_to_free); + +const char *nm_keyfile_key_decode (const char *key, + char **out_to_free); + #endif /* __NM_KEYFILE_UTILS_H__ */ diff --git a/libnm-core/nm-keyfile-writer.c b/libnm-core/nm-keyfile-writer.c index 3a7007d9..6a3d9a9f 100644 --- a/libnm-core/nm-keyfile-writer.c +++ b/libnm-core/nm-keyfile-writer.c @@ -138,7 +138,7 @@ write_ip_values (GKeyFile *file, int family, i; const char *addr, *gw; guint32 plen, metric; - char key_name[30], *key_name_idx; + char key_name[64], *key_name_idx; if (!array->len) return; @@ -188,6 +188,23 @@ write_ip_values (GKeyFile *file, sprintf (key_name_idx, "%d", i + 1); nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, output->str); + + if (is_route) { + gs_free char *attributes = NULL; + gs_strfreev char **names = NULL; + gs_unref_hashtable GHashTable *hash = g_hash_table_new (g_str_hash, g_str_equal); + int j; + + names = nm_ip_route_get_attribute_names (array->pdata[i]); + for (j = 0; names && names[j]; j++) + g_hash_table_insert (hash, names[j], nm_ip_route_get_attribute (array->pdata[i], names[j])); + + attributes = nm_utils_format_variant_attributes (hash, ',', '='); + if (attributes) { + g_strlcat (key_name, "_options", sizeof (key_name)); + nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, attributes); + } + } } g_string_free (output, TRUE); } @@ -283,8 +300,12 @@ write_hash_of_string (GKeyFile *file, } if (write_item) { + gs_free char *to_free = NULL; + data = g_hash_table_lookup (hash, property); - nm_keyfile_plugin_kf_set_string (file, group_name, property, data); + nm_keyfile_plugin_kf_set_string (file, group_name, + nm_keyfile_key_encode (property, &to_free), + data); } } } @@ -373,68 +394,6 @@ password_raw_writer (KeyfileWriterInfo *info, nm_keyfile_plugin_kf_set_integer_list_uint8 (info->keyfile, setting_name, key, data, len); } -typedef struct ObjectType { - const char *key; - const char *suffix; - NMSetting8021xCKScheme (*scheme_func) (NMSetting8021x *setting); - NMSetting8021xCKFormat (*format_func) (NMSetting8021x *setting); - const char * (*path_func) (NMSetting8021x *setting); - GBytes * (*blob_func) (NMSetting8021x *setting); - const char * (*uri_func) (NMSetting8021x *setting); -} ObjectType; - -static const ObjectType objtypes[10] = { - { NM_SETTING_802_1X_CA_CERT, - "ca-cert", - nm_setting_802_1x_get_ca_cert_scheme, - NULL, - nm_setting_802_1x_get_ca_cert_path, - nm_setting_802_1x_get_ca_cert_blob, - nm_setting_802_1x_get_ca_cert_uri }, - - { NM_SETTING_802_1X_PHASE2_CA_CERT, - "inner-ca-cert", - nm_setting_802_1x_get_phase2_ca_cert_scheme, - NULL, - nm_setting_802_1x_get_phase2_ca_cert_path, - nm_setting_802_1x_get_phase2_ca_cert_blob, - nm_setting_802_1x_get_phase2_ca_cert_uri }, - - { NM_SETTING_802_1X_CLIENT_CERT, - "client-cert", - nm_setting_802_1x_get_client_cert_scheme, - NULL, - nm_setting_802_1x_get_client_cert_path, - nm_setting_802_1x_get_client_cert_blob, - nm_setting_802_1x_get_client_cert_uri }, - - { NM_SETTING_802_1X_PHASE2_CLIENT_CERT, - "inner-client-cert", - nm_setting_802_1x_get_phase2_client_cert_scheme, - NULL, - nm_setting_802_1x_get_phase2_client_cert_path, - nm_setting_802_1x_get_phase2_client_cert_blob, - nm_setting_802_1x_get_phase2_client_cert_uri }, - - { NM_SETTING_802_1X_PRIVATE_KEY, - "private-key", - nm_setting_802_1x_get_private_key_scheme, - nm_setting_802_1x_get_private_key_format, - nm_setting_802_1x_get_private_key_path, - nm_setting_802_1x_get_private_key_blob, - nm_setting_802_1x_get_private_key_uri }, - - { NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, - "inner-private-key", - nm_setting_802_1x_get_phase2_private_key_scheme, - nm_setting_802_1x_get_phase2_private_key_format, - nm_setting_802_1x_get_phase2_private_key_path, - nm_setting_802_1x_get_phase2_private_key_blob, - nm_setting_802_1x_get_phase2_private_key_uri }, - - { NULL }, -}; - /*****************************************************************************/ static void @@ -445,13 +404,13 @@ cert_writer_default (NMConnection *connection, const char *setting_name = nm_setting_get_name (NM_SETTING (cert_data->setting)); NMSetting8021xCKScheme scheme; - scheme = cert_data->scheme_func (cert_data->setting); + scheme = cert_data->vtable->scheme_func (cert_data->setting); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { const char *path; char *path_free = NULL, *tmp; gs_free char *base_dir = NULL; - path = cert_data->path_func (cert_data->setting); + path = cert_data->vtable->path_func (cert_data->setting); g_assert (path); /* If the path is relative, make it an absolute path. @@ -475,7 +434,7 @@ cert_writer_default (NMConnection *connection, /* Path contains at least a '/', hence it cannot be recognized as the old * binary format consisting of a list of integers. */ - nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, path); + nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, path); g_free (tmp); g_free (path_free); } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { @@ -484,19 +443,19 @@ cert_writer_default (NMConnection *connection, gsize blob_len; char *blob_base64, *val; - blob = cert_data->blob_func (cert_data->setting); + blob = cert_data->vtable->blob_func (cert_data->setting); g_assert (blob); blob_data = g_bytes_get_data (blob, &blob_len); blob_base64 = g_base64_encode (blob_data, blob_len); val = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB, blob_base64, NULL); - nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, val); + nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, val); g_free (val); g_free (blob_base64); } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { - nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->property_name, - cert_data->uri_func (cert_data->setting)); + nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, + cert_data->vtable->uri_func (cert_data->setting)); } else { /* scheme_func() returns UNKNOWN in all other cases. The only valid case * where a scheme is allowed to be UNKNOWN, is unsetting the value. In this @@ -514,13 +473,13 @@ cert_writer (KeyfileWriterInfo *info, const char *key, const GValue *value) { - const ObjectType *objtype = NULL; + const NMSetting8021xSchemeVtable *objtype = NULL; guint i; NMKeyfileWriteTypeDataCert type_data = { 0 }; - for (i = 0; i < G_N_ELEMENTS (objtypes) && objtypes[i].key; i++) { - if (g_strcmp0 (objtypes[i].key, key) == 0) { - objtype = &objtypes[i]; + for (i = 0; nm_setting_8021x_scheme_vtable[i].setting_key; i++) { + if (g_strcmp0 (nm_setting_8021x_scheme_vtable[i].setting_key, key) == 0) { + objtype = &nm_setting_8021x_scheme_vtable[i]; break; } } @@ -528,13 +487,7 @@ cert_writer (KeyfileWriterInfo *info, g_return_if_reached (); type_data.setting = NM_SETTING_802_1X (setting); - type_data.property_name = key; - type_data.suffix = objtype->suffix; - type_data.scheme_func = objtype->scheme_func; - type_data.format_func = objtype->format_func; - type_data.path_func = objtype->path_func; - type_data.blob_func = objtype->blob_func; - type_data.uri_func = objtype->uri_func; + type_data.vtable = objtype; if (info->handler) { if (info->handler (info->connection, diff --git a/libnm-core/nm-property-compare.c b/libnm-core/nm-property-compare.c index ab19cd71..d13d019f 100644 --- a/libnm-core/nm-property-compare.c +++ b/libnm-core/nm-property-compare.c @@ -23,7 +23,6 @@ #include "nm-default.h" #include <string.h> -#include <math.h> #include <netinet/in.h> #include "nm-property-compare.h" diff --git a/libnm-core/nm-setting-8021x.c b/libnm-core/nm-setting-8021x.c index 97296650..ab0f5c66 100644 --- a/libnm-core/nm-setting-8021x.c +++ b/libnm-core/nm-setting-8021x.c @@ -77,22 +77,31 @@ typedef struct { char *anonymous_identity; char *pac_file; GBytes *ca_cert; + char *ca_cert_password; + NMSettingSecretFlags ca_cert_password_flags; char *ca_path; char *subject_match; GSList *altsubject_matches; char *domain_suffix_match; GBytes *client_cert; + char *client_cert_password; + NMSettingSecretFlags client_cert_password_flags; char *phase1_peapver; char *phase1_peaplabel; char *phase1_fast_provisioning; + NMSetting8021xAuthFlags phase1_auth_flags; char *phase2_auth; char *phase2_autheap; GBytes *phase2_ca_cert; + char *phase2_ca_cert_password; + NMSettingSecretFlags phase2_ca_cert_password_flags; char *phase2_ca_path; char *phase2_subject_match; GSList *phase2_altsubject_matches; char *phase2_domain_suffix_match; GBytes *phase2_client_cert; + char *phase2_client_cert_password; + NMSettingSecretFlags phase2_client_cert_password_flags; char *password; NMSettingSecretFlags password_flags; GBytes *password_raw; @@ -106,6 +115,7 @@ typedef struct { char *phase2_private_key_password; NMSettingSecretFlags phase2_private_key_password_flags; gboolean system_ca_certs; + gint auth_timeout; } NMSetting8021xPrivate; enum { @@ -115,22 +125,31 @@ enum { PROP_ANONYMOUS_IDENTITY, PROP_PAC_FILE, PROP_CA_CERT, + PROP_CA_CERT_PASSWORD, + PROP_CA_CERT_PASSWORD_FLAGS, PROP_CA_PATH, PROP_SUBJECT_MATCH, PROP_ALTSUBJECT_MATCHES, PROP_DOMAIN_SUFFIX_MATCH, PROP_CLIENT_CERT, + PROP_CLIENT_CERT_PASSWORD, + PROP_CLIENT_CERT_PASSWORD_FLAGS, PROP_PHASE1_PEAPVER, PROP_PHASE1_PEAPLABEL, PROP_PHASE1_FAST_PROVISIONING, + PROP_PHASE1_AUTH_FLAGS, PROP_PHASE2_AUTH, PROP_PHASE2_AUTHEAP, PROP_PHASE2_CA_CERT, + PROP_PHASE2_CA_CERT_PASSWORD, + PROP_PHASE2_CA_CERT_PASSWORD_FLAGS, PROP_PHASE2_CA_PATH, PROP_PHASE2_SUBJECT_MATCH, PROP_PHASE2_ALTSUBJECT_MATCHES, PROP_PHASE2_DOMAIN_SUFFIX_MATCH, PROP_PHASE2_CLIENT_CERT, + PROP_PHASE2_CLIENT_CERT_PASSWORD, + PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS, PROP_PASSWORD, PROP_PASSWORD_FLAGS, PROP_PASSWORD_RAW, @@ -144,6 +163,7 @@ enum { PROP_PIN, PROP_PIN_FLAGS, PROP_SYSTEM_CA_CERTS, + PROP_AUTH_TIMEOUT, LAST_PROP }; @@ -161,6 +181,8 @@ nm_setting_802_1x_new (void) return (NMSetting *) g_object_new (NM_TYPE_SETTING_802_1X, NULL); } +/*****************************************************************************/ + /** * nm_setting_802_1x_get_num_eap_methods: * @setting: the #NMSetting8021x @@ -740,6 +762,41 @@ nm_setting_802_1x_set_ca_cert (NMSetting8021x *setting, } /** + * nm_setting_802_1x_get_ca_cert_password: + * @setting: the #NMSetting8021x + * + * Returns: the password used to access the CA certificate stored in + * #NMSetting8021x:ca-cert property. Only makes sense if the certificate + * is stored on a PKCS#<!-- -->11 token that requires a login. + * + * Since: 1.8 + **/ +const char * +nm_setting_802_1x_get_ca_cert_password (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert_password; +} + +/** + * nm_setting_802_1x_get_ca_cert_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:ca-cert-password + * + * Since: 1.8 + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_ca_cert_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->ca_cert_password_flags; +} + +/** * nm_setting_802_1x_get_subject_match: * @setting: the #NMSetting8021x * @@ -1121,6 +1178,41 @@ nm_setting_802_1x_set_client_cert (NMSetting8021x *setting, } /** + * nm_setting_802_1x_get_client_cert_password: + * @setting: the #NMSetting8021x + * + * Returns: the password used to access the client certificate stored in + * #NMSetting8021x:client-cert property. Only makes sense if the certificate + * is stored on a PKCS#<!-- -->11 token that requires a login. + * + * Since: 1.8 + **/ +const char * +nm_setting_802_1x_get_client_cert_password (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert_password; +} + +/** + * nm_setting_802_1x_get_client_cert_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:client-cert-password + * + * Since: 1.8 + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_client_cert_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->client_cert_password_flags; +} + +/** * nm_setting_802_1x_get_phase1_peapver: * @setting: the #NMSetting8021x * @@ -1171,6 +1263,22 @@ nm_setting_802_1x_get_phase1_fast_provisioning (NMSetting8021x *setting) } /** + * nm_setting_802_1x_get_phase1_auth_flags: + * @setting: the #NMSetting8021x + * + * Returns: the authentication flags for "phase 1". + * + * Since: 1.8 + */ +NMSetting8021xAuthFlags +nm_setting_802_1x_get_phase1_auth_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), 0); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase1_auth_flags; +} + +/** * nm_setting_802_1x_get_phase2_auth: * @setting: the #NMSetting8021x * @@ -1413,6 +1521,41 @@ nm_setting_802_1x_set_phase2_ca_cert (NMSetting8021x *setting, } /** + * nm_setting_802_1x_get_phase2_ca_cert_password: + * @setting: the #NMSetting8021x + * + * Returns: the password used to access the "phase2" CA certificate stored in + * #NMSetting8021x:phase2-ca-cert property. Only makes sense if the certificate + * is stored on a PKCS#<!-- -->11 token that requires a login. + * + * Since: 1.8 + **/ +const char * +nm_setting_802_1x_get_phase2_ca_cert_password (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert_password; +} + +/** + * nm_setting_802_1x_get_phase2_ca_cert_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:phase2-private-key-password + * + * Since: 1.8 + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_phase2_ca_cert_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_ca_cert_password_flags; +} + +/** * nm_setting_802_1x_get_phase2_subject_match: * @setting: the #NMSetting8021x * @@ -1800,6 +1943,41 @@ nm_setting_802_1x_set_phase2_client_cert (NMSetting8021x *setting, } /** + * nm_setting_802_1x_get_phase2_client_cert_password: + * @setting: the #NMSetting8021x + * + * Returns: the password used to access the "phase2" client certificate stored in + * #NMSetting8021x:phase2-client-cert property. Only makes sense if the certificate + * is stored on a PKCS#<!-- -->11 token that requires a login. + * + * Since: 1.8 + **/ +const char * +nm_setting_802_1x_get_phase2_client_cert_password (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NULL); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert_password; +} + +/** + * nm_setting_802_1x_get_phase2_client_cert_password_flags: + * @setting: the #NMSetting8021x + * + * Returns: the #NMSettingSecretFlags pertaining to the + * #NMSetting8021x:phase2-client-cert-password + * + * Since: 1.8 + **/ +NMSettingSecretFlags +nm_setting_802_1x_get_phase2_client_cert_password_flags (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), NM_SETTING_SECRET_FLAG_NONE); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->phase2_client_cert_password_flags; +} + +/** * nm_setting_802_1x_get_password: * @setting: the #NMSetting8021x * @@ -2548,6 +2726,25 @@ nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting) return NM_SETTING_802_1X_CK_FORMAT_UNKNOWN; } +/** + * nm_setting_802_1x_get_auth_timeout: + * @setting: the #NMSetting8021x + * + * Returns the value contained in the #NMSetting8021x:auth-timeout property. + * + * Returns: the configured authentication timeout in seconds. Zero means the + * global default value. + * + * Since: 1.8 + **/ +gint +nm_setting_802_1x_get_auth_timeout (NMSetting8021x *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_802_1X (setting), 0); + + return NM_SETTING_802_1X_GET_PRIVATE (setting)->auth_timeout; +} + static void need_secrets_password (NMSetting8021x *self, GPtrArray *secrets, @@ -2576,10 +2773,14 @@ need_secrets_sim (NMSetting8021x *self, static gboolean need_private_key_password (GBytes *blob, const char *path, - const char *password) + const char *password, + NMSettingSecretFlags flags) { NMCryptoFileFormat format = NM_CRYPTO_FILE_FORMAT_UNKNOWN; + if (flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) + return FALSE; + /* Private key password is required */ if (password) { if (path) @@ -2589,7 +2790,7 @@ need_private_key_password (GBytes *blob, g_bytes_get_size (blob), password, NULL, NULL); else - g_warning ("%s: unknown private key password scheme", __func__); + return FALSE; } return (format == NM_CRYPTO_FILE_FORMAT_UNKNOWN); @@ -2609,34 +2810,52 @@ need_secrets_tls (NMSetting8021x *self, scheme = nm_setting_802_1x_get_phase2_private_key_scheme (self); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) path = nm_setting_802_1x_get_phase2_private_key_path (self); - else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) - return; else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) blob = nm_setting_802_1x_get_phase2_private_key_blob (self); - else { + else if (scheme != NM_SETTING_802_1X_CK_SCHEME_PKCS11) g_warning ("%s: unknown phase2 private key scheme %d", __func__, scheme); - g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY); - return; - } - if (need_private_key_password (blob, path, priv->phase2_private_key_password)) + if (need_private_key_password (blob, path, + priv->phase2_private_key_password, + priv->phase2_private_key_password_flags)) g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY_PASSWORD); + + scheme = nm_setting_802_1x_get_phase2_ca_cert_scheme (self); + if ( scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11 + && !(priv->phase2_ca_cert_password_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) + && !priv->phase2_ca_cert_password) + g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD); + + scheme = nm_setting_802_1x_get_phase2_client_cert_scheme (self); + if ( scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11 + && !(priv->phase2_client_cert_password_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) + && !priv->phase2_client_cert_password) + g_ptr_array_add (secrets, NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD); } else { scheme = nm_setting_802_1x_get_private_key_scheme (self); if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) path = nm_setting_802_1x_get_private_key_path (self); - else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) - return; else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) blob = nm_setting_802_1x_get_private_key_blob (self); - else { + else if (scheme != NM_SETTING_802_1X_CK_SCHEME_PKCS11) g_warning ("%s: unknown private key scheme %d", __func__, scheme); - g_ptr_array_add (secrets, NM_SETTING_802_1X_PRIVATE_KEY); - return; - } - if (need_private_key_password (blob, path, priv->private_key_password)) + if (need_private_key_password (blob, path, + priv->private_key_password, + priv->private_key_password_flags)) g_ptr_array_add (secrets, NM_SETTING_802_1X_PRIVATE_KEY_PASSWORD); + + scheme = nm_setting_802_1x_get_ca_cert_scheme (self); + if ( scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11 + && !(priv->ca_cert_password_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) + && !priv->ca_cert_password) + g_ptr_array_add (secrets, NM_SETTING_802_1X_CA_CERT_PASSWORD); + + scheme = nm_setting_802_1x_get_client_cert_scheme (self); + if ( scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11 + && !(priv->client_cert_password_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED) + && !priv->client_cert_password) + g_ptr_array_add (secrets, NM_SETTING_802_1X_CLIENT_CERT_PASSWORD); } } @@ -2951,21 +3170,37 @@ need_secrets (NMSetting *setting) } static gboolean -verify_cert (GBytes *bytes, const char *prop_name, GError **error) +verify_cert (GBytes *bytes, const char *prop_name, + const char *password, const char *password_prop_name, GError **error) { GError *local = NULL; + NMSetting8021xCKScheme scheme; - if ( !bytes - || get_cert_scheme (bytes, &local) != NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) + if (bytes) + scheme = get_cert_scheme (bytes, &local); + else return TRUE; - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("certificate is invalid: %s"), local->message); - g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, prop_name); - g_error_free (local); - return FALSE; + if (scheme == NM_SETTING_802_1X_CK_SCHEME_UNKNOWN) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("certificate is invalid: %s"), local->message); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, prop_name); + g_error_free (local); + return FALSE; + } + + if (password && (scheme != NM_SETTING_802_1X_CK_SCHEME_PKCS11)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("password is not supported when certificate is not on a PKCS#11 token")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, password_prop_name); + return FALSE; + } + + return TRUE; } static gboolean @@ -3048,6 +3283,15 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if (NM_FLAGS_ANY (priv->phase1_auth_flags, ~NM_SETTING_802_1X_AUTH_FLAGS_ALL)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("invalid auth flags")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_802_1X_SETTING_NAME, NM_SETTING_802_1X_PHASE1_AUTH_FLAGS); + return FALSE; + } + if (priv->phase2_auth && !g_strv_contains (valid_phase2_auth, priv->phase2_auth)) { g_set_error (error, NM_CONNECTION_ERROR, @@ -3068,19 +3312,23 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } - if (!verify_cert (priv->ca_cert, NM_SETTING_802_1X_CA_CERT, error)) + if (!verify_cert (priv->ca_cert, NM_SETTING_802_1X_CA_CERT, + priv->ca_cert_password, NM_SETTING_802_1X_CA_CERT_PASSWORD, error)) return FALSE; - if (!verify_cert (priv->phase2_ca_cert, NM_SETTING_802_1X_PHASE2_CA_CERT, error)) + if (!verify_cert (priv->phase2_ca_cert, NM_SETTING_802_1X_PHASE2_CA_CERT, + priv->phase2_ca_cert_password, NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD, error)) return FALSE; - if (!verify_cert (priv->client_cert, NM_SETTING_802_1X_CLIENT_CERT, error)) + if (!verify_cert (priv->client_cert, NM_SETTING_802_1X_CLIENT_CERT, + priv->client_cert_password, NM_SETTING_802_1X_CLIENT_CERT_PASSWORD, error)) return FALSE; - if (!verify_cert (priv->phase2_client_cert, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, error)) + if (!verify_cert (priv->phase2_client_cert, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, + priv->phase2_client_cert_password, NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD, error)) return FALSE; - if (!verify_cert (priv->private_key, NM_SETTING_802_1X_PRIVATE_KEY, error)) + if (!verify_cert (priv->private_key, NM_SETTING_802_1X_PRIVATE_KEY, NULL, NULL, error)) return FALSE; - if (!verify_cert (priv->phase2_private_key, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, error)) + if (!verify_cert (priv->phase2_private_key, NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, NULL, NULL, error)) return FALSE; /* FIXME: finish */ @@ -3125,15 +3373,19 @@ finalize (GObject *object) if (priv->ca_cert) g_bytes_unref (priv->ca_cert); + g_free (priv->ca_cert_password); if (priv->client_cert) g_bytes_unref (priv->client_cert); + g_free (priv->client_cert_password); if (priv->private_key) g_bytes_unref (priv->private_key); g_free (priv->private_key_password); if (priv->phase2_ca_cert) g_bytes_unref (priv->phase2_ca_cert); + g_free (priv->phase2_ca_cert_password); if (priv->phase2_client_cert) g_bytes_unref (priv->phase2_client_cert); + g_free (priv->phase2_client_cert_password); if (priv->phase2_private_key) g_bytes_unref (priv->phase2_private_key); g_free (priv->phase2_private_key_password); @@ -3150,7 +3402,7 @@ set_cert_prop_helper (const GValue *value, const char *prop_name, GError **error bytes = g_value_dup_boxed (value); /* Verify the new data */ if (bytes) { - valid = verify_cert (bytes, prop_name, error); + valid = verify_cert (bytes, prop_name, NULL, NULL, error); if (!valid) g_clear_pointer (&bytes, g_bytes_unref); } @@ -3191,6 +3443,13 @@ set_property (GObject *object, guint prop_id, g_error_free (error); } break; + case PROP_CA_CERT_PASSWORD: + g_free (priv->ca_cert_password); + priv->ca_cert_password = g_value_dup_string (value); + break; + case PROP_CA_CERT_PASSWORD_FLAGS: + priv->ca_cert_password_flags = g_value_get_flags (value); + break; case PROP_CA_PATH: g_free (priv->ca_path); priv->ca_path = g_value_dup_string (value); @@ -3216,6 +3475,13 @@ set_property (GObject *object, guint prop_id, g_error_free (error); } break; + case PROP_CLIENT_CERT_PASSWORD: + g_free (priv->client_cert_password); + priv->client_cert_password = g_value_dup_string (value); + break; + case PROP_CLIENT_CERT_PASSWORD_FLAGS: + priv->client_cert_password_flags = g_value_get_flags (value); + break; case PROP_PHASE1_PEAPVER: g_free (priv->phase1_peapver); priv->phase1_peapver = g_value_dup_string (value); @@ -3228,6 +3494,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->phase1_fast_provisioning); priv->phase1_fast_provisioning = g_value_dup_string (value); break; + case PROP_PHASE1_AUTH_FLAGS: + priv->phase1_auth_flags = g_value_get_uint (value); + break; case PROP_PHASE2_AUTH: g_free (priv->phase2_auth); priv->phase2_auth = g_value_dup_string (value); @@ -3245,6 +3514,13 @@ set_property (GObject *object, guint prop_id, g_error_free (error); } break; + case PROP_PHASE2_CA_CERT_PASSWORD: + g_free (priv->phase2_ca_cert_password); + priv->phase2_ca_cert_password = g_value_dup_string (value); + break; + case PROP_PHASE2_CA_CERT_PASSWORD_FLAGS: + priv->phase2_ca_cert_password_flags = g_value_get_flags (value); + break; case PROP_PHASE2_CA_PATH: g_free (priv->phase2_ca_path); priv->phase2_ca_path = g_value_dup_string (value); @@ -3262,6 +3538,7 @@ set_property (GObject *object, guint prop_id, priv->phase2_domain_suffix_match = nm_strdup_not_empty (g_value_get_string (value)); break; case PROP_PHASE2_CLIENT_CERT: + if (priv->phase2_client_cert) g_bytes_unref (priv->phase2_client_cert); priv->phase2_client_cert = set_cert_prop_helper (value, NM_SETTING_802_1X_PHASE2_CLIENT_CERT, &error); @@ -3270,6 +3547,13 @@ set_property (GObject *object, guint prop_id, g_error_free (error); } break; + case PROP_PHASE2_CLIENT_CERT_PASSWORD: + g_free (priv->phase2_client_cert_password); + priv->phase2_client_cert_password = g_value_dup_string (value); + break; + case PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS: + priv->phase2_client_cert_password_flags = g_value_get_flags (value); + break; case PROP_PASSWORD: g_free (priv->password); priv->password = g_value_dup_string (value); @@ -3327,6 +3611,9 @@ set_property (GObject *object, guint prop_id, case PROP_SYSTEM_CA_CERTS: priv->system_ca_certs = g_value_get_boolean (value); break; + case PROP_AUTH_TIMEOUT: + priv->auth_timeout = g_value_get_int (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3356,6 +3643,12 @@ get_property (GObject *object, guint prop_id, case PROP_CA_CERT: g_value_set_boxed (value, priv->ca_cert); break; + case PROP_CA_CERT_PASSWORD: + g_value_set_string (value, priv->ca_cert_password); + break; + case PROP_CA_CERT_PASSWORD_FLAGS: + g_value_set_flags (value, priv->ca_cert_password_flags); + break; case PROP_CA_PATH: g_value_set_string (value, priv->ca_path); break; @@ -3371,6 +3664,12 @@ get_property (GObject *object, guint prop_id, case PROP_CLIENT_CERT: g_value_set_boxed (value, priv->client_cert); break; + case PROP_CLIENT_CERT_PASSWORD: + g_value_set_string (value, priv->client_cert_password); + break; + case PROP_CLIENT_CERT_PASSWORD_FLAGS: + g_value_set_flags (value, priv->client_cert_password_flags); + break; case PROP_PHASE1_PEAPVER: g_value_set_string (value, priv->phase1_peapver); break; @@ -3380,6 +3679,9 @@ get_property (GObject *object, guint prop_id, case PROP_PHASE1_FAST_PROVISIONING: g_value_set_string (value, priv->phase1_fast_provisioning); break; + case PROP_PHASE1_AUTH_FLAGS: + g_value_set_uint (value, priv->phase1_auth_flags); + break; case PROP_PHASE2_AUTH: g_value_set_string (value, priv->phase2_auth); break; @@ -3389,6 +3691,12 @@ get_property (GObject *object, guint prop_id, case PROP_PHASE2_CA_CERT: g_value_set_boxed (value, priv->phase2_ca_cert); break; + case PROP_PHASE2_CA_CERT_PASSWORD: + g_value_set_string (value, priv->phase2_ca_cert_password); + break; + case PROP_PHASE2_CA_CERT_PASSWORD_FLAGS: + g_value_set_flags (value, priv->phase2_ca_cert_password_flags); + break; case PROP_PHASE2_CA_PATH: g_value_set_string (value, priv->phase2_ca_path); break; @@ -3404,6 +3712,12 @@ get_property (GObject *object, guint prop_id, case PROP_PHASE2_CLIENT_CERT: g_value_set_boxed (value, priv->phase2_client_cert); break; + case PROP_PHASE2_CLIENT_CERT_PASSWORD: + g_value_set_string (value, priv->phase2_client_cert_password); + break; + case PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS: + g_value_set_flags (value, priv->phase2_client_cert_password_flags); + break; case PROP_PASSWORD: g_value_set_string (value, priv->password); break; @@ -3443,6 +3757,9 @@ get_property (GObject *object, guint prop_id, case PROP_SYSTEM_CA_CERTS: g_value_set_boolean (value, priv->system_ca_certs); break; + case PROP_AUTH_TIMEOUT: + g_value_set_int (value, priv->auth_timeout); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -3583,6 +3900,44 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) G_PARAM_STATIC_STRINGS)); /** + * NMSetting8021x:ca-cert-password: + * + * The password used to access the CA certificate stored in + * #NMSetting8021x:ca-cert property. Only makes sense if the certificate + * is stored on a PKCS#<!-- -->11 token that requires a login. + * + * Since: 1.8 + **/ + /* ---ifcfg-rh--- + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_CA_CERT_PASSWORD, + g_param_spec_string (NM_SETTING_802_1X_CA_CERT_PASSWORD, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_SECRET | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:ca-cert-password-flags: + * + * Flags indicating how to handle the #NMSetting8021x:ca-cert-password property. + * + * Since: 1.8 + **/ + /* ---ifcfg-rh--- + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_CA_CERT_PASSWORD_FLAGS, + g_param_spec_flags (NM_SETTING_802_1X_CA_CERT_PASSWORD_FLAGS, "", "", + NM_TYPE_SETTING_SECRET_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** * NMSetting8021x:ca-path: * * UTF-8 encoded path to a directory containing PEM or DER formatted @@ -3701,6 +4056,44 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) G_PARAM_STATIC_STRINGS)); /** + * NMSetting8021x:client-cert-password: + * + * The password used to access the client certificate stored in + * #NMSetting8021x:client-cert property. Only makes sense if the certificate + * is stored on a PKCS#<!-- -->11 token that requires a login. + * + * Since: 1.8 + **/ + /* ---ifcfg-rh--- + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_CLIENT_CERT_PASSWORD, + g_param_spec_string (NM_SETTING_802_1X_CLIENT_CERT_PASSWORD, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_SECRET | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:client-cert-password-flags: + * + * Flags indicating how to handle the #NMSetting8021x:client-cert-password property. + * + * Since: 1.8 + **/ + /* ---ifcfg-rh--- + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_CLIENT_CERT_PASSWORD_FLAGS, + g_param_spec_flags (NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS, "", "", + NM_TYPE_SETTING_SECRET_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** * NMSetting8021x:phase1-peapver: * * Forces which PEAP version is used when PEAP is set as the EAP method in @@ -3773,6 +4166,34 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) G_PARAM_STATIC_STRINGS)); /** + * NMSetting8021x:phase1-auth-flags: + * + * Specifies authentication flags to use in "phase 1" outer + * authentication using #NMSetting8021xAuthFlags options. + * The invidual TLS versions can be explicitly disabled. If a certain + * TLS disable flag is not set, it is up to the supplicant to allow + * or forbid it. The TLS options map to tls_disable_tlsv1_x settings. + * See the wpa_supplicant documentation for more details. + * + * Since: 1.8 + */ + /* ---ifcfg-rh--- + * property: phase1-auth-flags + * variable: IEEE_8021X_PHASE1_AUTH_FLAGS(+) + * values: space-separated list of authentication flags names + * description: Authentication flags for the supplicant + * example: IEEE_8021X_PHASE1_AUTH_FLAGS="tls-1-0-disable tls-1-1-disable" + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE1_AUTH_FLAGS, + g_param_spec_uint (NM_SETTING_802_1X_PHASE1_AUTH_FLAGS, "", "", + 0, G_MAXUINT32, NM_SETTING_802_1X_AUTH_FLAGS_NONE, + G_PARAM_CONSTRUCT | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** * NMSetting8021x:phase2-auth: * * Specifies the allowed "phase 2" inner non-EAP authentication methods when @@ -3851,6 +4272,44 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) G_PARAM_STATIC_STRINGS)); /** + * NMSetting8021x:phase2-ca-cert-password: + * + * The password used to access the "phase2" CA certificate stored in + * #NMSetting8021x:phase2-ca-cert property. Only makes sense if the certificate + * is stored on a PKCS#<!-- -->11 token that requires a login. + * + * Since: 1.8 + **/ + /* ---ifcfg-rh--- + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_CA_CERT_PASSWORD, + g_param_spec_string (NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_SECRET | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-ca-cert-password-flags: + * + * Flags indicating how to handle the #NMSetting8021x:phase2-ca-cert-password property. + * + * Since: 1.8 + **/ + /* ---ifcfg-rh--- + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_CA_CERT_PASSWORD_FLAGS, + g_param_spec_flags (NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD_FLAGS, "", "", + NM_TYPE_SETTING_SECRET_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /** * NMSetting8021x:phase2-ca-path: * * UTF-8 encoded path to a directory containing PEM or DER formatted @@ -3966,6 +4425,47 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + + + /** + * NMSetting8021x:phase2-client-cert-password: + * + * The password used to access the "phase2" client certificate stored in + * #NMSetting8021x:phase2-client-cert property. Only makes sense if the certificate + * is stored on a PKCS#<!-- -->11 token that requires a login. + * + * Since: 1.8 + **/ + /* ---ifcfg-rh--- + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_CLIENT_CERT_PASSWORD, + g_param_spec_string (NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_SECRET | + G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:phase2-client-cert-password-flags: + * + * Flags indicating how to handle the #NMSetting8021x:phase2-client-cert-password property. + * + * Since: 1.8 + **/ + /* ---ifcfg-rh--- + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_PHASE2_CLIENT_CERT_PASSWORD_FLAGS, + g_param_spec_flags (NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS, "", "", + NM_TYPE_SETTING_SECRET_FLAGS, + NM_SETTING_SECRET_FLAG_NONE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + /** * NMSetting8021x:password: * @@ -4066,7 +4566,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) * property must be set to password used to decrypt the PKCS#<!-- -->12 * certificate and key. When using PKCS#<!-- -->12 files and the path * scheme, this property should be set to the full UTF-8 encoded path of the - * key, prefixed with the string "file://" and and ending with a terminating + * key, prefixed with the string "file://" and ending with a terminating * NUL byte, and as with the blob scheme the "private-key-password" property * must be set to the password used to decode the PKCS#<!-- -->12 private * key and certificate. @@ -4158,7 +4658,7 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) * property must be set to password used to decrypt the PKCS#<!-- -->12 * certificate and key. When using PKCS#<!-- -->12 files and the path * scheme, this property should be set to the full UTF-8 encoded path of the - * key, prefixed with the string "file://" and and ending with a terminating + * key, prefixed with the string "file://" and ending with a terminating * NUL byte, and as with the blob scheme the * #NMSetting8021x:phase2-private-key-password property must be set to the * password used to decode the PKCS#<!-- -->12 private key and certificate. @@ -4290,4 +4790,28 @@ nm_setting_802_1x_class_init (NMSetting8021xClass *setting_class) G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + + /** + * NMSetting8021x:auth-timeout: + * + * A timeout for the authentication. Zero means the global default; if the + * global default is not set, the authentication timeout is 25 seconds. + * + * Since: 1.8 + **/ + /* ---ifcfg-rh--- + * property: auth-timeout + * variable: IEEE_8021X_AUTH_TIMEOUT(+) + * default: 0 + * description: Timeout in seconds for the 802.1X authentication. Zero means the global default or 25. + * ---end--- + */ + g_object_class_install_property + (object_class, PROP_AUTH_TIMEOUT, + g_param_spec_int (NM_SETTING_802_1X_AUTH_TIMEOUT, "", "", + 0, G_MAXINT32, 0, + G_PARAM_READWRITE | + NM_SETTING_PARAM_FUZZY_IGNORE | + G_PARAM_STATIC_STRINGS)); + } diff --git a/libnm-core/nm-setting-8021x.h b/libnm-core/nm-setting-8021x.h index 9e58e4e2..0f5f7ddd 100644 --- a/libnm-core/nm-setting-8021x.h +++ b/libnm-core/nm-setting-8021x.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -75,6 +75,28 @@ typedef enum { /*< underscore_name=nm_setting_802_1x_ck_scheme >*/ NM_SETTING_802_1X_CK_SCHEME_PKCS11, } NMSetting8021xCKScheme; +/** + * NMSetting8021xAuthFlags: + * @NM_SETTING_802_1X_AUTH_FLAGS_NONE: No flags + * @NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE: Disable TLSv1.0 + * @NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE: Disable TLSv1.1 + * @NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_2_DISABLE: Disable TLSv1.2 + * @NM_SETTING_802_1X_AUTH_FLAGS_ALL: All supported flags + * + * #NMSetting8021xAuthFlags values indicate which authentication settings + * should be used. + * + * Since: 1.8 + */ +typedef enum { /*< underscore_name=nm_setting_802_1x_auth_flags >*/ + NM_SETTING_802_1X_AUTH_FLAGS_NONE = 0, + NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_0_DISABLE = (1 << 0), + NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_1_DISABLE = (1 << 1), + NM_SETTING_802_1X_AUTH_FLAGS_TLS_1_2_DISABLE = (1 << 2), + + _NM_SETTING_802_1X_AUTH_FLAGS_LAST, /*< skip >*/ + NM_SETTING_802_1X_AUTH_FLAGS_ALL = (((_NM_SETTING_802_1X_AUTH_FLAGS_LAST - 1) << 1) - 1), +} NMSetting8021xAuthFlags; #define NM_TYPE_SETTING_802_1X (nm_setting_802_1x_get_type ()) #define NM_SETTING_802_1X(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_802_1X, NMSetting8021x)) @@ -90,22 +112,31 @@ typedef enum { /*< underscore_name=nm_setting_802_1x_ck_scheme >*/ #define NM_SETTING_802_1X_ANONYMOUS_IDENTITY "anonymous-identity" #define NM_SETTING_802_1X_PAC_FILE "pac-file" #define NM_SETTING_802_1X_CA_CERT "ca-cert" +#define NM_SETTING_802_1X_CA_CERT_PASSWORD "ca-cert-password" +#define NM_SETTING_802_1X_CA_CERT_PASSWORD_FLAGS "ca-cert-password-flags" #define NM_SETTING_802_1X_CA_PATH "ca-path" #define NM_SETTING_802_1X_SUBJECT_MATCH "subject-match" #define NM_SETTING_802_1X_ALTSUBJECT_MATCHES "altsubject-matches" #define NM_SETTING_802_1X_DOMAIN_SUFFIX_MATCH "domain-suffix-match" #define NM_SETTING_802_1X_CLIENT_CERT "client-cert" +#define NM_SETTING_802_1X_CLIENT_CERT_PASSWORD "client-cert-password" +#define NM_SETTING_802_1X_CLIENT_CERT_PASSWORD_FLAGS "client-cert-password-flags" #define NM_SETTING_802_1X_PHASE1_PEAPVER "phase1-peapver" #define NM_SETTING_802_1X_PHASE1_PEAPLABEL "phase1-peaplabel" #define NM_SETTING_802_1X_PHASE1_FAST_PROVISIONING "phase1-fast-provisioning" +#define NM_SETTING_802_1X_PHASE1_AUTH_FLAGS "phase1-auth-flags" #define NM_SETTING_802_1X_PHASE2_AUTH "phase2-auth" #define NM_SETTING_802_1X_PHASE2_AUTHEAP "phase2-autheap" #define NM_SETTING_802_1X_PHASE2_CA_CERT "phase2-ca-cert" +#define NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD "phase2-ca-cert-password" +#define NM_SETTING_802_1X_PHASE2_CA_CERT_PASSWORD_FLAGS "phase2-ca-cert-password-flags" #define NM_SETTING_802_1X_PHASE2_CA_PATH "phase2-ca-path" #define NM_SETTING_802_1X_PHASE2_SUBJECT_MATCH "phase2-subject-match" #define NM_SETTING_802_1X_PHASE2_ALTSUBJECT_MATCHES "phase2-altsubject-matches" #define NM_SETTING_802_1X_PHASE2_DOMAIN_SUFFIX_MATCH "phase2-domain-suffix-match" #define NM_SETTING_802_1X_PHASE2_CLIENT_CERT "phase2-client-cert" +#define NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD "phase2-client-cert-password" +#define NM_SETTING_802_1X_PHASE2_CLIENT_CERT_PASSWORD_FLAGS "phase2-client-cert-password-flags" #define NM_SETTING_802_1X_PASSWORD "password" #define NM_SETTING_802_1X_PASSWORD_FLAGS "password-flags" #define NM_SETTING_802_1X_PASSWORD_RAW "password-raw" @@ -119,6 +150,7 @@ typedef enum { /*< underscore_name=nm_setting_802_1x_ck_scheme >*/ #define NM_SETTING_802_1X_PIN "pin" #define NM_SETTING_802_1X_PIN_FLAGS "pin-flags" #define NM_SETTING_802_1X_SYSTEM_CA_CERTS "system-ca-certs" +#define NM_SETTING_802_1X_AUTH_TIMEOUT "auth-timeout" /* PRIVATE KEY NOTE: when setting PKCS#12 private keys directly via properties * using the "blob" scheme, the data must be passed in PKCS#12 binary format. @@ -142,6 +174,8 @@ typedef enum { /*< underscore_name=nm_setting_802_1x_ck_scheme >*/ /** * NMSetting8021x: + * + * AIEEE 802.1x Authentication Settings */ struct _NMSetting8021x { NMSetting parent; @@ -189,6 +223,11 @@ gboolean nm_setting_802_1x_set_ca_cert (NMSetting8 NMSetting8021xCKFormat *out_format, GError **error); +NM_AVAILABLE_IN_1_8 +const char * nm_setting_802_1x_get_ca_cert_password (NMSetting8021x *setting); +NM_AVAILABLE_IN_1_8 +NMSettingSecretFlags nm_setting_802_1x_get_ca_cert_password_flags (NMSetting8021x *setting); + const char * nm_setting_802_1x_get_subject_match (NMSetting8021x *setting); guint32 nm_setting_802_1x_get_num_altsubject_matches (NMSetting8021x *setting); @@ -215,6 +254,11 @@ gboolean nm_setting_802_1x_set_client_cert (NMSetting8 NMSetting8021xCKFormat *out_format, GError **error); +NM_AVAILABLE_IN_1_8 +const char * nm_setting_802_1x_get_client_cert_password (NMSetting8021x *setting); +NM_AVAILABLE_IN_1_8 +NMSettingSecretFlags nm_setting_802_1x_get_client_cert_password_flags (NMSetting8021x *setting); + const char * nm_setting_802_1x_get_phase1_peapver (NMSetting8021x *setting); const char * nm_setting_802_1x_get_phase1_peaplabel (NMSetting8021x *setting); @@ -236,6 +280,12 @@ gboolean nm_setting_802_1x_set_phase2_ca_cert (NMSetting8 NMSetting8021xCKFormat *out_format, GError **error); + +NM_AVAILABLE_IN_1_8 +const char * nm_setting_802_1x_get_phase2_ca_cert_password (NMSetting8021x *setting); +NM_AVAILABLE_IN_1_8 +NMSettingSecretFlags nm_setting_802_1x_get_phase2_ca_cert_password_flags (NMSetting8021x *setting); + const char * nm_setting_802_1x_get_phase2_subject_match (NMSetting8021x *setting); guint32 nm_setting_802_1x_get_num_phase2_altsubject_matches (NMSetting8021x *setting); @@ -262,6 +312,11 @@ gboolean nm_setting_802_1x_set_phase2_client_cert (NMSett NMSetting8021xCKFormat *out_format, GError **error); +NM_AVAILABLE_IN_1_8 +const char * nm_setting_802_1x_get_phase2_client_cert_password (NMSetting8021x *setting); +NM_AVAILABLE_IN_1_8 +NMSettingSecretFlags nm_setting_802_1x_get_phase2_client_cert_password_flags (NMSetting8021x *setting); + const char * nm_setting_802_1x_get_password (NMSetting8021x *setting); NMSettingSecretFlags nm_setting_802_1x_get_password_flags (NMSetting8021x *setting); GBytes * nm_setting_802_1x_get_password_raw (NMSetting8021x *setting); @@ -302,6 +357,10 @@ NMSettingSecretFlags nm_setting_802_1x_get_phase2_private_key_password_flags ( NMSetting8021xCKFormat nm_setting_802_1x_get_phase2_private_key_format (NMSetting8021x *setting); +NM_AVAILABLE_IN_1_8 +NMSetting8021xAuthFlags nm_setting_802_1x_get_phase1_auth_flags (NMSetting8021x *setting); +NM_AVAILABLE_IN_1_8 +gint nm_setting_802_1x_get_auth_timeout (NMSetting8021x *setting); G_END_DECLS diff --git a/libnm-core/nm-setting-adsl.h b/libnm-core/nm-setting-adsl.h index 5afbe5bf..4f04355e 100644 --- a/libnm-core/nm-setting-adsl.h +++ b/libnm-core/nm-setting-adsl.h @@ -26,7 +26,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -56,6 +56,8 @@ G_BEGIN_DECLS /** * NMSettingAdsl: + * + * ADSL Settings */ struct _NMSettingAdsl { NMSetting parent; diff --git a/libnm-core/nm-setting-bluetooth.h b/libnm-core/nm-setting-bluetooth.h index 6746782e..312aab14 100644 --- a/libnm-core/nm-setting-bluetooth.h +++ b/libnm-core/nm-setting-bluetooth.h @@ -61,6 +61,8 @@ G_BEGIN_DECLS /** * NMSettingBluetooth: + * + * Bluetooth Settings */ struct _NMSettingBluetooth { NMSetting parent; diff --git a/libnm-core/nm-setting-bond.c b/libnm-core/nm-setting-bond.c index 904ebbfc..9a8bdc37 100644 --- a/libnm-core/nm-setting-bond.c +++ b/libnm-core/nm-setting-bond.c @@ -395,10 +395,12 @@ nm_setting_bond_remove_option (NMSettingBond *setting, /** * nm_setting_bond_get_valid_options: - * @setting: the #NMSettingBond + * @setting: (allow-none): the #NMSettingBond * * Returns a list of valid bond options. * + * The @setting argument is unused and may be passed as %NULL. + * * Returns: (transfer none): a %NULL-terminated array of strings of valid bond options. **/ const char ** diff --git a/libnm-core/nm-setting-bond.h b/libnm-core/nm-setting-bond.h index 8ee31888..e2d8f9b5 100644 --- a/libnm-core/nm-setting-bond.h +++ b/libnm-core/nm-setting-bond.h @@ -26,7 +26,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -72,6 +72,8 @@ G_BEGIN_DECLS /** * NMSettingBond: + * + * Bonding Settings */ struct _NMSettingBond { NMSetting parent; diff --git a/libnm-core/nm-setting-bridge-port.h b/libnm-core/nm-setting-bridge-port.h index b43f6366..0ff6d9f1 100644 --- a/libnm-core/nm-setting-bridge-port.h +++ b/libnm-core/nm-setting-bridge-port.h @@ -26,7 +26,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -45,6 +45,8 @@ G_BEGIN_DECLS /** * NMSettingBridgePort: + * + * Bridge Port Settings */ struct _NMSettingBridgePort { NMSetting parent; diff --git a/libnm-core/nm-setting-bridge.h b/libnm-core/nm-setting-bridge.h index 844c06ad..81e4c644 100644 --- a/libnm-core/nm-setting-bridge.h +++ b/libnm-core/nm-setting-bridge.h @@ -26,7 +26,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -50,6 +50,8 @@ G_BEGIN_DECLS /** * NMSettingBridge: + * + * Bridging Settings */ struct _NMSettingBridge { NMSetting parent; diff --git a/libnm-core/nm-setting-cdma.c b/libnm-core/nm-setting-cdma.c index 31b02d7f..b267ba63 100644 --- a/libnm-core/nm-setting-cdma.c +++ b/libnm-core/nm-setting-cdma.c @@ -48,6 +48,7 @@ typedef struct { char *username; char *password; NMSettingSecretFlags password_flags; + guint32 mtu; } NMSettingCdmaPrivate; enum { @@ -56,6 +57,7 @@ enum { PROP_USERNAME, PROP_PASSWORD, PROP_PASSWORD_FLAGS, + PROP_MTU, LAST_PROP }; @@ -129,6 +131,22 @@ nm_setting_cdma_get_password_flags (NMSettingCdma *setting) return NM_SETTING_CDMA_GET_PRIVATE (setting)->password_flags; } +/** + * nm_setting_cdma_get_mtu: + * @setting: the #NMSettingCdma + * + * Returns: the #NMSettingCdma:mtu property of the setting + * + * Since: 1.8 + **/ +guint32 +nm_setting_cdma_get_mtu (NMSettingCdma *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_CDMA (setting), 0); + + return NM_SETTING_CDMA_GET_PRIVATE (setting)->mtu; +} + static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { @@ -229,6 +247,9 @@ set_property (GObject *object, guint prop_id, case PROP_PASSWORD_FLAGS: priv->password_flags = g_value_get_flags (value); break; + case PROP_MTU: + priv->mtu = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -254,6 +275,9 @@ get_property (GObject *object, guint prop_id, case PROP_PASSWORD_FLAGS: g_value_set_flags (value, nm_setting_cdma_get_password_flags (setting)); break; + case PROP_MTU: + g_value_set_uint (value, nm_setting_cdma_get_mtu (setting)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -333,4 +357,22 @@ nm_setting_cdma_class_init (NMSettingCdmaClass *setting_class) NM_SETTING_SECRET_FLAG_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * NMSettingCdma:mtu: + * + * If non-zero, only transmit packets of the specified size or smaller, + * breaking larger packets up into multiple frames. + * + * Since: 1.8 + **/ + g_object_class_install_property + (object_class, PROP_MTU, + g_param_spec_uint (NM_SETTING_CDMA_MTU, "", "", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_FUZZY_IGNORE | + G_PARAM_STATIC_STRINGS)); + } diff --git a/libnm-core/nm-setting-cdma.h b/libnm-core/nm-setting-cdma.h index 091c530e..6e429bd1 100644 --- a/libnm-core/nm-setting-cdma.h +++ b/libnm-core/nm-setting-cdma.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -44,9 +44,12 @@ G_BEGIN_DECLS #define NM_SETTING_CDMA_USERNAME "username" #define NM_SETTING_CDMA_PASSWORD "password" #define NM_SETTING_CDMA_PASSWORD_FLAGS "password-flags" +#define NM_SETTING_CDMA_MTU "mtu" /** * NMSettingCdma: + * + * CDMA-based Mobile Broadband Settings */ struct _NMSettingCdma { NMSetting parent; @@ -67,6 +70,9 @@ const char *nm_setting_cdma_get_username (NMSettingCdma *setting); const char *nm_setting_cdma_get_password (NMSettingCdma *setting); NMSettingSecretFlags nm_setting_cdma_get_password_flags (NMSettingCdma *setting); +NM_AVAILABLE_IN_1_8 +guint32 nm_setting_cdma_get_mtu (NMSettingCdma *setting); + G_END_DECLS #endif /* __NM_SETTING_CDMA_H__ */ diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index ac8bdf2d..38f3bf44 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -289,10 +289,10 @@ nm_setting_connection_get_connection_type (NMSettingConnection *setting) * nm_setting_connection_get_num_permissions: * @setting: the #NMSettingConnection * - * Returns the number of entires in the #NMSettingConnection:permissions + * Returns the number of entries in the #NMSettingConnection:permissions * property of this setting. * - * Returns: the number of permissions entires + * Returns: the number of permissions entries */ guint32 nm_setting_connection_get_num_permissions (NMSettingConnection *setting) @@ -857,7 +857,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE (setting); gboolean is_slave; - const char *slave_setting_type = NULL; + const char *slave_setting_type; NMSetting *normerr_base_type = NULL; const char *normerr_slave_setting_type = NULL; const char *normerr_missing_slave_type = NULL; @@ -958,16 +958,17 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) } is_slave = FALSE; - if (priv->slave_type) + slave_setting_type = NULL; + if (priv->slave_type) { is_slave = _nm_setting_slave_type_is_valid (priv->slave_type, &slave_setting_type); - - if (priv->slave_type && !is_slave) { - g_set_error (error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Unknown slave type '%s'"), priv->slave_type); - g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE); - return FALSE; + if (!is_slave) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Unknown slave type '%s'"), priv->slave_type); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE); + return FALSE; + } } if (is_slave) { @@ -1063,6 +1064,24 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; } + if (connection) { + gboolean has_bridge_port = FALSE; + + if ( ( !nm_streq0 (priv->slave_type, NM_SETTING_BRIDGE_SETTING_NAME) + && (has_bridge_port = !!nm_connection_get_setting_by_name (connection, NM_SETTING_BRIDGE_PORT_SETTING_NAME))) + || ( !nm_streq0 (priv->slave_type, NM_SETTING_TEAM_SETTING_NAME) + && nm_connection_get_setting_by_name (connection, NM_SETTING_TEAM_PORT_SETTING_NAME))) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_SETTING, + _("A slave connection with '%s' set to '%s' cannot have a '%s' setting"), + NM_SETTING_CONNECTION_SLAVE_TYPE, priv->slave_type ?: "", + has_bridge_port ? NM_SETTING_BRIDGE_PORT_SETTING_NAME : NM_SETTING_TEAM_PORT_SETTING_NAME); + g_prefix_error (error, "%s.%s: ", NM_SETTING_CONNECTION_SETTING_NAME, NM_SETTING_CONNECTION_SLAVE_TYPE); + return NM_SETTING_VERIFY_NORMALIZABLE_ERROR; + } + } + return TRUE; } diff --git a/libnm-core/nm-setting-connection.h b/libnm-core/nm-setting-connection.h index 89fa64ce..bd5b98ff 100644 --- a/libnm-core/nm-setting-connection.h +++ b/libnm-core/nm-setting-connection.h @@ -99,8 +99,7 @@ typedef enum { /** * NMSettingConnection: * - * The NMSettingConnection struct contains only private data. - * It should only be accessed through the functions described below. + * General Connection Profile Settings */ struct _NMSettingConnection { NMSetting parent; diff --git a/libnm-core/nm-setting-dcb.h b/libnm-core/nm-setting-dcb.h index 6cc2ce41..d2a364a2 100644 --- a/libnm-core/nm-setting-dcb.h +++ b/libnm-core/nm-setting-dcb.h @@ -26,7 +26,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -94,6 +94,8 @@ typedef enum { /*< flags >*/ /** * NMSettingDcb: + * + * Data Center Bridging Settings */ struct _NMSettingDcb { NMSetting parent; diff --git a/libnm-core/nm-setting-dummy.c b/libnm-core/nm-setting-dummy.c new file mode 100644 index 00000000..d23f0a30 --- /dev/null +++ b/libnm-core/nm-setting-dummy.c @@ -0,0 +1,76 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-setting-dummy.h" + +#include "nm-connection-private.h" +#include "nm-setting-connection.h" +#include "nm-setting-private.h" + +/** + * SECTION:nm-setting-dummy + * @short_description: Describes connection properties for dummy interfaces + * + * The #NMSettingDummy object is a #NMSetting subclass that describes properties + * necessary for connection to dummy devices + **/ + +G_DEFINE_TYPE_WITH_CODE (NMSettingDummy, nm_setting_dummy, NM_TYPE_SETTING, + _nm_register_setting (DUMMY, 1)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_DUMMY) + +/** + * nm_setting_dummy_new: + * + * Creates a new #NMSettingDummy object with default values. + * + * Returns: (transfer full): the new empty #NMSettingDummy object + * + * Since: 1.8 + **/ +NMSetting * +nm_setting_dummy_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_DUMMY, NULL); +} + +static gboolean +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + if (!_nm_connection_verify_required_interface_name (connection, error)) + return FALSE; + + return TRUE; +} + +static void +nm_setting_dummy_init (NMSettingDummy *setting) +{ +} + +static void +nm_setting_dummy_class_init (NMSettingDummyClass *setting_class) +{ + NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class); + + parent_class->verify = verify; +} diff --git a/libnm-core/nm-setting-dummy.h b/libnm-core/nm-setting-dummy.h new file mode 100644 index 00000000..62fe3fa6 --- /dev/null +++ b/libnm-core/nm-setting-dummy.h @@ -0,0 +1,65 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * 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 2017 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_DUMMY_H__ +#define __NM_SETTING_DUMMY_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only <NetworkManager.h> can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_DUMMY (nm_setting_dummy_get_type ()) +#define NM_SETTING_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_DUMMY, NMSettingDummy)) +#define NM_SETTING_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_DUMMYCONFIG, NMSettingDummyClass)) +#define NM_IS_SETTING_DUMMY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_DUMMY)) +#define NM_IS_SETTING_DUMMY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_DUMMY)) +#define NM_SETTING_DUMMY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_DUMMY, NMSettingDummyClass)) + +#define NM_SETTING_DUMMY_SETTING_NAME "dummy" + +/** + * NMSettingDummy: + * + * Dummy Link Settings + */ +struct _NMSettingDummy { + NMSetting parent; +}; + +typedef struct { + NMSettingClass parent; + + /*< private >*/ + gpointer padding[4]; +} NMSettingDummyClass; + +NM_AVAILABLE_IN_1_8 +GType nm_setting_dummy_get_type (void); +NM_AVAILABLE_IN_1_8 +NMSetting *nm_setting_dummy_new (void); + +G_END_DECLS + +#endif /* __NM_SETTING_DUMMY_H__ */ diff --git a/libnm-core/nm-setting-generic.h b/libnm-core/nm-setting-generic.h index 0ce3b160..864b9004 100644 --- a/libnm-core/nm-setting-generic.h +++ b/libnm-core/nm-setting-generic.h @@ -26,7 +26,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -41,6 +41,8 @@ G_BEGIN_DECLS /** * NMSettingGeneric: + * + * Generic Link Settings */ struct _NMSettingGeneric { NMSetting parent; diff --git a/libnm-core/nm-setting-gsm.c b/libnm-core/nm-setting-gsm.c index 86166df2..be32b852 100644 --- a/libnm-core/nm-setting-gsm.c +++ b/libnm-core/nm-setting-gsm.c @@ -62,6 +62,7 @@ typedef struct { NMSettingSecretFlags pin_flags; gboolean home_only; + guint32 mtu; } NMSettingGsmPrivate; enum { @@ -78,6 +79,7 @@ enum { PROP_DEVICE_ID, PROP_SIM_ID, PROP_SIM_OPERATOR_ID, + PROP_MTU, LAST_PROP }; @@ -269,6 +271,22 @@ nm_setting_gsm_get_sim_operator_id (NMSettingGsm *setting) return NM_SETTING_GSM_GET_PRIVATE (setting)->sim_operator_id; } +/** + * nm_setting_gsm_get_mtu: + * @setting: the #NMSettingGsm + * + * Returns: the #NMSettingGsm:mtu property of the setting + * + * Since: 1.8 + **/ +guint32 +nm_setting_gsm_get_mtu (NMSettingGsm *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_GSM (setting), 0); + + return NM_SETTING_GSM_GET_PRIVATE (setting)->mtu; +} + static gboolean verify (NMSetting *setting, NMConnection *connection, GError **error) { @@ -524,6 +542,9 @@ set_property (GObject *object, guint prop_id, g_free (priv->sim_operator_id); priv->sim_operator_id = g_value_dup_string (value); break; + case PROP_MTU: + priv->mtu = g_value_get_uint (value); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -573,6 +594,9 @@ get_property (GObject *object, guint prop_id, case PROP_SIM_OPERATOR_ID: g_value_set_string (value, nm_setting_gsm_get_sim_operator_id (setting)); break; + case PROP_MTU: + g_value_set_uint (value, nm_setting_gsm_get_mtu (setting)); + break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; @@ -780,6 +804,23 @@ nm_setting_gsm_class_init (NMSettingGsmClass *setting_class) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * NMSettingGsm:mtu: + * + * If non-zero, only transmit packets of the specified size or smaller, + * breaking larger packets up into multiple frames. + * + * Since: 1.8 + **/ + g_object_class_install_property + (object_class, PROP_MTU, + g_param_spec_uint (NM_SETTING_GSM_MTU, "", "", + 0, G_MAXUINT32, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT | + NM_SETTING_PARAM_FUZZY_IGNORE | + G_PARAM_STATIC_STRINGS)); + /* Ignore incoming deprecated properties */ _nm_setting_class_add_dbus_only_property (parent_class, "allowed-bands", G_VARIANT_TYPE_UINT32, diff --git a/libnm-core/nm-setting-gsm.h b/libnm-core/nm-setting-gsm.h index 7f97d386..8516698d 100644 --- a/libnm-core/nm-setting-gsm.h +++ b/libnm-core/nm-setting-gsm.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -52,9 +52,12 @@ G_BEGIN_DECLS #define NM_SETTING_GSM_DEVICE_ID "device-id" #define NM_SETTING_GSM_SIM_ID "sim-id" #define NM_SETTING_GSM_SIM_OPERATOR_ID "sim-operator-id" +#define NM_SETTING_GSM_MTU "mtu" /** * NMSettingGsm: + * + * GSM-based Mobile Broadband Settings */ struct _NMSettingGsm { NMSetting parent; @@ -84,6 +87,8 @@ NM_AVAILABLE_IN_1_2 const char *nm_setting_gsm_get_sim_id (NMSettingGsm *setting); NM_AVAILABLE_IN_1_2 const char *nm_setting_gsm_get_sim_operator_id (NMSettingGsm *setting); +NM_AVAILABLE_IN_1_8 +guint32 nm_setting_gsm_get_mtu (NMSettingGsm *setting); NMSettingSecretFlags nm_setting_gsm_get_pin_flags (NMSettingGsm *setting); NMSettingSecretFlags nm_setting_gsm_get_password_flags (NMSettingGsm *setting); diff --git a/libnm-core/nm-setting-infiniband.h b/libnm-core/nm-setting-infiniband.h index f19983b4..ff78b3dc 100644 --- a/libnm-core/nm-setting-infiniband.h +++ b/libnm-core/nm-setting-infiniband.h @@ -26,7 +26,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -47,6 +47,8 @@ G_BEGIN_DECLS /** * NMSettingInfiniband: + * + * Infiniband Settings */ struct _NMSettingInfiniband { NMSetting parent; diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index 09c5798a..139c2c3e 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -1182,6 +1182,157 @@ nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value) g_hash_table_remove (route->attributes, name); } +#define ATTR_SPEC_PTR(name, type, v4, v6, str_type) \ + &(NMVariantAttributeSpec) { name, type, v4, v6, str_type } + +static const NMVariantAttributeSpec * const ip_route_attribute_spec[] = { + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_SRC, G_VARIANT_TYPE_STRING, TRUE, TRUE, 'a'), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_FROM, G_VARIANT_TYPE_STRING, FALSE, TRUE, 'p'), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_TOS, G_VARIANT_TYPE_BYTE, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_WINDOW, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_CWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITCWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_INITRWND, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_MTU, G_VARIANT_TYPE_UINT32, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + ATTR_SPEC_PTR (NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, G_VARIANT_TYPE_BOOLEAN, TRUE, TRUE, 0 ), + NULL, +}; + +/** + * nm_ip_route_get_variant_attribute_spec: + * + * Returns: the specifiers for route attributes + * + * Since: 1.8 + */ +const NMVariantAttributeSpec *const * +nm_ip_route_get_variant_attribute_spec (void) +{ + return ip_route_attribute_spec; +} + +/** + * nm_ip_route_attribute_validate: + * @name: the attribute name + * @value: the attribute value + * @family: IP address family of the route + * @known: (out): on return, whether the attribute name is a known one + * @error: (allow-none): return location for a #GError, or %NULL + * + * Validates a route attribute, i.e. checks that the attribute is a known one + * and the value is of the correct type and well-formed. + * + * Returns: %TRUE if the attribute is valid, %FALSE otherwise + * + * Since: 1.8 + */ +gboolean +nm_ip_route_attribute_validate (const char *name, + GVariant *value, + int family, + gboolean *known, + GError **error) +{ + const NMVariantAttributeSpec *const *iter; + const NMVariantAttributeSpec *spec = NULL; + + g_return_val_if_fail (name, FALSE); + g_return_val_if_fail (value, FALSE); + g_return_val_if_fail (family == AF_INET || family == AF_INET6, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + for (iter = ip_route_attribute_spec; *iter; iter++) { + if (nm_streq (name, (*iter)->name)) { + spec = *iter; + break; + } + } + + if (!spec) { + NM_SET_OUT (known, FALSE); + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("unknown attribute")); + return FALSE; + } + + NM_SET_OUT (known, TRUE); + + if (!g_variant_is_of_type (value, spec->type)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("invalid attribute type '%s'"), + g_variant_get_type_string (value)); + return FALSE; + } + + if ( (family == AF_INET && !spec->v4) + || (family == AF_INET6 && !spec->v6)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + family == AF_INET ? + _("attribute is not valid for a IPv4 route") : + _("attribute is not valid for a IPv6 route")); + return FALSE; + } + + if (spec->type == G_VARIANT_TYPE_STRING) { + const char *string = g_variant_get_string (value, NULL); + gs_free char *string_free = NULL; + char *sep; + + switch (spec->str_type) { + case 'a': /* IP address */ + if (!nm_utils_ipaddr_valid (family, string)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + family == AF_INET ? + _("'%s' is not a valid IPv4 address") : + _("'%s' is not a valid IPv6 address"), + string); + return FALSE; + } + break; + case 'p': /* IP address + optional prefix */ + string_free = g_strdup (string); + sep = strchr (string_free, '/'); + if (sep) { + *sep = 0; + if (_nm_utils_ascii_str_to_int64 (sep + 1, 10, 1, family == AF_INET ? 32 : 128, -1) < 0) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("invalid prefix %s"), sep + 1); + return FALSE; + } + } + if (!nm_utils_ipaddr_valid (family, string_free)) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + family == AF_INET ? + _("'%s' is not a valid IPv4 address") : + _("'%s' is not a valid IPv6 address"), + string_free); + return FALSE; + } + break; + default: + break; + } + } + + return TRUE; +} + /*****************************************************************************/ G_DEFINE_ABSTRACT_TYPE (NMSettingIPConfig, nm_setting_ip_config, NM_TYPE_SETTING) diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h index b18d6a94..b7bb0215 100644 --- a/libnm-core/nm-setting-ip-config.h +++ b/libnm-core/nm-setting-ip-config.h @@ -28,6 +28,7 @@ #endif #include "nm-setting.h" +#include "nm-utils.h" G_BEGIN_DECLS @@ -121,7 +122,28 @@ GVariant *nm_ip_route_get_attribute (NMIPRoute *route, void nm_ip_route_set_attribute (NMIPRoute *route, const char *name, GVariant *value); +NM_AVAILABLE_IN_1_8 +const NMVariantAttributeSpec *const *nm_ip_route_get_variant_attribute_spec (void); +NM_AVAILABLE_IN_1_8 +gboolean nm_ip_route_attribute_validate (const char *name, + GVariant *value, + int family, + gboolean *known, + GError **error); +#define NM_IP_ROUTE_ATTRIBUTE_SRC "src" +#define NM_IP_ROUTE_ATTRIBUTE_FROM "from" +#define NM_IP_ROUTE_ATTRIBUTE_TOS "tos" +#define NM_IP_ROUTE_ATTRIBUTE_WINDOW "window" +#define NM_IP_ROUTE_ATTRIBUTE_CWND "cwnd" +#define NM_IP_ROUTE_ATTRIBUTE_INITCWND "initcwnd" +#define NM_IP_ROUTE_ATTRIBUTE_INITRWND "initrwnd" +#define NM_IP_ROUTE_ATTRIBUTE_MTU "mtu" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_WINDOW "lock-window" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_CWND "lock-cwnd" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITCWND "lock-initcwnd" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_INITRWND "lock-initrwnd" +#define NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU "lock-mtu" #define NM_TYPE_SETTING_IP_CONFIG (nm_setting_ip_config_get_type ()) #define NM_SETTING_IP_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_IP_CONFIG, NMSettingIPConfig)) diff --git a/libnm-core/nm-setting-ip-tunnel.h b/libnm-core/nm-setting-ip-tunnel.h index 3ee4aafe..dfa62116 100644 --- a/libnm-core/nm-setting-ip-tunnel.h +++ b/libnm-core/nm-setting-ip-tunnel.h @@ -25,7 +25,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -53,6 +53,8 @@ G_BEGIN_DECLS /** * NMSettingIPTunnel: + * + * IP Tunneling Settings */ struct _NMSettingIPTunnel { NMSetting parent; diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c index 91a4a3f5..3a366161 100644 --- a/libnm-core/nm-setting-ip4-config.c +++ b/libnm-core/nm-setting-ip4-config.c @@ -615,7 +615,7 @@ nm_setting_ip4_config_class_init (NMSettingIP4ConfigClass *ip4_class) * ---end--- * ---ifcfg-rh--- * property: routes - * variable: ADDRESS1, NETMASK1, GATEWAY1, METRIC1, ... + * variable: ADDRESS1, NETMASK1, GATEWAY1, METRIC1, OPTIONS1, ... * description: List of static routes. They are not stored in ifcfg-* file, * but in route-* file instead. * ---end--- diff --git a/libnm-core/nm-setting-ip4-config.h b/libnm-core/nm-setting-ip4-config.h index adef3754..ca894509 100644 --- a/libnm-core/nm-setting-ip4-config.h +++ b/libnm-core/nm-setting-ip4-config.h @@ -89,6 +89,8 @@ G_BEGIN_DECLS /** * NMSettingIP4Config: + * + * IPv4 Settings */ struct _NMSettingIP4Config { NMSettingIPConfig parent; diff --git a/libnm-core/nm-setting-ip6-config.h b/libnm-core/nm-setting-ip6-config.h index 8e2c7771..e01a36b7 100644 --- a/libnm-core/nm-setting-ip6-config.h +++ b/libnm-core/nm-setting-ip6-config.h @@ -139,6 +139,8 @@ typedef enum { /** * NMSettingIP6Config: + * + * IPv6 Settings */ struct _NMSettingIP6Config { NMSettingIPConfig parent; diff --git a/libnm-core/nm-setting-macsec.c b/libnm-core/nm-setting-macsec.c index 60df6839..c818f07f 100644 --- a/libnm-core/nm-setting-macsec.c +++ b/libnm-core/nm-setting-macsec.c @@ -251,7 +251,7 @@ verify_macsec_key (const char *key, gboolean cak, GError **error) g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("the key contais non-hexadecimal characters")); + _("the key contains non-hexadecimal characters")); return FALSE; } diff --git a/libnm-core/nm-setting-macsec.h b/libnm-core/nm-setting-macsec.h index f9431dfe..6a524faa 100644 --- a/libnm-core/nm-setting-macsec.h +++ b/libnm-core/nm-setting-macsec.h @@ -50,6 +50,8 @@ G_BEGIN_DECLS /** * NMSettingMacsec: + * + * MACSec Settings */ struct _NMSettingMacsec { NMSetting parent; diff --git a/libnm-core/nm-setting-macvlan.h b/libnm-core/nm-setting-macvlan.h index 33860aac..605efd0f 100644 --- a/libnm-core/nm-setting-macvlan.h +++ b/libnm-core/nm-setting-macvlan.h @@ -46,6 +46,8 @@ G_BEGIN_DECLS /** * NMSettingMacvlan: + * + * MAC VLAN Settings */ struct _NMSettingMacvlan { NMSetting parent; diff --git a/libnm-core/nm-setting-olpc-mesh.h b/libnm-core/nm-setting-olpc-mesh.h index 2506cec9..69b3c6e9 100644 --- a/libnm-core/nm-setting-olpc-mesh.h +++ b/libnm-core/nm-setting-olpc-mesh.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -46,6 +46,8 @@ G_BEGIN_DECLS /** * NMSettingOlpcMesh: + * + * OLPC Wireless Mesh Settings */ struct _NMSettingOlpcMesh { NMSetting parent; diff --git a/libnm-core/nm-setting-ppp.h b/libnm-core/nm-setting-ppp.h index a835ef8a..01536d84 100644 --- a/libnm-core/nm-setting-ppp.h +++ b/libnm-core/nm-setting-ppp.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -61,6 +61,8 @@ G_BEGIN_DECLS /** * NMSettingPpp: + * + * Point-to-Point Protocol Settings */ struct _NMSettingPpp { NMSetting parent; diff --git a/libnm-core/nm-setting-pppoe.h b/libnm-core/nm-setting-pppoe.h index 1f5b6ed9..b6717cde 100644 --- a/libnm-core/nm-setting-pppoe.h +++ b/libnm-core/nm-setting-pppoe.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -47,6 +47,8 @@ G_BEGIN_DECLS /** * NMSettingPppoe: + * + * PPP-over-Ethernet Settings */ struct _NMSettingPppoe { NMSetting parent; diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h index 8d09e3d7..79b6ac87 100644 --- a/libnm-core/nm-setting-private.h +++ b/libnm-core/nm-setting-private.h @@ -27,22 +27,6 @@ #include "nm-core-internal.h" -/** - * NMSettingVerifyResult: - * @NM_SETTING_VERIFY_SUCCESS: the setting verifies successfully - * @NM_SETTING_VERIFY_ERROR: the setting has a serious misconfiguration - * @NM_SETTING_VERIFY_NORMALIZABLE: the setting is valid but has properties - * that should be normalized - * @NM_SETTING_VERIFY_NORMALIZABLE_ERROR: the setting is invalid but the - * errors can be fixed by nm_connection_normalize(). - */ -typedef enum { - NM_SETTING_VERIFY_SUCCESS = TRUE, - NM_SETTING_VERIFY_ERROR = FALSE, - NM_SETTING_VERIFY_NORMALIZABLE = 2, - NM_SETTING_VERIFY_NORMALIZABLE_ERROR = 3, -} NMSettingVerifyResult; - void _nm_register_setting (const char *name, const GType type, const guint32 priority); diff --git a/libnm-core/nm-setting-proxy.h b/libnm-core/nm-setting-proxy.h index 2009dfab..0c72799f 100644 --- a/libnm-core/nm-setting-proxy.h +++ b/libnm-core/nm-setting-proxy.h @@ -26,7 +26,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -58,6 +58,11 @@ typedef enum { #define NM_SETTING_PROXY_PAC_URL "pac-url" #define NM_SETTING_PROXY_PAC_SCRIPT "pac-script" +/** + * NMSettingProxy: + * + * WWW Proxy Settings + */ struct _NMSettingProxy { NMSetting parent; }; diff --git a/libnm-core/nm-setting-serial.h b/libnm-core/nm-setting-serial.h index 182efc61..2362b246 100644 --- a/libnm-core/nm-setting-serial.h +++ b/libnm-core/nm-setting-serial.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -62,6 +62,8 @@ typedef enum { /** * NMSettingSerial: + * + * Serial Link Settings */ struct _NMSettingSerial { NMSetting parent; diff --git a/libnm-core/nm-setting-team-port.h b/libnm-core/nm-setting-team-port.h index 546cc69a..4fcc5108 100644 --- a/libnm-core/nm-setting-team-port.h +++ b/libnm-core/nm-setting-team-port.h @@ -25,7 +25,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -42,6 +42,8 @@ G_BEGIN_DECLS /** * NMSettingTeamPort: + * + * Team Port Settings */ struct _NMSettingTeamPort { NMSetting parent; diff --git a/libnm-core/nm-setting-team.h b/libnm-core/nm-setting-team.h index 726f8420..532963aa 100644 --- a/libnm-core/nm-setting-team.h +++ b/libnm-core/nm-setting-team.h @@ -25,7 +25,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -42,6 +42,8 @@ G_BEGIN_DECLS /** * NMSettingTeam: + * + * Teaming Settings */ struct _NMSettingTeam { NMSetting parent; diff --git a/libnm-core/nm-setting-tun.c b/libnm-core/nm-setting-tun.c index fe14eec2..62e9ef14 100644 --- a/libnm-core/nm-setting-tun.c +++ b/libnm-core/nm-setting-tun.c @@ -184,7 +184,7 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("'%u': invalid mode"), (unsigned int) priv->mode); + _("'%u': invalid mode"), (unsigned) priv->mode); g_prefix_error (error, "%s.%s: ", NM_SETTING_TUN_SETTING_NAME, NM_SETTING_TUN_MODE); return FALSE; } diff --git a/libnm-core/nm-setting-tun.h b/libnm-core/nm-setting-tun.h index 63c0cbd8..d977e381 100644 --- a/libnm-core/nm-setting-tun.h +++ b/libnm-core/nm-setting-tun.h @@ -62,6 +62,8 @@ typedef enum { /** * NMSettingTun: + * + * Tunnel Settings */ struct _NMSettingTun { NMSetting parent; diff --git a/libnm-core/nm-setting-user.c b/libnm-core/nm-setting-user.c new file mode 100644 index 00000000..71d73891 --- /dev/null +++ b/libnm-core/nm-setting-user.c @@ -0,0 +1,612 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * 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 2017 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-setting-user.h" + +#include "nm-setting.h" +#include "nm-setting-private.h" +#include "nm-utils-private.h" + +/** + * SECTION:nm-setting-user + * @short_description: Describes user properties + * + * The #NMSettingUser object is a #NMSetting subclass that allow to attach + * arbitrary user data to #NMConnection objects. + **/ + +#define MAX_NUM_KEYS 256 + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE (NMSettingUser, + PROP_DATA, +); + +typedef struct { + GHashTable *data; + GHashTable *data_invalid; + const char **keys; +} NMSettingUserPrivate; + +/** + * NMSettingUser: + * + * General User Profile Settings + */ +struct _NMSettingUser { + NMSetting parent; + NMSettingUserPrivate _priv; +}; + +struct _NMSettingUserClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE_WITH_CODE (NMSettingUser, nm_setting_user, NM_TYPE_SETTING, + _nm_register_setting (USER, 10)) +NM_SETTING_REGISTER_TYPE (NM_TYPE_SETTING_USER) + +#define NM_SETTING_USER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMSettingUser, NM_IS_SETTING_USER) + +/*****************************************************************************/ + +static gboolean +_key_char_is_regular (char ch) +{ + /* allow words of printable characters, plus some + * special characters, for example to support base64 encoding. */ + return (ch >= 'a' && ch <= 'z') + || (ch >= 'A' && ch <= 'Z') + || (ch >= '0' && ch <= '9') + || NM_IN_SET (ch, '-', '_', '+', '/', '='); +} + +/** + * nm_setting_user_check_key: + * @key: the key to check + * @error: a #GError, %NULL to ignore. + * + * Checks whether @key is a valid user data key. This means, + * key is not %NULL, not too large and valid ASCII. Also, + * only digits and numbers are allowed with a few special + * characters. The key must contain at least one '.' and + * look like a fully qualified DNS name. + * + * Since: 1.8 + * + * Returns: %TRUE if @key is a valid user data key. + */ +gboolean +nm_setting_user_check_key (const char *key, GError **error) +{ + gsize len; + gboolean has_dot; + char ch; + + g_return_val_if_fail (!error || !*error, FALSE); + + if (!key || !key[0]) { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("missing key")); + return FALSE; + } + len = strlen (key); + if (len > 255) { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key is too long")); + return FALSE; + } + if (!g_utf8_validate (key, len, NULL)) { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key must be UTF8")); + return FALSE; + } + + has_dot = FALSE; + while (TRUE) { + ch = (key++)[0]; + + /* Allow something that looks like a FQN, separating namespaces by a single '.' + * We want to print the keys nicely in nmcli requiring escaping. + * + * If a user really has to encode special values in the name, he may base64 encode it. */ + + if (!_key_char_is_regular (ch)) + break; + + while (_key_char_is_regular (key[0])) + key++; + + ch = key[0]; + if (ch == '\0') { + if (!has_dot) { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key requires a '.' for a namespace")); + return FALSE; + } + return TRUE; + } + + if (ch != '.') + break; + + has_dot = TRUE; + ch = (++key)[0]; + if (ch == '.') { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key cannot contain \"..\"")); + return FALSE; + } + } + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key contains invalid characters")); + return FALSE; +} + +/** + * nm_setting_user_check_val: + * @val: the value to check + * @error: a #GError, %NULL to ignore. + * + * Checks whether @val is a valid user data value. This means, + * value is not %NULL, not too large and valid UTF-8. + * + * Since: 1.8 + * + * Returns: %TRUE if @val is a valid user data value. + */ +gboolean +nm_setting_user_check_val (const char *val, GError **error) +{ + gsize len; + + g_return_val_if_fail (!error || !*error, FALSE); + + if (!val) { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("value is missing")); + return FALSE; + } + + len = strlen (val); + if (len > 8*1024) { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("value is too large")); + return FALSE; + } + + if (!g_utf8_validate (val, len, NULL)) { + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("value is not valid UTF8")); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + +static GHashTable * +_create_data_hash (void) +{ + return g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); +} + +/** + * nm_setting_user_get_keys: + * @setting: the #NMSettingUser + * @out_len: (out): the length of the returned array + * + * Returns: (array length=out_len) (transfer none): a + * %NULL-terminated array containing each key from the table. + **/ +const char *const* +nm_setting_user_get_keys (NMSettingUser *setting, guint *out_len) +{ + NMSettingUser *self = setting; + NMSettingUserPrivate *priv; + guint len; + + g_return_val_if_fail (NM_IS_SETTING_USER (self), NULL); + + priv = NM_SETTING_USER_GET_PRIVATE (self); + + if (priv->keys) { + NM_SET_OUT (out_len, g_hash_table_size (priv->data)); + return priv->keys; + } + + if (!priv->data || !g_hash_table_size (priv->data)) { + NM_SET_OUT (out_len, 0); + return (const char **) &priv->keys; + } + + priv->keys = (const char **) g_hash_table_get_keys_as_array (priv->data, &len); + g_qsort_with_data (priv->keys, + len, + sizeof (const char *), + nm_strcmp_p_with_data, + NULL); + NM_SET_OUT (out_len, len); + return priv->keys; +} + +/*****************************************************************************/ + +/** + * nm_setting_user_get_data: + * @setting: the #NMSettingUser instance + * @key: the key to lookup + * + * Since: 1.8 + * + * Returns: (transfer none): the value associated with @key or %NULL if no such + * value exists. + */ +const char * +nm_setting_user_get_data (NMSettingUser *setting, const char *key) +{ + NMSettingUser *self = setting; + NMSettingUserPrivate *priv; + + g_return_val_if_fail (NM_IS_SETTING_USER (self), NULL); + g_return_val_if_fail (key, NULL); + + priv = NM_SETTING_USER_GET_PRIVATE (self); + + if (!priv->data) + return NULL; + + return g_hash_table_lookup (priv->data, key); +} + +/** + * nm_setting_user_set_data: + * @setting: the #NMSettingUser instance + * @key: the key to set + * @val: (allow-none): the value to set or %NULL to clear a key. + * @error: (allow-none): optional error argument + * + * Since: 1.8 + * + * Returns: %TRUE if the operation was successful. The operation + * can fail if @key or @val are not valid strings according + * to nm_setting_user_check_key() and nm_setting_user_check_val(). + */ +gboolean +nm_setting_user_set_data (NMSettingUser *setting, + const char *key, + const char *val, + GError **error) +{ + NMSettingUser *self = setting; + NMSettingUserPrivate *priv; + gboolean changed = FALSE; + + g_return_val_if_fail (NM_IS_SETTING (self), FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + if (!nm_setting_user_check_key (key, error)) + return FALSE; + + if ( val + && !nm_setting_user_check_val (val, error)) + return FALSE; + + priv = NM_SETTING_USER_GET_PRIVATE (self); + + if (!val) { + if ( priv->data + && g_hash_table_remove (priv->data, key)) { + nm_clear_g_free (&priv->keys); + changed = TRUE; + } + goto out; + } + + if (priv->data) { + const char *key2, *val2; + + if (g_hash_table_lookup_extended (priv->data, key, (gpointer *) &key2, (gpointer *) &val2)) { + if (nm_streq (val, val2)) + goto out; + } else { + if (g_hash_table_size (priv->data) >= MAX_NUM_KEYS) { + /* limit the number of valid keys */ + g_set_error_literal (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("maximum number of user data entries reached")); + return FALSE; + } + + nm_clear_g_free (&priv->keys); + } + } else + priv->data = _create_data_hash (); + + g_hash_table_insert (priv->data, g_strdup (key), g_strdup (val)); + changed = TRUE; + +out: + if (priv->data_invalid) { + /* setting a value purges all invalid values that were set + * via GObject property. */ + changed = TRUE; + g_clear_pointer (&priv->data_invalid, g_hash_table_unref); + } + if (changed) + _notify (self, PROP_DATA); + return TRUE; +} + +/*****************************************************************************/ + +static gboolean +verify (NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingUser *self = NM_SETTING_USER (setting); + NMSettingUserPrivate *priv = NM_SETTING_USER_GET_PRIVATE (self); + + if (priv->data_invalid) { + const char *key, *val; + GHashTableIter iter; + gs_free_error GError *local = NULL; + + g_hash_table_iter_init (&iter, priv->data_invalid); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) { + if (!nm_setting_user_check_key (key, &local)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("invalid key \"%s\": %s"), + key, local->message); + } else if (!nm_setting_user_check_val (val, &local)) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("invalid value for \"%s\": %s"), + key, local->message); + } else { + nm_assert_not_reached (); + continue; + } + g_prefix_error (error, "%s.%s: ", NM_SETTING_USER_SETTING_NAME, NM_SETTING_USER_DATA); + return FALSE; + } + nm_assert_not_reached (); + } + + if ( priv->data + && g_hash_table_size (priv->data) > MAX_NUM_KEYS) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("maximum number of user data entries reached (%u instead of %u)"), + g_hash_table_size (priv->data), (unsigned) MAX_NUM_KEYS); + g_prefix_error (error, "%s.%s: ", NM_SETTING_USER_SETTING_NAME, NM_SETTING_USER_DATA); + return FALSE; + } + + return TRUE; +} + +static gboolean +hash_table_equal (GHashTable *a, GHashTable *b) +{ + guint n; + GHashTableIter iter; + const char *key, *value, *valu2; + + n = a ? g_hash_table_size (a) : 0; + if (n != (b ? g_hash_table_size (b) : 0)) + return FALSE; + if (n > 0) { + g_hash_table_iter_init (&iter, a); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) { + if (!g_hash_table_lookup_extended (b, key, NULL, (gpointer *) &valu2)) + return FALSE; + if (!nm_streq (value, valu2)) + return FALSE; + } + } + return TRUE; + +} + +static gboolean +compare_property (NMSetting *setting, + NMSetting *other, + const GParamSpec *prop_spec, + NMSettingCompareFlags flags) +{ + NMSettingUserPrivate *priv, *pri2; + + g_return_val_if_fail (NM_IS_SETTING_USER (setting), FALSE); + g_return_val_if_fail (NM_IS_SETTING_USER (other), FALSE); + + if (!nm_streq0 (prop_spec->name, NM_SETTING_USER_DATA)) + goto call_parent; + + priv = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (setting)); + pri2 = NM_SETTING_USER_GET_PRIVATE (NM_SETTING_USER (other)); + + if (!hash_table_equal (priv->data, pri2->data)) + return FALSE; + + if (!hash_table_equal (priv->data_invalid, pri2->data_invalid)) + return FALSE; + + return TRUE; + +call_parent: + return NM_SETTING_CLASS (nm_setting_user_parent_class)->compare_property (setting, other, prop_spec, flags); +} + +/*****************************************************************************/ + +static void +get_property (GObject *object, guint prop_id, + GValue *value, GParamSpec *pspec) +{ + NMSettingUser *self = NM_SETTING_USER (object); + NMSettingUserPrivate *priv = NM_SETTING_USER_GET_PRIVATE (self); + GHashTableIter iter; + GHashTable *data; + const char *key, *val; + + switch (prop_id) { + case PROP_DATA: + data = _create_data_hash (); + if (priv->data) { + g_hash_table_iter_init (&iter, priv->data); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) + g_hash_table_insert (data, g_strdup (key), g_strdup (val)); + } + if (priv->data_invalid) { + g_hash_table_iter_init (&iter, priv->data_invalid); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) + g_hash_table_insert (data, g_strdup (key), g_strdup (val)); + } + g_value_take_boxed (value, data); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMSettingUser *self = NM_SETTING_USER (object); + NMSettingUserPrivate *priv = NM_SETTING_USER_GET_PRIVATE (self); + GHashTableIter iter; + GHashTable *data; + const char *key, *val; + + switch (prop_id) { + case PROP_DATA: + nm_clear_g_free (&priv->keys); + + data = g_value_get_boxed (value); + if (!data || !g_hash_table_size (data)) { + g_clear_pointer (&priv->data, g_hash_table_unref); + g_clear_pointer (&priv->data_invalid, g_hash_table_unref); + return; + } + + if (priv->data) + g_hash_table_remove_all (priv->data); + else + priv->data = _create_data_hash (); + + if (priv->data_invalid) + g_hash_table_remove_all (priv->data_invalid); + + g_hash_table_iter_init (&iter, data); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &val)) { + if ( nm_setting_user_check_key (key, NULL) + && nm_setting_user_check_val (val, NULL)) + g_hash_table_insert (priv->data, g_strdup (key), g_strdup (val)); + else { + if (!priv->data_invalid) + priv->data_invalid = _create_data_hash (); + g_hash_table_insert (priv->data_invalid, g_strdup (key), g_strdup (val)); + } + } + if ( priv->data_invalid + && !g_hash_table_size (priv->data_invalid)) + g_clear_pointer (&priv->data_invalid, g_hash_table_unref); + + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_user_init (NMSettingUser *self) +{ +} + +/** + * nm_setting_user_new: + * + * Creates a new #NMSettingUser object with default values. + * + * Returns: the new empty #NMSettingUser object + **/ +NMSetting *nm_setting_user_new (void) +{ + return (NMSetting *) g_object_new (NM_TYPE_SETTING_USER, NULL); +} + +static void +finalize (GObject *object) +{ + NMSettingUser *self = NM_SETTING_USER (object); + NMSettingUserPrivate *priv = NM_SETTING_USER_GET_PRIVATE (self); + + g_free (priv->keys); + if (priv->data) + g_hash_table_unref (priv->data); + if (priv->data_invalid) + g_hash_table_unref (priv->data_invalid); + + G_OBJECT_CLASS (nm_setting_user_parent_class)->finalize (object); +} + +static void +nm_setting_user_class_init (NMSettingUserClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + NMSettingClass *setting_class = NM_SETTING_CLASS (klass); + + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + setting_class->compare_property = compare_property; + setting_class->verify = verify; + + /** + * NMSettingUser:data: + * + * A dictionary of key/value pairs with user data. This data is ignored by NetworkManager + * and can be used at the users discretion. The keys only support a strict ascii format, + * but the values can be arbitrary UTF8 strings up to a certain length. + * + * Type: GHashTable(utf8,utf8) + * + * Since: 1.8 + **/ + obj_properties[PROP_DATA] = + g_param_spec_boxed (NM_SETTING_USER_DATA, "", "", + G_TYPE_HASH_TABLE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_transform_property (setting_class, NM_SETTING_USER_DATA, + G_VARIANT_TYPE ("a{ss}"), + _nm_utils_strdict_to_dbus, + _nm_utils_strdict_from_dbus); +} diff --git a/libnm-core/nm-setting-user.h b/libnm-core/nm-setting-user.h new file mode 100644 index 00000000..38e97a93 --- /dev/null +++ b/libnm-core/nm-setting-user.h @@ -0,0 +1,68 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ + +/* + * 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 2017 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_USER_H__ +#define __NM_SETTING_USER_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only <NetworkManager.h> can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_USER (nm_setting_user_get_type ()) +#define NM_SETTING_USER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SETTING_USER, NMSettingUser)) +#define NM_SETTING_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SETTING_USER, NMSettingUserClass)) +#define NM_IS_SETTING_USER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SETTING_USER)) +#define NM_IS_SETTING_USER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTING_USER)) +#define NM_SETTING_USER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTING_USER, NMSettingUserClass)) + +#define NM_SETTING_USER_SETTING_NAME "user" + +#define NM_SETTING_USER_DATA "data" + +typedef struct _NMSettingUserClass NMSettingUserClass; + +NM_AVAILABLE_IN_1_8 +GType nm_setting_user_get_type (void); + +NM_AVAILABLE_IN_1_8 +NMSetting * nm_setting_user_new (void); + +NM_AVAILABLE_IN_1_8 +const char *const*nm_setting_user_get_keys (NMSettingUser *setting, guint *out_len); + +NM_AVAILABLE_IN_1_8 +const char *nm_setting_user_get_data (NMSettingUser *setting, const char *key); +NM_AVAILABLE_IN_1_8 +gboolean nm_setting_user_set_data (NMSettingUser *setting, const char *key, const char *val, GError **error); + + +NM_AVAILABLE_IN_1_8 +gboolean nm_setting_user_check_key (const char *key, GError **error); +NM_AVAILABLE_IN_1_8 +gboolean nm_setting_user_check_val (const char *val, GError **error); + +G_END_DECLS + +#endif /* __NM_SETTING_USER_H__ */ diff --git a/libnm-core/nm-setting-vlan.c b/libnm-core/nm-setting-vlan.c index 61264784..de9c5c48 100644 --- a/libnm-core/nm-setting-vlan.c +++ b/libnm-core/nm-setting-vlan.c @@ -290,7 +290,7 @@ nm_setting_vlan_add_priority_str (NMSettingVlan *setting, * @setting: the #NMSettingVlan * @map: the type of priority map * - * Returns the number of entires in the + * Returns the number of entries in the * #NMSettingVlan:ingress_priority_map or #NMSettingVlan:egress_priority_map * properties of this setting. * @@ -577,7 +577,7 @@ nm_setting_vlan_remove_priority_str_by_value (NMSettingVlan *setting, * @setting: the #NMSettingVlan * @map: the type of priority map * - * Clear all the entires from #NMSettingVlan:ingress_priority_map or + * Clear all the entries from #NMSettingVlan:ingress_priority_map or * #NMSettingVlan:egress_priority_map properties. */ void @@ -600,7 +600,7 @@ nm_setting_vlan_init (NMSettingVlan *setting) { } -static gboolean +static int verify (NMSetting *setting, NMConnection *connection, GError **error) { NMSettingVlanPrivate *priv = NM_SETTING_VLAN_GET_PRIVATE (setting); @@ -681,6 +681,18 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if (connection && !s_wired) { + /* technically, a VLAN setting does not require an ethernet setting. However, + * the ifcfg-rh reader always adds a ethernet setting when reading a vlan setting. + * Thus, in order to be consistent, always add one via normalization. */ + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_SETTING_NOT_FOUND, + _("vlan setting should have a ethernet setting as well")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VLAN_FLAGS); + return NM_SETTING_VERIFY_NORMALIZABLE; + } + return TRUE; } diff --git a/libnm-core/nm-setting-vlan.h b/libnm-core/nm-setting-vlan.h index b147a185..ec41b595 100644 --- a/libnm-core/nm-setting-vlan.h +++ b/libnm-core/nm-setting-vlan.h @@ -48,6 +48,8 @@ G_BEGIN_DECLS /** * NMSettingVlan: + * + * VLAN Settings */ struct _NMSettingVlan { NMSetting parent; diff --git a/libnm-core/nm-setting-vpn.h b/libnm-core/nm-setting-vpn.h index 539656f8..115aa867 100644 --- a/libnm-core/nm-setting-vpn.h +++ b/libnm-core/nm-setting-vpn.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -49,6 +49,8 @@ G_BEGIN_DECLS /** * NMSettingVpn: + * + * VPN Settings */ struct _NMSettingVpn { NMSetting parent; diff --git a/libnm-core/nm-setting-vxlan.h b/libnm-core/nm-setting-vxlan.h index fab2d820..ce266941 100644 --- a/libnm-core/nm-setting-vxlan.h +++ b/libnm-core/nm-setting-vxlan.h @@ -58,6 +58,8 @@ G_BEGIN_DECLS /** * NMSettingVxlan: + * + * VXLAN Settings */ struct _NMSettingVxlan { NMSetting parent; diff --git a/libnm-core/nm-setting-wimax.h b/libnm-core/nm-setting-wimax.h index 3f0767e9..fb0abbac 100644 --- a/libnm-core/nm-setting-wimax.h +++ b/libnm-core/nm-setting-wimax.h @@ -26,7 +26,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -44,6 +44,8 @@ G_BEGIN_DECLS /** * NMSettingWimax: + * + * WiMax Settings */ struct _NMSettingWimax { NMSetting parent; diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c index fcd8e837..5569f558 100644 --- a/libnm-core/nm-setting-wired.c +++ b/libnm-core/nm-setting-wired.c @@ -565,10 +565,12 @@ nm_setting_wired_remove_s390_option (NMSettingWired *setting, /** * nm_setting_wired_get_valid_s390_options: - * @setting: the #NMSettingWired + * @setting: (allow-none): the #NMSettingWired * * Returns a list of valid s390 options. * + * The @setting argument is unused and %NULL may be passed instead. + * * Returns: (transfer none): a %NULL-terminated array of strings of valid s390 options. **/ const char ** diff --git a/libnm-core/nm-setting-wired.h b/libnm-core/nm-setting-wired.h index 30b0b6c2..015f09da 100644 --- a/libnm-core/nm-setting-wired.h +++ b/libnm-core/nm-setting-wired.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -96,6 +96,8 @@ typedef enum { /*< flags >*/ /** * NMSettingWired: + * + * Wired Ethernet Settings */ struct _NMSettingWired { NMSetting parent; diff --git a/libnm-core/nm-setting-wireless-security.c b/libnm-core/nm-setting-wireless-security.c index f98e9e57..70bdf754 100644 --- a/libnm-core/nm-setting-wireless-security.c +++ b/libnm-core/nm-setting-wireless-security.c @@ -182,7 +182,7 @@ nm_setting_wireless_security_get_proto (NMSettingWirelessSecurity *setting, guin * by this connection only supports WPA2/RSN, the connection cannot be used * with the access point. * - * Returns: %TRUE if the protocol was new and and was added to the allowed + * Returns: %TRUE if the protocol was new and was added to the allowed * protocol list, or %FALSE if it was already in the list **/ gboolean @@ -236,7 +236,7 @@ nm_setting_wireless_security_remove_proto (NMSettingWirelessSecurity *setting, g * * Removes a protocol from the allowed protocol list. * - * Returns: %TRUE if the protocol was found and removed; %FALSE it it was not. + * Returns: %TRUE if the protocol was found and removed; %FALSE if it was not. **/ gboolean nm_setting_wireless_security_remove_proto_by_value (NMSettingWirelessSecurity *setting, @@ -382,7 +382,7 @@ nm_setting_wireless_security_remove_pairwise (NMSettingWirelessSecurity *setting * Removes an encryption algorithm from the allowed pairwise encryption * algorithm list. * - * Returns: %TRUE if the encryption algorith was found and removed; %FALSE it it was not. + * Returns: %TRUE if the encryption algorith was found and removed; %FALSE if it was not. **/ gboolean nm_setting_wireless_security_remove_pairwise_by_value (NMSettingWirelessSecurity *setting, @@ -530,7 +530,7 @@ nm_setting_wireless_security_remove_group (NMSettingWirelessSecurity *setting, g * Removes an encryption algorithm from the allowed groupwise encryption * algorithm list. * - * Returns: %TRUE if the algorithm was found and removed; %FALSE it it was not. + * Returns: %TRUE if the algorithm was found and removed; %FALSE if it was not. **/ gboolean nm_setting_wireless_security_remove_group_by_value (NMSettingWirelessSecurity *setting, diff --git a/libnm-core/nm-setting-wireless-security.h b/libnm-core/nm-setting-wireless-security.h index 093cb386..ae252f11 100644 --- a/libnm-core/nm-setting-wireless-security.h +++ b/libnm-core/nm-setting-wireless-security.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> +#include "nm-setting.h" G_BEGIN_DECLS @@ -91,6 +91,8 @@ typedef enum { /** * NMSettingWirelessSecurity: + * + * Wi-Fi Security Settings */ struct _NMSettingWirelessSecurity { NMSetting parent; diff --git a/libnm-core/nm-setting-wireless.h b/libnm-core/nm-setting-wireless.h index 35fa79c1..b0ef4756 100644 --- a/libnm-core/nm-setting-wireless.h +++ b/libnm-core/nm-setting-wireless.h @@ -27,8 +27,8 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-setting.h> -#include <nm-setting-wireless-security.h> +#include "nm-setting.h" +#include "nm-setting-wireless-security.h" G_BEGIN_DECLS @@ -101,6 +101,8 @@ typedef enum { /** * NMSettingWireless: + * + * Wi-Fi Settings */ struct _NMSettingWireless { NMSetting parent; diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 82467c9c..e4be8706 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -147,6 +147,8 @@ _ensure_registered_constructor (void) * can be established, like PPP, PPPoE, etc. * * 4: IP-level stuff + * + * 10: NMSettingUser */ void (_nm_register_setting) (const char *name, @@ -158,7 +160,6 @@ void g_return_if_fail (name != NULL && *name); g_return_if_fail (type != G_TYPE_INVALID); g_return_if_fail (type != G_TYPE_NONE); - g_return_if_fail (priority <= 4); _ensure_registered (); @@ -304,8 +305,8 @@ typedef struct { NMSettingPropertyTransformFromFunc from_dbus; } NMSettingProperty; -static GQuark setting_property_overrides_quark; -static GQuark setting_properties_quark; +static NM_CACHED_QUARK_FCN ("nm-setting-property-overrides", setting_property_overrides_quark) +static NM_CACHED_QUARK_FCN ("nm-setting-properties", setting_properties_quark) static NMSettingProperty * find_property (GArray *properties, const char *name) @@ -341,7 +342,7 @@ add_property_override (NMSettingClass *setting_class, GArray *overrides; NMSettingProperty override; - g_return_if_fail (g_type_get_qdata (setting_type, setting_properties_quark) == NULL); + g_return_if_fail (g_type_get_qdata (setting_type, setting_properties_quark ()) == NULL); memset (&override, 0, sizeof (override)); override.name = property_name; @@ -354,10 +355,10 @@ add_property_override (NMSettingClass *setting_class, override.to_dbus = to_dbus; override.from_dbus = from_dbus; - overrides = g_type_get_qdata (setting_type, setting_property_overrides_quark); + overrides = g_type_get_qdata (setting_type, setting_property_overrides_quark ()); if (!overrides) { overrides = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty)); - g_type_set_qdata (setting_type, setting_property_overrides_quark, overrides); + g_type_set_qdata (setting_type, setting_property_overrides_quark (), overrides); } g_return_if_fail (find_property (overrides, property_name) == NULL); @@ -530,14 +531,14 @@ nm_setting_class_ensure_properties (NMSettingClass *setting_class) GParamSpec **property_specs; guint n_property_specs, i; - properties = g_type_get_qdata (type, setting_properties_quark); + properties = g_type_get_qdata (type, setting_properties_quark ()); if (properties) return properties; /* Build overrides array from @setting_class and its superclasses */ overrides = g_array_new (FALSE, FALSE, sizeof (NMSettingProperty)); for (otype = type; otype != G_TYPE_OBJECT; otype = g_type_parent (otype)) { - type_overrides = g_type_get_qdata (otype, setting_property_overrides_quark); + type_overrides = g_type_get_qdata (otype, setting_property_overrides_quark ()); if (type_overrides) g_array_append_vals (overrides, (NMSettingProperty *)type_overrides->data, type_overrides->len); } @@ -568,7 +569,7 @@ nm_setting_class_ensure_properties (NMSettingClass *setting_class) } g_array_unref (overrides); - g_type_set_qdata (type, setting_properties_quark, properties); + g_type_set_qdata (type, setting_properties_quark (), properties); return properties; } @@ -1995,11 +1996,6 @@ nm_setting_class_init (NMSettingClass *setting_class) { GObjectClass *object_class = G_OBJECT_CLASS (setting_class); - if (!setting_property_overrides_quark) - setting_property_overrides_quark = g_quark_from_static_string ("nm-setting-property-overrides"); - if (!setting_properties_quark) - setting_properties_quark = g_quark_from_static_string ("nm-setting-properties"); - g_type_class_add_private (setting_class, sizeof (NMSettingPrivate)); /* virtual methods */ diff --git a/libnm-core/nm-setting.h b/libnm-core/nm-setting.h index 3083ef60..bf3f8e56 100644 --- a/libnm-core/nm-setting.h +++ b/libnm-core/nm-setting.h @@ -27,7 +27,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-core-types.h> +#include "nm-core-types.h" G_BEGIN_DECLS diff --git a/libnm-core/nm-simple-connection.h b/libnm-core/nm-simple-connection.h index d6a60447..4166d4ca 100644 --- a/libnm-core/nm-simple-connection.h +++ b/libnm-core/nm-simple-connection.h @@ -25,7 +25,7 @@ #error "Only <NetworkManager.h> can be included directly." #endif -#include <nm-connection.h> +#include "nm-connection.h" G_BEGIN_DECLS diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h index fab38038..03c87907 100644 --- a/libnm-core/nm-utils-private.h +++ b/libnm-core/nm-utils-private.h @@ -28,6 +28,14 @@ #include "nm-setting-private.h" #include "nm-setting-ip-config.h" +struct _NMVariantAttributeSpec { + char *name; + const GVariantType *type; + bool v4:1; + bool v6:1; + char str_type; +}; + gboolean _nm_utils_string_slist_validate (GSList *list, const char **valid_values); diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 478a548d..1feee7ac 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -443,52 +443,6 @@ nm_utils_same_ssid (const guint8 *ssid1, gsize len1, return memcmp (ssid1, ssid2, len1) == 0 ? TRUE : FALSE; } -/** - * _nm_utils_strv_find_first: - * @list: the strv list to search - * @len: the length of the list, or a negative value if @list is %NULL terminated. - * @needle: the value to search for. The search is done using strcmp(). - * - * Searches @list for @needle and returns the index of the first match (based - * on strcmp()). - * - * For convenience, @list has type 'char**' instead of 'const char **'. - * - * Returns: index of first occurrence or -1 if @needle is not found in @list. - */ -gssize -_nm_utils_strv_find_first (char **list, gssize len, const char *needle) -{ - gssize i; - - if (len > 0) { - g_return_val_if_fail (list, -1); - - if (!needle) { - /* if we search a list with known length, %NULL is a valid @needle. */ - for (i = 0; i < len; i++) { - if (!list[i]) - return i; - } - } else { - for (i = 0; i < len; i++) { - if (list[i] && !strcmp (needle, list[i])) - return i; - } - } - } else if (len < 0) { - g_return_val_if_fail (needle, -1); - - if (list) { - for (i = 0; list[i]; i++) { - if (strcmp (needle, list[i]) == 0) - return i; - } - } - } - return -1; -} - char ** _nm_utils_strv_cleanup (char **strv, gboolean strip_whitespace, @@ -509,7 +463,7 @@ _nm_utils_strv_cleanup (char **strv, j = 0; for (i = 0; strv[i]; i++) { if ( (skip_empty && !*strv[i]) - || (skip_repeated && _nm_utils_strv_find_first (strv, j, strv[i]) >= 0)) + || (skip_repeated && nm_utils_strv_find_first (strv, j, strv[i]) >= 0)) g_free (strv[i]); else strv[j++] = strv[i]; @@ -3791,7 +3745,7 @@ nm_utils_is_valid_iface_name (const char *name, GError **error) * * Validate the network interface name. * - * Deprecated: 1.6: use nm_utils_is_valid_iface_name() insteead, with better error reporting. + * Deprecated: 1.6: use nm_utils_is_valid_iface_name() instead, with better error reporting. * * Returns: %TRUE if interface name is valid, otherwise %FALSE is returned. */ @@ -4295,48 +4249,74 @@ int _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option) return -1; } -/** - * nm_utils_enum_to_str: - * @type: the %GType of the enum - * @value: the value to be translated - * - * Converts an enum value to its string representation. If the enum is a - * %G_TYPE_FLAGS the function returns a comma-separated list of matching values. - * If the enum is a %G_TYPE_ENUM and the given value is not valid the - * function returns %NULL. - * - * Returns: a newly allocated string or %NULL - * - * Since: 1.2 - */ -char *nm_utils_enum_to_str (GType type, int value) +#define IS_FLAGS_SEPARATOR(ch) (NM_IN_SET ((ch), ' ', '\t', ',', '\n', '\r')) + +static gboolean +_is_hex_string (const char *str) +{ + return str[0] == '0' + && str[1] == 'x' + && str[2] + && NM_STRCHAR_ALL (&str[2], ch, g_ascii_isxdigit (ch)); +} + +static gboolean +_enum_is_valid_enum_nick (const char *str) +{ + return str[0] + && !NM_STRCHAR_ANY (str, ch, g_ascii_isspace (ch)) + && !NM_STRCHAR_ALL (str, ch, g_ascii_isdigit (ch)); +} + +static gboolean +_enum_is_valid_flags_nick (const char *str) +{ + return str[0] + && !NM_STRCHAR_ANY (str, ch, IS_FLAGS_SEPARATOR (ch)) + && !_is_hex_string (str); +} + +char * +_nm_utils_enum_to_str_full (GType type, + int value, + const char *flags_separator) { GTypeClass *class; char *ret; + if ( flags_separator + && ( !flags_separator[0] + || NM_STRCHAR_ANY (flags_separator, ch, !IS_FLAGS_SEPARATOR (ch)))) + g_return_val_if_reached (NULL); + class = g_type_class_ref (type); if (G_IS_ENUM_CLASS (class)) { GEnumValue *enum_value; enum_value = g_enum_get_value (G_ENUM_CLASS (class), value); - ret = enum_value ? strdup (enum_value->value_nick) : NULL; + if ( !enum_value + || !_enum_is_valid_enum_nick (enum_value->value_nick)) + ret = g_strdup_printf ("%d", value); + else + ret = strdup (enum_value->value_nick); } else if (G_IS_FLAGS_CLASS (class)) { GFlagsValue *flags_value; GString *str = g_string_new (""); - gboolean first = TRUE; + + flags_separator = flags_separator ?: " "; while (value) { flags_value = g_flags_get_first_value (G_FLAGS_CLASS (class), value); - if (!flags_value) + if (str->len) + g_string_append (str, flags_separator); + if ( !flags_value + || !_enum_is_valid_flags_nick (flags_value->value_nick)) { + g_string_append_printf (str, "0x%x", (unsigned) value); break; - - if (!first) - g_string_append (str, ", "); + } g_string_append (str, flags_value->value_nick); - value &= ~flags_value->value; - first = FALSE; } ret = g_string_free (str, FALSE); } else @@ -4347,11 +4327,31 @@ char *nm_utils_enum_to_str (GType type, int value) } /** + * nm_utils_enum_to_str: + * @type: the %GType of the enum + * @value: the value to be translated + * + * Converts an enum value to its string representation. If the enum is a + * %G_TYPE_FLAGS the function returns a comma-separated list of matching values. + * If the enum is a %G_TYPE_ENUM and the given value is not valid the + * function returns %NULL. + * + * Returns: a newly allocated string or %NULL + * + * Since: 1.2 + */ +char * +nm_utils_enum_to_str (GType type, int value) +{ + return _nm_utils_enum_to_str_full (type, value, ", "); +} + +/** * nm_utils_enum_from_str: * @type: the %GType of the enum * @str: the input string * @out_value: (out) (allow-none): the output value - * @err_token: (out) (allow-none): location to store the first unrecognized token + * @err_token: (out) (allow-none) (transfer full): location to store the first unrecognized token * * Converts a string to the matching enum value. * @@ -4364,55 +4364,83 @@ char *nm_utils_enum_to_str (GType type, int value) * * Since: 1.2 */ -gboolean nm_utils_enum_from_str (GType type, const char *str, - int *out_value, char **err_token) +gboolean +nm_utils_enum_from_str (GType type, const char *str, + int *out_value, char **err_token) { GTypeClass *class; gboolean ret = FALSE; int value = 0; - gs_free char *stripped = NULL; + gs_free char *str_clone = NULL; + char *s; + gint64 v64; g_return_val_if_fail (str, FALSE); - stripped = g_strstrip (strdup (str)); + + str_clone = strdup (str); + s = nm_str_skip_leading_spaces (str_clone); + g_strchomp (s); + class = g_type_class_ref (type); if (G_IS_ENUM_CLASS (class)) { GEnumValue *enum_value; - enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (class), stripped); - if (enum_value) { - value = enum_value->value; - ret = TRUE; + if (s[0]) { + if (NM_STRCHAR_ALL (s, ch, g_ascii_isdigit (ch))) { + v64 = _nm_utils_ascii_str_to_int64 (s, 10, 0, G_MAXINT, -1); + if (v64 != -1) { + value = (int) v64; + ret = TRUE; + } + } else { + enum_value = g_enum_get_value_by_nick (G_ENUM_CLASS (class), s); + if (enum_value) { + value = enum_value->value; + ret = TRUE; + } + } } } else if (G_IS_FLAGS_CLASS (class)) { GFlagsValue *flags_value; - gs_strfreev char **strv = NULL; - int i; - strv = g_strsplit_set (stripped, " \t,", 0); - for (i = 0; strv[i]; i++) { - if (!strv[i][0]) - continue; + ret = TRUE; + while (s[0]) { + char *s_end; - flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), strv[i]); - if (!flags_value) - break; + for (s_end = s; s_end[0]; s_end++) { + if (IS_FLAGS_SEPARATOR (s_end[0])) { + s_end[0] = '\0'; + s_end++; + break; + } + } - value |= flags_value->value; - } + if (s[0]) { + if (_is_hex_string (s)) { + v64 = _nm_utils_ascii_str_to_int64 (&s[2], 16, 0, G_MAXUINT, -1); + if (v64 == -1) { + ret = FALSE; + break; + } + value |= (int) v64; + } else { + flags_value = g_flags_get_value_by_nick (G_FLAGS_CLASS (class), s); + if (!flags_value) { + ret = FALSE; + break; + } + value |= flags_value->value; + } + } - if (strv[i]) { - if (err_token) - *err_token = strdup (strv[i]); - value = 0; - } else - ret = TRUE; + s = s_end; + } } else g_return_val_if_reached (FALSE); - if (out_value) - *out_value = value; - + NM_SET_OUT (err_token, !ret && s[0] ? g_strdup (s) : NULL); + NM_SET_OUT (out_value, ret ? value : 0); g_type_class_unref (class); return ret; } @@ -4425,7 +4453,7 @@ gboolean nm_utils_enum_from_str (GType type, const char *str, * * Returns the list of possible values for a given enum. * - * Returns: (transfer full): a NULL-terminated dynamically-allocated array of static strings + * Returns: (transfer container): a NULL-terminated dynamically-allocated array of static strings * or %NULL on error * * Since: 1.2 @@ -4435,6 +4463,7 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to) GTypeClass *class; GPtrArray *array; gint i; + char sbuf[64]; class = g_type_class_ref (type); array = g_ptr_array_new (); @@ -4445,8 +4474,12 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to) for (i = 0; i < enum_class->n_values; i++) { enum_value = &enum_class->values[i]; - if (enum_value->value >= from && enum_value->value <= to) - g_ptr_array_add (array, (gpointer) enum_value->value_nick); + if (enum_value->value >= from && enum_value->value <= to) { + if (_enum_is_valid_enum_nick (enum_value->value_nick)) + g_ptr_array_add (array, (gpointer) enum_value->value_nick); + else + g_ptr_array_add (array, (gpointer) g_intern_string (nm_sprintf_buf (sbuf, "%d", enum_value->value))); + } } } else if (G_IS_FLAGS_CLASS (class)) { GFlagsClass *flags_class = G_FLAGS_CLASS (class); @@ -4454,8 +4487,12 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to) for (i = 0; i < flags_class->n_values; i++) { flags_value = &flags_class->values[i]; - if (flags_value->value >= from && flags_value->value <= to) - g_ptr_array_add (array, (gpointer) flags_value->value_nick); + if (flags_value->value >= from && flags_value->value <= to) { + if (_enum_is_valid_flags_nick (flags_value->value_nick)) + g_ptr_array_add (array, (gpointer) flags_value->value_nick); + else + g_ptr_array_add (array, (gpointer) g_intern_string (nm_sprintf_buf (sbuf, "0x%x", (unsigned) flags_value->value))); + } } } else { g_type_class_unref (class); @@ -4660,6 +4697,261 @@ _nm_utils_team_config_equal (const char *conf1, } #endif +static char * +attribute_escape (const char *src, char c1, char c2) +{ + char *ret, *dest; + + dest = ret = malloc (strlen (src) * 2 + 1); + + while (*src) { + if (*src == c1 || *src == c2 || *src == '\\') + *dest++ = '\\'; + *dest++ = *src++; + } + *dest++ = '\0'; + + return ret; +} + +static char * +attribute_unescape (const char *start, const char *end) +{ + char *ret, *dest; + + nm_assert (start <= end); + dest = ret = g_malloc (end - start + 1); + + for (; start < end && *start; start++) { + if (*start == '\\') { + start++; + if (!*start) + break; + } + *dest++ = *start; + } + *dest = '\0'; + + return ret; +} + +/** + * nm_utils_parse_variant_attributes: + * @string: the input string + * @attr_separator: the attribute separator character + * @key_value_separator: character separating key and values + * @ignore_unknown: whether unknown attributes should be ignored + * @spec: the attribute format specifiers + * @error: (out) (allow-none): location to store the error on failure + * + * Parse attributes from a string. + * + * Returns: (transfer full): a #GHashTable mapping attribute names to #GVariant values. + * + * Since: 1.8 + */ +GHashTable * +nm_utils_parse_variant_attributes (const char *string, + char attr_separator, + char key_value_separator, + gboolean ignore_unknown, + const NMVariantAttributeSpec *const *spec, + GError **error) +{ + gs_unref_hashtable GHashTable *ht = NULL; + const char *ptr = string, *start = NULL, *sep; + GVariant *variant; + const NMVariantAttributeSpec * const *s; + + g_return_val_if_fail (string, NULL); + g_return_val_if_fail (attr_separator, NULL); + g_return_val_if_fail (key_value_separator, NULL); + g_return_val_if_fail (!error || !*error, NULL); + + ht = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, (GDestroyNotify) g_variant_unref); + + while (TRUE) { + gs_free char *name = NULL, *value = NULL; + + if (!start) + start = ptr; + if (*ptr == '\\') { + ptr++; + if (!*ptr) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("unterminated escape sequence")); + return NULL; + } + goto next; + } + if (*ptr == attr_separator || *ptr == '\0') { + if (ptr == start) { + /* multiple separators */ + start = NULL; + goto next; + } + + /* Find the key-value separator */ + for (sep = start; sep != ptr; sep++) { + if (*sep == '\\') { + sep++; + if (!*sep) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("unterminated escape sequence")); + return NULL; + } + } + if (*sep == key_value_separator) + break; + } + + if (*sep != key_value_separator) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("missing key-value separator '%c'"), key_value_separator); + return NULL; + } + + name = attribute_unescape (start, sep); + value = attribute_unescape (sep + 1, ptr); + + for (s = spec; *s; s++) { + if (nm_streq (name, (*s)->name)) + break; + } + + if (!*s) { + if (ignore_unknown) + goto next; + else { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("unknown attribute '%s'"), name); + return NULL; + } + } + + if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_UINT32)) { + gint64 num = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT32, -1); + + if (num == -1) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("invalid uint32 value '%s' for attribute '%s'"), value, name); + return NULL; + } + variant = g_variant_new_uint32 (num); + } else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_BYTE)) { + gint64 num = _nm_utils_ascii_str_to_int64 (value, 10, 0, G_MAXUINT8, -1); + + if (num == -1) { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("invalid uint8 value '%s' for attribute '%s'"), value, name); + return NULL; + } + variant = g_variant_new_byte ((guchar) num); + } else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_BOOLEAN)) { + gboolean b; + + if (nm_streq (value, "true")) + b = TRUE; + else if (nm_streq (value, "false")) + b = FALSE; + else { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("invalid boolean value '%s' for attribute '%s'"), value, name); + return NULL; + } + variant = g_variant_new_boolean (b); + } else if (g_variant_type_equal ((*s)->type, G_VARIANT_TYPE_STRING)) { + variant = g_variant_new_take_string (g_steal_pointer (&value)); + } else { + g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED, + _("unsupported attribute '%s' of type '%s'"), name, + (char *) (*s)->type); + return NULL; + } + + g_hash_table_insert (ht, g_steal_pointer (&name), variant); + start = NULL; + } +next: + if (*ptr == '\0') + break; + ptr++; + } + + return g_steal_pointer (&ht); +} + +/* + * nm_utils_format_variant_attributes: + * @attributes: a #GHashTable mapping attribute names to #GVariant values + * @attr_separator: the attribute separator character + * @key_value_separator: character separating key and values + * + * Format attributes to a string. + * + * Returns: (transfer full): the string representing attributes, or %NULL + * in case there are no attributes + * + * Since: 1.8 + */ +char * +nm_utils_format_variant_attributes (GHashTable *attributes, + char attr_separator, + char key_value_separator) +{ + GString *str = NULL; + GVariant *variant; + char sep = 0; + const char *name, *value; + char *escaped; + char buf[64]; + gs_free_list GList *keys = NULL; + GList *iter; + + g_return_val_if_fail (attr_separator, NULL); + g_return_val_if_fail (key_value_separator, NULL); + + if (!attributes || !g_hash_table_size (attributes)) + return NULL; + + keys = g_list_sort (g_hash_table_get_keys (attributes), (GCompareFunc) g_strcmp0); + str = g_string_new (""); + + for (iter = keys; iter; iter = g_list_next (iter)) { + name = iter->data; + variant = g_hash_table_lookup (attributes, name); + value = NULL; + + if (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)) + value = nm_sprintf_buf (buf, "%u", g_variant_get_uint32 (variant)); + else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BYTE)) + value = nm_sprintf_buf (buf, "%hhu", g_variant_get_byte (variant)); + else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_BOOLEAN)) + value = g_variant_get_boolean (variant) ? "true" : "false"; + else if (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)) + value = g_variant_get_string (variant, NULL); + else + continue; + + if (sep) + g_string_append_c (str, sep); + + escaped = attribute_escape (name, attr_separator, key_value_separator); + g_string_append (str, escaped); + g_free (escaped); + + g_string_append_c (str, key_value_separator); + + escaped = attribute_escape (value, attr_separator, key_value_separator); + g_string_append (str, escaped); + g_free (escaped); + + sep = attr_separator; + } + + return g_string_free (str, FALSE); +} + /*****************************************************************************/ /** diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h index caf2e62e..77fe18a9 100644 --- a/libnm-core/nm-utils.h +++ b/libnm-core/nm-utils.h @@ -38,6 +38,8 @@ G_BEGIN_DECLS +typedef struct _NMVariantAttributeSpec NMVariantAttributeSpec; + /* SSID helpers */ gboolean nm_utils_is_empty_ssid (const guint8 *ssid, gsize len); const char *nm_utils_escape_ssid (const guint8 *ssid, gsize len); @@ -215,6 +217,19 @@ const char **nm_utils_enum_get_values (GType type, gint from, gint to); NM_AVAILABLE_IN_1_6 guint nm_utils_version (void); +NM_AVAILABLE_IN_1_8 +GHashTable * nm_utils_parse_variant_attributes (const char *string, + char attr_separator, + char key_value_separator, + gboolean ignore_unknown, + const NMVariantAttributeSpec *const *spec, + GError **error); + +NM_AVAILABLE_IN_1_8 +char * nm_utils_format_variant_attributes (GHashTable *attributes, + char attr_separator, + char key_value_separator); + G_END_DECLS #endif /* __NM_UTILS_H__ */ diff --git a/libnm-core/nm-version.h b/libnm-core/nm-version.h index aa92c3f8..c6cd2892 100644 --- a/libnm-core/nm-version.h +++ b/libnm-core/nm-version.h @@ -23,7 +23,7 @@ #include <glib.h> -#include <nm-version-macros.h> +#include "nm-version-macros.h" /* Deprecation / Availability macros */ @@ -118,4 +118,18 @@ # define NM_AVAILABLE_IN_1_6 #endif +#if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_8 +# define NM_DEPRECATED_IN_1_8 G_DEPRECATED +# define NM_DEPRECATED_IN_1_8_FOR(f) G_DEPRECATED_FOR(f) +#else +# define NM_DEPRECATED_IN_1_8 +# define NM_DEPRECATED_IN_1_8_FOR(f) +#endif + +#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_8 +# define NM_AVAILABLE_IN_1_8 G_UNAVAILABLE(1,8) +#else +# define NM_AVAILABLE_IN_1_8 +#endif + #endif /* NM_VERSION_H */ diff --git a/libnm-core/nm-vpn-dbus-interface.h b/libnm-core/nm-vpn-dbus-interface.h index 1495c955..9c9bc297 100644 --- a/libnm-core/nm-vpn-dbus-interface.h +++ b/libnm-core/nm-vpn-dbus-interface.h @@ -26,6 +26,12 @@ #ifndef __NM_VPN_DBUS_INTERFACE_H__ #define __NM_VPN_DBUS_INTERFACE_H__ +#include "nm-dbus-interface.h" + +#ifndef NM_VERSION_H +#define NM_DEPRECATED_IN_1_8_FOR(n) +#endif + /* * dbus services details */ @@ -147,19 +153,20 @@ typedef enum { * * VPN connection state reasons */ +NM_DEPRECATED_IN_1_8_FOR(NMActiveConnectionStateReason) typedef enum { - NM_VPN_CONNECTION_STATE_REASON_UNKNOWN = 0, - NM_VPN_CONNECTION_STATE_REASON_NONE, - NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED, - NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, - NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED, - NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, - NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, - NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, - NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, - NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, - NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED, - NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED + NM_VPN_CONNECTION_STATE_REASON_UNKNOWN = NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN, + NM_VPN_CONNECTION_STATE_REASON_NONE = NM_ACTIVE_CONNECTION_STATE_REASON_NONE, + NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED = NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED, + NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED = NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, + NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED = NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED, + NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID = NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, + NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT = NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, + NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT = NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, + NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED = NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED, + NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS = NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS, + NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED = NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED, + NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED = NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED, } NMVpnConnectionStateReason; /** @@ -177,6 +184,9 @@ typedef enum { NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG } NMVpnPluginFailure; +#ifndef NM_VERSION_H +#undef NM_DEPRECATED_IN_1_8_FOR +#endif /*** Generic config ***/ diff --git a/libnm-core/nm-vpn-dbus-types.xml b/libnm-core/nm-vpn-dbus-types.xml index 5da02420..571b437e 100644 --- a/libnm-core/nm-vpn-dbus-types.xml +++ b/libnm-core/nm-vpn-dbus-types.xml @@ -144,62 +144,62 @@ <tbody> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_UNKNOWN</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>0</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN</literal></para><para></para></entry> <entry role="enum_member_description"><para>The reason for the VPN connection state change is unknown.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_NONE</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>1</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_NONE</literal></para><para></para></entry> <entry role="enum_member_description"><para>No reason was given for the VPN connection state change.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>2</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED</literal></para><para></para></entry> <entry role="enum_member_description"><para>The VPN connection changed state because the user disconnected it.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>3</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED</literal></para><para></para></entry> <entry role="enum_member_description"><para>The VPN connection changed state because the device it was using was disconnected.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>4</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED</literal></para><para></para></entry> <entry role="enum_member_description"><para>The service providing the VPN connection was stopped.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>5</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID</literal></para><para></para></entry> <entry role="enum_member_description"><para>The IP config of the VPN connection was invalid.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>6</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT</literal></para><para></para></entry> <entry role="enum_member_description"><para>The connection attempt to the VPN service timed out.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>7</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT</literal></para><para></para></entry> <entry role="enum_member_description"><para>A timeout occurred while starting the service providing the VPN connection.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>8</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED</literal></para><para></para></entry> <entry role="enum_member_description"><para>Starting the service starting the service providing the VPN connection failed.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>9</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS</literal></para><para></para></entry> <entry role="enum_member_description"><para>Necessary secrets for the VPN connection were not provided.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>10</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED</literal></para><para></para></entry> <entry role="enum_member_description"><para>Authentication to the VPN server failed.</para><para></para></entry> </row> <row role="constant"> <entry role="enum_member_name"><para>NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED</para><para></para></entry> - <entry role="enum_member_value"><para>= <literal>11</literal></para><para></para></entry> + <entry role="enum_member_value"><para>= <literal>NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED</literal></para><para></para></entry> <entry role="enum_member_description"><para>The connection was deleted from settings.</para><para></para></entry> </row> </tbody> diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c index 14c3588e..115c397f 100644 --- a/libnm-core/nm-vpn-plugin-info.c +++ b/libnm-core/nm-vpn-plugin-info.c @@ -339,7 +339,7 @@ nm_vpn_plugin_info_list_load () for (i = 0; i < G_N_ELEMENTS (dir); i++) { if ( !dir[i] - || _nm_utils_strv_find_first ((char **) dir, i, dir[i]) >= 0) + || nm_utils_strv_find_first ((char **) dir, i, dir[i]) >= 0) continue; infos = _nm_vpn_plugin_info_list_load_dir (dir[i], TRUE, uid, NULL, NULL); @@ -384,7 +384,7 @@ nm_vpn_plugin_info_new_search_file (const char *name, const char *service) for (i = 0; !plugin_info && i < G_N_ELEMENTS (dir); i++) { if ( !dir[i] - || _nm_utils_strv_find_first ((char **) dir, i, dir[i]) >= 0) + || nm_utils_strv_find_first ((char **) dir, i, dir[i]) >= 0) continue; /* We still must load the entire directory while searching for the matching @@ -400,8 +400,8 @@ nm_vpn_plugin_info_new_search_file (const char *name, const char *service) continue; if ( service && !nm_streq (nm_vpn_plugin_info_get_service (p), service) - && (_nm_utils_strv_find_first (NM_VPN_PLUGIN_INFO_GET_PRIVATE (p)->aliases, - -1, service) < 0)) + && (nm_utils_strv_find_first (NM_VPN_PLUGIN_INFO_GET_PRIVATE (p)->aliases, + -1, service) < 0)) continue; plugin_info = g_object_ref (p); break; @@ -580,7 +580,7 @@ _list_find_by_service (GSList *list, const char *service) NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (list->data); if ( nm_streq (priv->service, service) - || _nm_utils_strv_find_first (priv->aliases, -1, service) >= 0) + || nm_utils_strv_find_first (priv->aliases, -1, service) >= 0) return list->data; } return NULL; @@ -667,7 +667,7 @@ nm_vpn_plugin_info_list_find_service_type (GSList *list, const char *name) /* check the hard-coded list of short-names. They all have have the same * well-known prefix org.freedesktop.NetworkManager and the name. */ - if (_nm_utils_strv_find_first ((char **) known_names, G_N_ELEMENTS (known_names), name) >= 0) + if (nm_utils_strv_find_first ((char **) known_names, G_N_ELEMENTS (known_names), name) >= 0) return g_strdup_printf ("%s.%s", NM_DBUS_INTERFACE, name); /* try, if there exists a plugin with @name under org.freedesktop.NetworkManager. diff --git a/libnm-core/tests/test-general-enums.h b/libnm-core/tests/test-general-enums.h index d06d6e39..8aa3f99f 100644 --- a/libnm-core/tests/test-general-enums.h +++ b/libnm-core/tests/test-general-enums.h @@ -27,6 +27,8 @@ typedef enum { NM_TEST_GENERAL_BOOL_ENUM_MAYBE = 2, NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN = 3, NM_TEST_GENERAL_BOOL_ENUM_INVALID = 4, /*< skip >*/ + NM_TEST_GENERAL_BOOL_ENUM_67 = 67, + NM_TEST_GENERAL_BOOL_ENUM_46 = 64, } NMTestGeneralBoolEnum; typedef enum { @@ -34,6 +36,8 @@ typedef enum { NM_TEST_GENERAL_META_FLAGS_FOO = (1 << 0), NM_TEST_GENERAL_META_FLAGS_BAR = (1 << 1), NM_TEST_GENERAL_META_FLAGS_BAZ = (1 << 2), + NM_TEST_GENERAL_META_FLAGS_0x8 = (1 << 3), + NM_TEST_GENERAL_META_FLAGS_0x4 = (1 << 4), } NMTestGeneralMetaFlags; typedef enum { /*< flags >*/ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index b9fef8da..7ecd6813 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -51,6 +51,7 @@ #include "nm-setting-serial.h" #include "nm-setting-team.h" #include "nm-setting-team-port.h" +#include "nm-setting-user.h" #include "nm-setting-vlan.h" #include "nm-setting-vpn.h" #include "nm-setting-wimax.h" @@ -643,6 +644,47 @@ test_setting_ip4_config_address_data (void) } static void +test_setting_ip_route_attributes (void) +{ + GVariant *variant; + gboolean res, known; + +#define TEST_ATTR(name, type, value, family, exp_res, exp_known) \ + variant = g_variant_new_ ## type (value); \ + res = nm_ip_route_attribute_validate (name, variant, family, &known, NULL); \ + g_assert (res == exp_res); \ + g_assert (known == exp_known); \ + g_variant_unref (variant); + + TEST_ATTR ("foo", uint32, 12, AF_INET, FALSE, FALSE); + + TEST_ATTR ("tos", byte, 127, AF_INET, TRUE, TRUE); + TEST_ATTR ("tos", string, "0x28", AF_INET, FALSE, TRUE); + + TEST_ATTR ("cwnd", uint32, 10, AF_INET, TRUE, TRUE); + TEST_ATTR ("cwnd", string, "11", AF_INET, FALSE, TRUE); + + TEST_ATTR ("lock-mtu", boolean, TRUE, AF_INET, TRUE, TRUE); + TEST_ATTR ("lock-mtu", uint32, 1, AF_INET, FALSE, TRUE); + + TEST_ATTR ("from", string, "fd01::1", AF_INET6, TRUE, TRUE); + TEST_ATTR ("from", string, "fd01::1/64", AF_INET6, TRUE, TRUE); + TEST_ATTR ("from", string, "fd01::1/128", AF_INET6, TRUE, TRUE); + TEST_ATTR ("from", string, "fd01::1/129", AF_INET6, FALSE, TRUE); + TEST_ATTR ("from", string, "fd01::1/a", AF_INET6, FALSE, TRUE); + TEST_ATTR ("from", string, "abc/64", AF_INET6, FALSE, TRUE); + TEST_ATTR ("from", string, "1.2.3.4", AF_INET, FALSE, TRUE); + TEST_ATTR ("from", string, "1.2.3.4", AF_INET6, FALSE, TRUE); + + TEST_ATTR ("src", string, "1.2.3.4", AF_INET, TRUE, TRUE); + TEST_ATTR ("src", string, "1.2.3.4", AF_INET6, FALSE, TRUE); + TEST_ATTR ("src", string, "1.2.3.0/24", AF_INET, FALSE, TRUE); + TEST_ATTR ("src", string, "fd01::12", AF_INET6, TRUE, TRUE); + +#undef TEST_ATTR +} + +static void test_setting_gsm_apn_spaces (void) { gs_unref_object NMSettingGsm *s_gsm = NULL; @@ -4285,6 +4327,18 @@ test_setting_compare_default_strv (void) out_settings = NULL; } +/*****************************************************************************/ + +static void +test_setting_user_data (void) +{ + gs_unref_object NMSettingUser *s_user = NULL; + + s_user = NM_SETTING_USER (nm_setting_user_new ()); +} + +/*****************************************************************************/ + static void test_hexstr2bin (void) { @@ -4837,7 +4891,7 @@ test_nm_utils_is_power_of_two (void) if (i == -1) xyes = 0; else { - xyes = (1LL << i); + xyes = (((guint64) 1) << i); g_assert (xyes != 0); } @@ -4848,7 +4902,7 @@ again: * by randomly setting bits. */ numbits = g_rand_int_range (rand, 1, 65); while (xno != ~((guint64) 0) && numbits > 0) { - guint64 v = (1LL << g_rand_int_range (rand, 0, 64)); + guint64 v = (((guint64) 1) << g_rand_int_range (rand, 0, 64)); if ((xno | v) != xno) { xno |= v; @@ -5142,25 +5196,30 @@ static void test_nm_utils_enum (void) test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_YES, "yes"); test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_UNKNOWN, "unknown"); - test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_INVALID, NULL); + test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_INVALID, "4"); + test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_67, "67"); + test_nm_utils_enum_to_str_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_46, "64"); test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_NONE, ""); test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_BAZ, "baz"); test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_FOO | NM_TEST_GENERAL_META_FLAGS_BAR | NM_TEST_GENERAL_META_FLAGS_BAZ, "foo, bar, baz"); + test_nm_utils_enum_to_str_do (meta_flags, 0xFF, "foo, bar, baz, 0xf8"); + test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_0x8, "0x8"); + test_nm_utils_enum_to_str_do (meta_flags, NM_TEST_GENERAL_META_FLAGS_0x4, "0x10"); test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_RED, "red"); - test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_WHITE, ""); + test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_WHITE, "0x1"); test_nm_utils_enum_to_str_do (color_flags, NM_TEST_GENERAL_COLOR_FLAGS_RED | NM_TEST_GENERAL_COLOR_FLAGS_GREEN, "red, green"); test_nm_utils_enum_from_str_do (bool_enum, "", FALSE, 0, NULL); test_nm_utils_enum_from_str_do (bool_enum, " ", FALSE, 0, NULL); - test_nm_utils_enum_from_str_do (bool_enum, "invalid", FALSE, 0, NULL); + test_nm_utils_enum_from_str_do (bool_enum, "invalid", FALSE, 0, "invalid"); test_nm_utils_enum_from_str_do (bool_enum, "yes", TRUE, NM_TEST_GENERAL_BOOL_ENUM_YES, NULL); test_nm_utils_enum_from_str_do (bool_enum, "no", TRUE, NM_TEST_GENERAL_BOOL_ENUM_NO, NULL); - test_nm_utils_enum_from_str_do (bool_enum, "yes,no", FALSE, 0, NULL); + test_nm_utils_enum_from_str_do (bool_enum, "yes,no", FALSE, 0, "yes,no"); test_nm_utils_enum_from_str_do (meta_flags, "", TRUE, 0, NULL); test_nm_utils_enum_from_str_do (meta_flags, " ", TRUE, 0, NULL); @@ -5172,16 +5231,18 @@ static void test_nm_utils_enum (void) test_nm_utils_enum_from_str_do (meta_flags, "foo,,bar", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO | NM_TEST_GENERAL_META_FLAGS_BAR, NULL); test_nm_utils_enum_from_str_do (meta_flags, "foo,baz,quux,bar", FALSE, 0, "quux"); + test_nm_utils_enum_from_str_do (meta_flags, "foo,0x6", TRUE, NM_TEST_GENERAL_META_FLAGS_FOO | 0x6, NULL); + test_nm_utils_enum_from_str_do (meta_flags, "0x30,0x08,foo", TRUE, 0x39, NULL); test_nm_utils_enum_from_str_do (color_flags, "green", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_GREEN, NULL); test_nm_utils_enum_from_str_do (color_flags, "blue,red", TRUE, NM_TEST_GENERAL_COLOR_FLAGS_BLUE | NM_TEST_GENERAL_COLOR_FLAGS_RED, NULL); test_nm_utils_enum_from_str_do (color_flags, "blue,white", FALSE, 0, "white"); - test_nm_utils_enum_get_values_do (bool_enum, 0, G_MAXINT, "no,yes,maybe,unknown"); + test_nm_utils_enum_get_values_do (bool_enum, 0, G_MAXINT, "no,yes,maybe,unknown,67,64"); test_nm_utils_enum_get_values_do (bool_enum, NM_TEST_GENERAL_BOOL_ENUM_YES, NM_TEST_GENERAL_BOOL_ENUM_MAYBE, "yes,maybe"); - test_nm_utils_enum_get_values_do (meta_flags, 0, G_MAXINT, "none,foo,bar,baz"); + test_nm_utils_enum_get_values_do (meta_flags, 0, G_MAXINT, "none,foo,bar,baz,0x8,0x10"); test_nm_utils_enum_get_values_do (color_flags, 0, G_MAXINT, "blue,red,green"); } @@ -5405,6 +5466,97 @@ test_nm_in_strset (void) #undef _ASSERT } +static void +test_route_attributes_parse (void) +{ + GHashTable *ht; + GError *error = NULL; + GVariant *variant; + + ht = nm_utils_parse_variant_attributes ("mtu=1400 src=1.2.3.4 cwnd=14", + ' ', '=', FALSE, + nm_ip_route_get_variant_attribute_spec (), + &error); + g_assert_no_error (error); + g_assert (ht); + g_hash_table_unref (ht); + + ht = nm_utils_parse_variant_attributes ("mtu=1400 src=1.2.3.4 cwnd=14 \\", + ' ', '=', FALSE, + nm_ip_route_get_variant_attribute_spec (), + &error); + g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_FAILED); + g_assert (!ht); + g_clear_error (&error); + + ht = nm_utils_parse_variant_attributes ("mtu.1400 src.1\\.2\\.3\\.4 ", + ' ', '.', FALSE, + nm_ip_route_get_variant_attribute_spec (), + &error); + g_assert (ht); + g_assert_no_error (error); + variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_MTU); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)); + g_assert_cmpuint (g_variant_get_uint32 (variant), ==, 1400); + + variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_SRC); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "1.2.3.4"); + g_hash_table_unref (ht); + + ht = nm_utils_parse_variant_attributes ("from:fd01\\:\\:42\\/64/initrwnd:21", + '/', ':', FALSE, + nm_ip_route_get_variant_attribute_spec (), + &error); + g_assert (ht); + g_assert_no_error (error); + variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_INITRWND); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_UINT32)); + g_assert_cmpuint (g_variant_get_uint32 (variant), ==, 21); + + variant = g_hash_table_lookup (ht, NM_IP_ROUTE_ATTRIBUTE_FROM); + g_assert (variant); + g_assert (g_variant_is_of_type (variant, G_VARIANT_TYPE_STRING)); + g_assert_cmpstr (g_variant_get_string (variant, NULL), ==, "fd01::42/64"); + g_hash_table_unref (ht); +} + +static void +test_route_attributes_format (void) +{ + gs_unref_hashtable GHashTable *ht = NULL; + char *str; + + ht = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, (GDestroyNotify) g_variant_unref); + + str = nm_utils_format_variant_attributes (NULL, ' ', '='); + g_assert_cmpstr (str, ==, NULL); + + str = nm_utils_format_variant_attributes (ht, ' ', '='); + g_assert_cmpstr (str, ==, NULL); + + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_MTU, g_variant_new_uint32 (5000)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_INITRWND, g_variant_new_uint32 (20)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_LOCK_MTU, g_variant_new_boolean (TRUE)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_SRC, g_variant_new_string ("aaaa:bbbb::1")); + str = nm_utils_format_variant_attributes (ht, ' ', '='); + g_assert_cmpstr (str, ==, "initrwnd=20 lock-mtu=true mtu=5000 src=aaaa:bbbb::1"); + g_hash_table_remove_all (ht); + g_free (str); + + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_WINDOW, g_variant_new_uint32 (30000)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_INITCWND, g_variant_new_uint32 (21)); + g_hash_table_insert (ht, NM_IP_ROUTE_ATTRIBUTE_FROM, g_variant_new_string ("aaaa:bbbb:cccc:dddd::/64")); + str = nm_utils_format_variant_attributes (ht, '/', ':'); + g_assert_cmpstr (str, ==, "from:aaaa\\:bbbb\\:cccc\\:dddd\\:\\:\\/64/initcwnd:21/window:30000"); + g_hash_table_remove_all (ht); + g_free (str); +} + /*****************************************************************************/ static gboolean @@ -5460,6 +5612,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/test_setting_vpn_modify_during_foreach", test_setting_vpn_modify_during_foreach); g_test_add_func ("/core/general/test_setting_ip4_config_labels", test_setting_ip4_config_labels); g_test_add_func ("/core/general/test_setting_ip4_config_address_data", test_setting_ip4_config_address_data); + g_test_add_func ("/core/general/test_setting_ip_route_attributes", test_setting_ip_route_attributes); g_test_add_func ("/core/general/test_setting_gsm_apn_spaces", test_setting_gsm_apn_spaces); g_test_add_func ("/core/general/test_setting_gsm_apn_bad_chars", test_setting_gsm_apn_bad_chars); g_test_add_func ("/core/general/test_setting_gsm_apn_underscore", test_setting_gsm_apn_underscore); @@ -5551,6 +5704,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/test_setting_ip4_gateway", test_setting_ip4_gateway); g_test_add_func ("/core/general/test_setting_ip6_gateway", test_setting_ip6_gateway); g_test_add_func ("/core/general/test_setting_compare_default_strv", test_setting_compare_default_strv); + g_test_add_func ("/core/general/test_setting_user_data", test_setting_user_data); g_test_add_func ("/core/general/hexstr2bin", test_hexstr2bin); g_test_add_func ("/core/general/test_nm_utils_uuid_generate_from_string", test_nm_utils_uuid_generate_from_string); @@ -5569,6 +5723,8 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/_nm_utils_team_config_equal", test_nm_utils_team_config_equal); g_test_add_func ("/core/general/test_nm_utils_enum", test_nm_utils_enum); g_test_add_func ("/core/general/nm-set-out", test_nm_set_out); + g_test_add_func ("/core/general/route_attributes/parse", test_route_attributes_parse); + g_test_add_func ("/core/general/route_attributes/format", test_route_attributes_format); return g_test_run (); } diff --git a/libnm-core/tests/test-keyfile.c b/libnm-core/tests/test-keyfile.c index 9944eb5e..2dc929af 100644 --- a/libnm-core/tests/test-keyfile.c +++ b/libnm-core/tests/test-keyfile.c @@ -28,6 +28,7 @@ #include "nm-setting-wired.h" #include "nm-setting-8021x.h" #include "nm-setting-team.h" +#include "nm-setting-user.h" #include "nm-setting-proxy.h" #include "nm-utils/nm-test-utils.h" @@ -36,6 +37,69 @@ #define TEST_WIRED_TLS_CA_CERT TEST_CERT_DIR"/test-ca-cert.pem" #define TEST_WIRED_TLS_PRIVKEY TEST_CERT_DIR"/test-key-and-cert.pem" +/*****************************************************************************/ + +static void +do_test_encode_key_full (GKeyFile *kf, const char *name, const char *key, const char *key_decode_encode) +{ + gs_free char *to_free1 = NULL; + gs_free char *to_free2 = NULL; + const char *key2; + const char *name2; + + g_assert (key); + + if (name) { + key2 = nm_keyfile_key_encode (name, &to_free1); + g_assert (key2); + g_assert (NM_STRCHAR_ALL (key2, ch, (guchar) ch < 127)); + g_assert_cmpstr (key2, ==, key); + + /* try to add the encoded key to the keyfile. We expect + * no g_critical warning about invalid key. */ + g_key_file_set_value (kf, "group", key, "dummy"); + } + + name2 = nm_keyfile_key_decode (key, &to_free2); + if (name) + g_assert_cmpstr (name2, ==, name); + else { + key2 = nm_keyfile_key_encode (name2, &to_free1); + g_assert (key2); + g_assert (NM_STRCHAR_ALL (key2, ch, (guchar) ch < 127)); + if (key_decode_encode) + g_assert_cmpstr (key2, ==, key_decode_encode); + g_key_file_set_value (kf, "group", key2, "dummy"); + } +} + +#define do_test_encode_key_bijection(kf, name, key) do_test_encode_key_full (kf, ""name, ""key, NULL) +#define do_test_encode_key_identity(kf, name) do_test_encode_key_full (kf, ""name, ""name, NULL) +#define do_test_encode_key_decode_surjection(kf, key, key_decode_encode) do_test_encode_key_full (kf, NULL, ""key, ""key_decode_encode) + +static void +test_encode_key (void) +{ + gs_unref_keyfile GKeyFile *kf = g_key_file_new (); + + do_test_encode_key_identity (kf, "a"); + do_test_encode_key_bijection (kf, "", "\\00"); + do_test_encode_key_bijection (kf, " ", "\\20"); + do_test_encode_key_bijection (kf, "\\ ", "\\\\20"); + do_test_encode_key_identity (kf, "\\0"); + do_test_encode_key_identity (kf, "\\a"); + do_test_encode_key_identity (kf, "\\0g"); + do_test_encode_key_bijection (kf, "\\0f", "\\5C0f"); + do_test_encode_key_bijection (kf, "\\0f ", "\\5C0f\\20"); + do_test_encode_key_bijection (kf, " \\0f ", "\\20\\5C0f\\20"); + do_test_encode_key_bijection (kf, "\xF5", "\\F5"); + do_test_encode_key_bijection (kf, "\x7F", "\\7F"); + do_test_encode_key_bijection (kf, "\x1f", "\\1F"); + do_test_encode_key_bijection (kf, " ", "\\20\\20"); + do_test_encode_key_bijection (kf, " ", "\\20 \\20"); + do_test_encode_key_decode_surjection (kf, "f\\20c", "f c"); + do_test_encode_key_decode_surjection (kf, "\\20\\20\\20", "\\20 \\20"); +} /*****************************************************************************/ @@ -583,16 +647,85 @@ test_team_conf_read_invalid (void) /*****************************************************************************/ +static void +test_user_1 (void) +{ + gs_unref_keyfile GKeyFile *keyfile = NULL; + gs_unref_object NMConnection *con = NULL; + NMSettingUser *s_user; + + con = nmtst_create_connection_from_keyfile ( + "[connection]\n" + "id=t\n" + "type=ethernet\n" + "\n" + "[user]\n" + "my-value.x=value1\n" + "", + "/test_user_1/invalid", NULL); + g_assert (con); + s_user = NM_SETTING_USER (nm_connection_get_setting (con, NM_TYPE_SETTING_USER)); + g_assert (s_user); + g_assert_cmpstr (nm_setting_user_get_data (s_user, "my-value.x"), ==, "value1"); + + CLEAR (&con, &keyfile); + + con = nmtst_create_minimal_connection ("user-2", "8b85fb8d-3070-48ba-93d9-53eee231d9a2", NM_SETTING_WIRED_SETTING_NAME, NULL); + s_user = NM_SETTING_USER (nm_setting_user_new ()); + +#define _USER_SET_DATA(s_user, key, val) \ + G_STMT_START { \ + GError *_error = NULL; \ + gboolean _success; \ + \ + _success = nm_setting_user_set_data ((s_user), (key), (val), &_error); \ + nmtst_assert_success (_success, _error); \ + } G_STMT_END + +#define _USER_SET_DATA_X(s_user, key) \ + _USER_SET_DATA (s_user, key, "val="key"") + + _USER_SET_DATA (s_user, "my.val1", ""); + _USER_SET_DATA_X (s_user, "my.val2"); + _USER_SET_DATA_X (s_user, "my.v__al3"); + _USER_SET_DATA_X (s_user, "my._v"); + _USER_SET_DATA_X (s_user, "my.v+"); + _USER_SET_DATA_X (s_user, "my.Av"); + _USER_SET_DATA_X (s_user, "MY.AV"); + _USER_SET_DATA_X (s_user, "MY.8V"); + _USER_SET_DATA_X (s_user, "MY.8-V"); + _USER_SET_DATA_X (s_user, "MY.8_V"); + _USER_SET_DATA_X (s_user, "MY.8+V"); + _USER_SET_DATA_X (s_user, "MY.8/V"); + _USER_SET_DATA_X (s_user, "MY.8=V"); + _USER_SET_DATA_X (s_user, "MY.-"); + _USER_SET_DATA_X (s_user, "MY._"); + _USER_SET_DATA_X (s_user, "MY.+"); + _USER_SET_DATA_X (s_user, "MY./"); + _USER_SET_DATA_X (s_user, "MY.="); + _USER_SET_DATA_X (s_user, "my.keys.1"); + _USER_SET_DATA_X (s_user, "my.other.KEY.42"); + + nm_connection_add_setting (con, NM_SETTING (s_user)); + nmtst_connection_normalize (con); + + _keyfile_convert (&con, &keyfile, NULL, NULL, NULL, NULL, NULL, NULL, FALSE); +} + +/*****************************************************************************/ + NMTST_DEFINE (); int main (int argc, char **argv) { nmtst_init (&argc, &argv, TRUE); + g_test_add_func ("/core/keyfile/encode_key", test_encode_key); g_test_add_func ("/core/keyfile/test_8021x_cert", test_8021x_cert); g_test_add_func ("/core/keyfile/test_8021x_cert_read", test_8021x_cert_read); g_test_add_func ("/core/keyfile/test_team_conf_read/valid", test_team_conf_read_valid); g_test_add_func ("/core/keyfile/test_team_conf_read/invalid", test_team_conf_read_invalid); + g_test_add_func ("/core/keyfile/test_user/1", test_user_1); return g_test_run (); } |