From 80ec1decc49c72efec2a8b87c06245c92c0ab807 Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Thu, 11 Feb 2021 18:11:46 +0100 Subject: New upstream version 1.29.90 --- libnm-core/meson.build | 143 +- libnm-core/nm-connection-private.h | 10 +- libnm-core/nm-connection.c | 8 +- libnm-core/nm-connection.h | 4 +- libnm-core/nm-core-enum-types.c.template | 90 - libnm-core/nm-core-enum-types.h.template | 21 - libnm-core/nm-core-internal.h | 45 +- libnm-core/nm-core-types-internal.h | 2 +- libnm-core/nm-core-types.h | 5 +- libnm-core/nm-crypto-gnutls.c | 4 +- libnm-core/nm-crypto-impl.h | 2 +- libnm-core/nm-crypto-nss.c | 4 +- libnm-core/nm-crypto.c | 4 +- libnm-core/nm-crypto.h | 2 +- libnm-core/nm-dbus-interface.h | 51 +- libnm-core/nm-dbus-types.xml | 23 +- libnm-core/nm-dbus-utils.c | 4 +- libnm-core/nm-default-libnm-core.h | 22 + libnm-core/nm-errors.c | 5 +- libnm-core/nm-errors.h | 4 +- libnm-core/nm-keyfile-internal.h | 124 + libnm-core/nm-keyfile-utils.c | 684 +++ libnm-core/nm-keyfile-utils.h | 95 + libnm-core/nm-keyfile.c | 4443 ++++++++++++++++++++ libnm-core/nm-keyfile.h | 165 + libnm-core/nm-keyfile/nm-keyfile-internal.h | 213 - libnm-core/nm-keyfile/nm-keyfile-utils.c | 682 --- libnm-core/nm-keyfile/nm-keyfile-utils.h | 95 - libnm-core/nm-keyfile/nm-keyfile.c | 4272 ------------------- libnm-core/nm-libnm-core-aux/nm-dispatcher-api.h | 2 +- libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c | 4 +- libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.h | 2 +- libnm-core/nm-libnm-core-intern/nm-auth-subject.c | 44 +- libnm-core/nm-libnm-core-intern/nm-auth-subject.h | 2 +- libnm-core/nm-libnm-core-intern/nm-common-macros.h | 2 +- libnm-core/nm-libnm-core-intern/nm-ethtool-utils.c | 276 -- libnm-core/nm-libnm-core-intern/nm-ethtool-utils.h | 164 - .../nm-libnm-core-intern/nm-libnm-core-utils.c | 62 +- .../nm-libnm-core-intern/nm-libnm-core-utils.h | 12 +- libnm-core/nm-meta-setting-base-impl.c | 641 +++ libnm-core/nm-meta-setting-base-impl.h | 187 + libnm-core/nm-meta-setting-base.h | 10 + libnm-core/nm-property-compare.c | 4 +- libnm-core/nm-property-compare.h | 2 +- libnm-core/nm-setting-6lowpan.c | 6 +- libnm-core/nm-setting-6lowpan.h | 2 +- libnm-core/nm-setting-8021x.c | 33 +- libnm-core/nm-setting-8021x.h | 2 +- libnm-core/nm-setting-adsl.c | 6 +- libnm-core/nm-setting-adsl.h | 2 +- libnm-core/nm-setting-bluetooth.c | 6 +- libnm-core/nm-setting-bluetooth.h | 2 +- libnm-core/nm-setting-bond.c | 64 +- libnm-core/nm-setting-bond.h | 2 +- libnm-core/nm-setting-bridge-port.c | 6 +- libnm-core/nm-setting-bridge-port.h | 2 +- libnm-core/nm-setting-bridge.c | 7 +- libnm-core/nm-setting-bridge.h | 2 +- libnm-core/nm-setting-cdma.c | 6 +- libnm-core/nm-setting-cdma.h | 2 +- libnm-core/nm-setting-connection.c | 166 +- libnm-core/nm-setting-connection.h | 2 +- libnm-core/nm-setting-dcb.c | 6 +- libnm-core/nm-setting-dcb.h | 2 +- libnm-core/nm-setting-dummy.c | 6 +- libnm-core/nm-setting-dummy.h | 2 +- libnm-core/nm-setting-ethtool.c | 14 +- libnm-core/nm-setting-ethtool.h | 87 +- libnm-core/nm-setting-generic.c | 6 +- libnm-core/nm-setting-generic.h | 2 +- libnm-core/nm-setting-gsm.c | 6 +- libnm-core/nm-setting-gsm.h | 2 +- libnm-core/nm-setting-hostname.c | 339 ++ libnm-core/nm-setting-hostname.h | 53 + libnm-core/nm-setting-infiniband.c | 7 +- libnm-core/nm-setting-infiniband.h | 2 +- libnm-core/nm-setting-ip-config.c | 8 +- libnm-core/nm-setting-ip-config.h | 2 +- libnm-core/nm-setting-ip-tunnel.c | 6 +- libnm-core/nm-setting-ip-tunnel.h | 2 +- libnm-core/nm-setting-ip4-config.c | 14 +- libnm-core/nm-setting-ip4-config.h | 2 +- libnm-core/nm-setting-ip6-config.c | 6 +- libnm-core/nm-setting-ip6-config.h | 2 +- libnm-core/nm-setting-macsec.c | 6 +- libnm-core/nm-setting-macsec.h | 2 +- libnm-core/nm-setting-macvlan.c | 6 +- libnm-core/nm-setting-macvlan.h | 2 +- libnm-core/nm-setting-match.c | 6 +- libnm-core/nm-setting-match.h | 2 +- libnm-core/nm-setting-olpc-mesh.c | 8 +- libnm-core/nm-setting-olpc-mesh.h | 2 +- libnm-core/nm-setting-ovs-bridge.c | 6 +- libnm-core/nm-setting-ovs-bridge.h | 2 +- libnm-core/nm-setting-ovs-dpdk.c | 6 +- libnm-core/nm-setting-ovs-dpdk.h | 2 +- libnm-core/nm-setting-ovs-external-ids.c | 551 +++ libnm-core/nm-setting-ovs-external-ids.h | 68 + libnm-core/nm-setting-ovs-interface.c | 6 +- libnm-core/nm-setting-ovs-interface.h | 2 +- libnm-core/nm-setting-ovs-patch.c | 6 +- libnm-core/nm-setting-ovs-patch.h | 2 +- libnm-core/nm-setting-ovs-port.c | 6 +- libnm-core/nm-setting-ovs-port.h | 2 +- libnm-core/nm-setting-ppp.c | 6 +- libnm-core/nm-setting-ppp.h | 2 +- libnm-core/nm-setting-pppoe.c | 6 +- libnm-core/nm-setting-pppoe.h | 2 +- libnm-core/nm-setting-private.h | 3 +- libnm-core/nm-setting-proxy.c | 6 +- libnm-core/nm-setting-proxy.h | 2 +- libnm-core/nm-setting-serial.c | 6 +- libnm-core/nm-setting-serial.h | 2 +- libnm-core/nm-setting-sriov.c | 6 +- libnm-core/nm-setting-sriov.h | 2 +- libnm-core/nm-setting-tc-config.c | 6 +- libnm-core/nm-setting-tc-config.h | 2 +- libnm-core/nm-setting-team-port.c | 6 +- libnm-core/nm-setting-team-port.h | 2 +- libnm-core/nm-setting-team.c | 10 +- libnm-core/nm-setting-team.h | 2 +- libnm-core/nm-setting-tun.c | 6 +- libnm-core/nm-setting-tun.h | 2 +- libnm-core/nm-setting-user.c | 18 +- libnm-core/nm-setting-user.h | 2 +- libnm-core/nm-setting-veth.c | 194 + libnm-core/nm-setting-veth.h | 41 + libnm-core/nm-setting-vlan.c | 6 +- libnm-core/nm-setting-vlan.h | 3 +- libnm-core/nm-setting-vpn.c | 6 +- libnm-core/nm-setting-vpn.h | 2 +- libnm-core/nm-setting-vrf.c | 6 +- libnm-core/nm-setting-vrf.h | 2 +- libnm-core/nm-setting-vxlan.c | 76 +- libnm-core/nm-setting-vxlan.h | 2 +- libnm-core/nm-setting-wifi-p2p.c | 4 +- libnm-core/nm-setting-wifi-p2p.h | 2 +- libnm-core/nm-setting-wimax.c | 6 +- libnm-core/nm-setting-wimax.h | 2 +- libnm-core/nm-setting-wired.c | 6 +- libnm-core/nm-setting-wired.h | 2 +- libnm-core/nm-setting-wireguard.c | 4 +- libnm-core/nm-setting-wireguard.h | 2 +- libnm-core/nm-setting-wireless-security.c | 52 +- libnm-core/nm-setting-wireless-security.h | 2 +- libnm-core/nm-setting-wireless.c | 6 +- libnm-core/nm-setting-wireless.h | 2 +- libnm-core/nm-setting-wpan.c | 6 +- libnm-core/nm-setting-wpan.h | 2 +- libnm-core/nm-setting.c | 44 +- libnm-core/nm-setting.h | 2 +- libnm-core/nm-simple-connection.c | 6 +- libnm-core/nm-simple-connection.h | 2 +- libnm-core/nm-team-utils.c | 25 +- libnm-core/nm-team-utils.h | 2 +- libnm-core/nm-utils-private.h | 2 +- libnm-core/nm-utils.c | 180 +- libnm-core/nm-utils.h | 15 +- libnm-core/nm-version-macros.h | 91 + libnm-core/nm-version-macros.h.in | 91 + libnm-core/nm-version.h | 16 +- libnm-core/nm-vpn-dbus-interface.h | 34 +- libnm-core/nm-vpn-dbus-types.xml | 24 +- libnm-core/nm-vpn-editor-plugin.c | 4 +- libnm-core/nm-vpn-editor-plugin.h | 2 +- libnm-core/nm-vpn-plugin-info.c | 4 +- libnm-core/nm-vpn-plugin-info.h | 2 +- libnm-core/tests/meson.build | 40 +- libnm-core/tests/test-compare.c | 4 +- libnm-core/tests/test-crypto.c | 4 +- libnm-core/tests/test-general-enums.h | 2 +- libnm-core/tests/test-general.c | 142 +- libnm-core/tests/test-keyfile.c | 8 +- libnm-core/tests/test-secrets.c | 4 +- libnm-core/tests/test-setting.c | 7 +- libnm-core/tests/test-settings-defaults.c | 4 +- 176 files changed, 8832 insertions(+), 6691 deletions(-) delete mode 100644 libnm-core/nm-core-enum-types.c.template delete mode 100644 libnm-core/nm-core-enum-types.h.template create mode 100644 libnm-core/nm-default-libnm-core.h create mode 100644 libnm-core/nm-keyfile-internal.h create mode 100644 libnm-core/nm-keyfile-utils.c create mode 100644 libnm-core/nm-keyfile-utils.h create mode 100644 libnm-core/nm-keyfile.c create mode 100644 libnm-core/nm-keyfile.h delete mode 100644 libnm-core/nm-keyfile/nm-keyfile-internal.h delete mode 100644 libnm-core/nm-keyfile/nm-keyfile-utils.c delete mode 100644 libnm-core/nm-keyfile/nm-keyfile-utils.h delete mode 100644 libnm-core/nm-keyfile/nm-keyfile.c delete mode 100644 libnm-core/nm-libnm-core-intern/nm-ethtool-utils.c delete mode 100644 libnm-core/nm-libnm-core-intern/nm-ethtool-utils.h create mode 100644 libnm-core/nm-meta-setting-base-impl.c create mode 100644 libnm-core/nm-meta-setting-base-impl.h create mode 100644 libnm-core/nm-meta-setting-base.h create mode 100644 libnm-core/nm-setting-hostname.c create mode 100644 libnm-core/nm-setting-hostname.h create mode 100644 libnm-core/nm-setting-ovs-external-ids.c create mode 100644 libnm-core/nm-setting-ovs-external-ids.h create mode 100644 libnm-core/nm-setting-veth.c create mode 100644 libnm-core/nm-setting-veth.h create mode 100644 libnm-core/nm-version-macros.h create mode 100644 libnm-core/nm-version-macros.h.in (limited to 'libnm-core') diff --git a/libnm-core/meson.build b/libnm-core/meson.build index da74fb04..ec9fb8ce 100644 --- a/libnm-core/meson.build +++ b/libnm-core/meson.build @@ -1,23 +1,25 @@ -# SPDX-License-Identifier: LGPL-2.1+ +# SPDX-License-Identifier: LGPL-2.1-or-later libnm_core_inc = include_directories('.') +nm_version_macro_header = configure_file( + input: 'nm-version-macros.h.in', + output: '@BASENAME@', + configuration: data_conf, +) + libnm_core_nm_default_dep = declare_dependency( sources: nm_version_macro_header, include_directories: libnm_core_inc, dependencies: glib_nm_default_dep, ) -common_c_flags = [ - '-DG_LOG_DOMAIN="@0@"'.format(libnm_name), - '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_LIBNM_CORE', -] - libnm_core_headers = files( 'nm-connection.h', 'nm-core-types.h', 'nm-dbus-interface.h', 'nm-errors.h', + 'nm-keyfile.h', 'nm-setting-6lowpan.h', 'nm-setting-8021x.h', 'nm-setting-adsl.h', @@ -32,6 +34,7 @@ libnm_core_headers = files( 'nm-setting-ethtool.h', 'nm-setting-generic.h', 'nm-setting-gsm.h', + 'nm-setting-hostname.h', 'nm-setting-infiniband.h', 'nm-setting-ip-config.h', 'nm-setting-ip-tunnel.h', @@ -42,8 +45,9 @@ libnm_core_headers = files( 'nm-setting-match.h', 'nm-setting-olpc-mesh.h', 'nm-setting-ovs-bridge.h', - 'nm-setting-ovs-interface.h', 'nm-setting-ovs-dpdk.h', + 'nm-setting-ovs-external-ids.h', + 'nm-setting-ovs-interface.h', 'nm-setting-ovs-patch.h', 'nm-setting-ovs-port.h', 'nm-setting-ppp.h', @@ -56,6 +60,7 @@ libnm_core_headers = files( 'nm-setting-team.h', 'nm-setting-tun.h', 'nm-setting-user.h', + 'nm-setting-veth.h', 'nm-setting-vlan.h', 'nm-setting-vpn.h', 'nm-setting-vrf.h', @@ -76,13 +81,11 @@ libnm_core_headers = files( 'nm-vpn-plugin-info.h', ) -enum_types = 'nm-core-enum-types' - libnm_core_enum_sources = gnome.mkenums_simple( - enum_types, + 'nm-core-enum-types', sources: libnm_core_headers + [nm_version_macro_header], identifier_prefix: nm_id_prefix, - body_prefix: '#include "nm-default.h"', + body_prefix: '#include "libnm-core/nm-default-libnm-core.h"', install_header: true, install_dir: libnm_pkgincludedir, ) @@ -91,30 +94,37 @@ libnm_libnm_core_intern = static_library( 'nm-libnm-core-intern', sources: files( 'nm-libnm-core-intern/nm-auth-subject.c', - 'nm-libnm-core-intern/nm-ethtool-utils.c', 'nm-libnm-core-intern/nm-libnm-core-utils.c', ) + [libnm_core_enum_sources[1]], - dependencies: libnm_core_nm_default_dep, - c_args: common_c_flags, + dependencies: [ + libnm_core_nm_default_dep, + libnm_base_dep, + ], + c_args: [ + '-DG_LOG_DOMAIN="libnm"', + ], ) libnm_libnm_core_intern_dep = declare_dependency( sources: [libnm_core_enum_sources[1], nm_version_macro_header], include_directories: [libnm_core_inc, shared_inc], - dependencies: libnm_utils_base_dep, + dependencies: [ + libnm_glib_aux_dep, + libnm_base_dep, + ], link_with: libnm_libnm_core_intern, ) -deps = [ - crypto_dep, - libnm_utils_base_dep, -] - libnm_crypto = static_library( 'nm-crypto', sources: 'nm-crypto-@0@.c'.format(crypto), - dependencies: deps, - c_args: common_c_flags, + dependencies: [ + crypto_dep, + libnm_glib_aux_dep, + ], + c_args: [ + '-DG_LOG_DOMAIN="libnm"', + ], ) libnm_core_settings_sources = files( @@ -132,6 +142,7 @@ libnm_core_settings_sources = files( 'nm-setting-ethtool.c', 'nm-setting-generic.c', 'nm-setting-gsm.c', + 'nm-setting-hostname.c', 'nm-setting-infiniband.c', 'nm-setting-ip-config.c', 'nm-setting-ip-tunnel.c', @@ -142,8 +153,9 @@ libnm_core_settings_sources = files( 'nm-setting-match.c', 'nm-setting-olpc-mesh.c', 'nm-setting-ovs-bridge.c', - 'nm-setting-ovs-interface.c', 'nm-setting-ovs-dpdk.c', + 'nm-setting-ovs-external-ids.c', + 'nm-setting-ovs-interface.c', 'nm-setting-ovs-patch.c', 'nm-setting-ovs-port.c', 'nm-setting-ppp.c', @@ -156,6 +168,7 @@ libnm_core_settings_sources = files( 'nm-setting-team.c', 'nm-setting-tun.c', 'nm-setting-user.c', + 'nm-setting-veth.c', 'nm-setting-vlan.c', 'nm-setting-vpn.c', 'nm-setting-vrf.c', @@ -174,6 +187,9 @@ libnm_core_sources = libnm_core_settings_sources + files( 'nm-crypto.c', 'nm-dbus-utils.c', 'nm-errors.c', + 'nm-keyfile-utils.c', + 'nm-keyfile.c', + 'nm-meta-setting-base-impl.c', 'nm-property-compare.c', 'nm-setting.c', 'nm-simple-connection.c', @@ -183,27 +199,23 @@ libnm_core_sources = libnm_core_settings_sources + files( 'nm-vpn-plugin-info.c', ) -deps = [ - dl_dep, - libnm_systemd_shared_dep, - libnm_utils_base_dep, - uuid_dep, -] - -links = [ - libnm_crypto, - libnm_libnm_core_intern, -] - -libnm_core_c_args = common_c_flags - libnm_core = static_library( 'nm-core', - sources: libnm_core_sources + libnm_core_enum_sources + nm_meta_setting_source + [nm_version_macro_header], + sources: libnm_core_sources + libnm_core_enum_sources + [nm_version_macro_header], include_directories: top_inc, - dependencies: deps, - c_args: libnm_core_c_args, - link_with: links, + dependencies: [ + dl_dep, + libnm_systemd_shared_dep, + libnm_glib_aux_dep, + uuid_dep, + ], + c_args: [ + '-DG_LOG_DOMAIN="libnm"', + ], + link_with: [ + libnm_crypto, + libnm_libnm_core_intern, + ], ) libnm_core_dep = declare_dependency( @@ -213,53 +225,30 @@ libnm_core_dep = declare_dependency( link_with: libnm_core, ) -c_flags = [ - '-DG_LOG_DOMAIN="@0@"'.format(libnm_name), - '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_WITH_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB)', -] - libnm_libnm_core_aux = static_library( 'nm-libnm-core-aux', sources: files( 'nm-libnm-core-aux/nm-libnm-core-aux.c', ) + [libnm_core_enum_sources[1]], - dependencies: libnm_utils_base_dep, - c_args: c_flags, - link_with: libnm_libnm_core_intern, -) - -libnm_libnm_core_aux_dep = declare_dependency( - sources: [libnm_core_enum_sources[1], nm_version_macro_header], - include_directories: [libnm_core_inc, shared_inc], - dependencies: glib_dep, - link_with: libnm_libnm_core_aux, -) - -libnm_keyfile = static_library( - 'nm-keyfile', - sources: files( - 'nm-keyfile/nm-keyfile-utils.c', - 'nm-keyfile/nm-keyfile.c', - ) + [libnm_core_enum_sources[1]], - dependencies: libnm_utils_base_dep, + dependencies: libnm_glib_aux_dep, c_args: [ - '-DG_LOG_DOMAIN="@0@"'.format(libnm_name), - '-DNETWORKMANAGER_COMPILATION=(NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB|NM_NETWORKMANAGER_COMPILATION_WITH_GLIB_I18N_LIB)', + '-DG_LOG_DOMAIN="libnm"', + ], + link_with: [ + libnm_libnm_core_intern, + libnm_base, ], - link_with: libnm_libnm_core_intern, ) -libnm_keyfile_dep = declare_dependency( +libnm_libnm_core_aux_dep = declare_dependency( sources: [libnm_core_enum_sources[1], nm_version_macro_header], include_directories: [libnm_core_inc, shared_inc], dependencies: glib_dep, - link_with: libnm_keyfile, + link_with: libnm_libnm_core_aux, ) -enums_to_docbook = join_paths(source_root, 'tools', 'enums-to-docbook.pl') - docbooks = [ - ['nm-dbus-types', 'nm-dbus-interface.h', 'NetworkManager D-Bus API Types'], + ['nm-dbus-types', 'nm-dbus-interface.h', 'NetworkManager D-Bus API Types'], ['nm-vpn-dbus-types', 'nm-vpn-dbus-interface.h', 'VPN Plugin D-Bus API Types'], ] @@ -271,7 +260,13 @@ foreach docbook: docbooks input: docbook[1], output: output, capture: true, - command: [perl, enums_to_docbook, docbook[0], docbook[2], '@INPUT@'], + command: [ + perl, + join_paths(source_root, 'tools', 'enums-to-docbook.pl'), + docbook[0], + docbook[2], + '@INPUT@', + ], # FIXME: gtkdoc does not depend directly on this. # https://github.com/mesonbuild/meson/pull/2806 build_by_default: true, diff --git a/libnm-core/nm-connection-private.h b/libnm-core/nm-connection-private.h index 4c05c36b..532b1763 100644 --- a/libnm-core/nm-connection-private.h +++ b/libnm-core/nm-connection-private.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2014 Red Hat, Inc. */ @@ -17,6 +17,14 @@ NMSetting *_nm_connection_find_base_type_setting(NMConnection *connection); const char *_nm_connection_detect_slave_type(NMConnection *connection, NMSetting **out_s_port); +gboolean _nm_connection_detect_slave_type_full(NMSettingConnection *s_con, + NMConnection * connection, + const char ** out_slave_type, + const char ** out_normerr_slave_setting_type, + const char ** out_normerr_missing_slave_type, + const char **out_normerr_missing_slave_type_port, + GError ** error); + const char *_nm_connection_detect_bluetooth_type(NMConnection *self); gboolean _nm_connection_verify_required_interface_name(NMConnection *connection, GError **error); diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 10bfe7b8..b39c41d7 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2018 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-connection.h" @@ -1065,7 +1065,8 @@ _normalize_bond_mode(NMConnection *self) if (mode_int != -1) { const char *mode_new = nm_utils_bond_mode_int_to_string(mode_int); - if (g_strcmp0(mode_new, mode) != 0) { + + if (!nm_streq0(mode_new, mode)) { nm_setting_bond_add_option(s_bond, NM_SETTING_BOND_OPTION_MODE, mode_new); return TRUE; } @@ -2641,6 +2642,7 @@ nm_connection_is_virtual(NMConnection *connection) NM_SETTING_OVS_PORT_SETTING_NAME, NM_SETTING_TEAM_SETTING_NAME, NM_SETTING_TUN_SETTING_NAME, + NM_SETTING_VETH_SETTING_NAME, NM_SETTING_VLAN_SETTING_NAME, NM_SETTING_VRF_SETTING_NAME, NM_SETTING_VXLAN_SETTING_NAME, diff --git a/libnm-core/nm-connection.h b/libnm-core/nm-connection.h index 8b8375d5..19034e79 100644 --- a/libnm-core/nm-connection.h +++ b/libnm-core/nm-connection.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2018 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. @@ -94,7 +94,7 @@ NMSetting *nm_connection_get_setting_by_name(NMConnection *connection, const cha * @NM_CONNECTION_SERIALIZE_NO_SECRETS: do not include secrets * @NM_CONNECTION_SERIALIZE_ONLY_SECRETS: only serialize secrets * @NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED: if set, only secrets that - * are agent owned will be serialized. Since: 1.20 + * are agent owned will be serialized. Since: 1.20. * * These flags determine which properties are serialized when calling when * calling nm_connection_to_dbus(). diff --git a/libnm-core/nm-core-enum-types.c.template b/libnm-core/nm-core-enum-types.c.template deleted file mode 100644 index b6cb38ee..00000000 --- a/libnm-core/nm-core-enum-types.c.template +++ /dev/null @@ -1,90 +0,0 @@ -/*** BEGIN file-header ***/ -#include "config.h" - -#include "nm-core-enum-types.h" -#include "nm-default.h" - -#include "nm-connection.h" -#include "nm-core-types.h" -#include "nm-dbus-interface.h" -#include "nm-errors.h" -#include "nm-setting-8021x.h" -#include "nm-setting-adsl.h" -#include "nm-setting-bluetooth.h" -#include "nm-setting-bond.h" -#include "nm-setting-bridge-port.h" -#include "nm-setting-bridge.h" -#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" -#include "nm-setting-ip-config.h" -#include "nm-setting-ip-tunnel.h" -#include "nm-setting-ip4-config.h" -#include "nm-setting-ip6-config.h" -#include "nm-setting-macsec.h" -#include "nm-setting-macvlan.h" -#include "nm-setting-olpc-mesh.h" -#include "nm-setting-ovs-bridge.h" -#include "nm-setting-ovs-interface.h" -#include "nm-setting-ovs-dpdk.h" -#include "nm-setting-ovs-patch.h" -#include "nm-setting-ovs-port.h" -#include "nm-setting-ppp.h" -#include "nm-setting-pppoe.h" -#include "nm-setting-proxy.h" -#include "nm-setting-serial.h" -#include "nm-setting-team-port.h" -#include "nm-setting-team.h" -#include "nm-setting-tun.h" -#include "nm-setting-user.h" -#include "nm-setting-vlan.h" -#include "nm-setting-vpn.h" -#include "nm-setting-vxlan.h" -#include "nm-setting-wifi-p2p.h" -#include "nm-setting-wimax.h" -#include "nm-setting-wired.h" -#include "nm-setting-wireguard.h" -#include "nm-setting-wireless-security.h" -#include "nm-setting-wireless.h" -#include "nm-setting-wpan.h" -#include "nm-setting.h" -#include "nm-simple-connection.h" -#include "nm-utils.h" -#include "nm-version-macros.h" -#include "nm-version.h" -#include "nm-vpn-dbus-interface.h" -#include "nm-vpn-editor-plugin.h" -#include "nm-vpn-plugin-info.h" -/*** END file-header ***/ - -/*** BEGIN value-header ***/ -GType -@enum_name@_get_type (void) -{ - static volatile gsize g_define_type_id__volatile = 0; - - if (g_once_init_enter (&g_define_type_id__volatile)) - { - static const G@Type@Value values[] = { -/*** END value-header ***/ - -/*** BEGIN value-production ***/ - { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, -/*** END value-production ***/ - -/*** BEGIN value-tail ***/ - { 0, NULL, NULL } - }; - GType g_define_type_id = - g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); - g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); - } - - return g_define_type_id__volatile; -} - -/*** END value-tail ***/ diff --git a/libnm-core/nm-core-enum-types.h.template b/libnm-core/nm-core-enum-types.h.template deleted file mode 100644 index 0f1be1e1..00000000 --- a/libnm-core/nm-core-enum-types.h.template +++ /dev/null @@ -1,21 +0,0 @@ -/*** BEGIN file-header ***/ -#ifndef __NM_CORE_ENUM_TYPES_H__ -#define __NM_CORE_ENUM_TYPES_H__ - -#include - -G_BEGIN_DECLS - -/*** END file-header ***/ - -/*** BEGIN enumeration-production ***/ -GType @enum_name@_get_type (void) G_GNUC_CONST; -#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) - -/*** END enumeration-production ***/ - -/*** BEGIN file-tail ***/ -G_END_DECLS - -#endif /* __NM_CORE_ENUM_TYPES_H__ */ -/*** END file-tail ***/ diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index f296a77f..d9374fe5 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2014 - 2018 Red Hat, Inc. */ @@ -20,10 +20,11 @@ #error Cannot use this header. #endif +#include "nm-base/nm-base.h" #include "nm-connection.h" #include "nm-core-enum-types.h" #include "nm-core-types-internal.h" -#include "nm-meta-setting.h" +#include "nm-meta-setting-base.h" #include "nm-setting-6lowpan.h" #include "nm-setting-8021x.h" #include "nm-setting-adsl.h" @@ -37,6 +38,7 @@ #include "nm-setting-dummy.h" #include "nm-setting-generic.h" #include "nm-setting-gsm.h" +#include "nm-setting-hostname.h" #include "nm-setting-infiniband.h" #include "nm-setting-ip-tunnel.h" #include "nm-setting-ip4-config.h" @@ -59,6 +61,7 @@ #include "nm-setting-team-port.h" #include "nm-setting-team.h" #include "nm-setting-tun.h" +#include "nm-setting-veth.h" #include "nm-setting-vlan.h" #include "nm-setting-vpn.h" #include "nm-setting-vrf.h" @@ -213,6 +216,38 @@ nm_bluetooth_capability_to_string(NMBluetoothCapabilities capabilities, char *bu /*****************************************************************************/ +static inline _NMSettingWiredWakeOnLan +_NM_SETTING_WIRED_WAKE_ON_LAN_CAST(NMSettingWiredWakeOnLan v) +{ + /* _NMSettingWiredWakeOnLan and NMSettingWiredWakeOnLan enums are really + * the same. + * + * The former is used by nm-platform (which should have no libnm-core dependency), + * the latter is used by libnm-core. A unit test ensures they are exactly the same, + * so we can just cast them. */ + return (_NMSettingWiredWakeOnLan) v; +} + +/*****************************************************************************/ + +static inline NMTernary +NM_TERNARY_FROM_OPTION_BOOL(NMOptionBool v) +{ + nm_assert(NM_IN_SET(v, NM_OPTION_BOOL_DEFAULT, NM_OPTION_BOOL_TRUE, NM_OPTION_BOOL_FALSE)); + + return (NMTernary) v; +} + +static inline NMOptionBool +NM_TERNARY_TO_OPTION_BOOL(NMTernary v) +{ + nm_assert(NM_IN_SET(v, NM_TERNARY_DEFAULT, NM_TERNARY_TRUE, NM_TERNARY_FALSE)); + + return (NMOptionBool) v; +} + +/*****************************************************************************/ + typedef enum { /*< skip >*/ NM_SETTING_PARSE_FLAGS_NONE = 0, NM_SETTING_PARSE_FLAGS_STRICT = 1LL << 0, @@ -325,7 +360,7 @@ gboolean _nm_setting_option_clear(NMSetting *setting, const char *optname); guint nm_setting_ethtool_init_features( NMSettingEthtool *setting, - NMTernary * requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */); + NMOptionBool * requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */); /*****************************************************************************/ @@ -476,6 +511,10 @@ GSList *_nm_vpn_plugin_info_list_load_dir(const char * dirname, /*****************************************************************************/ +GHashTable *_nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *self); + +/*****************************************************************************/ + typedef struct { const char *name; gboolean numeric; diff --git a/libnm-core/nm-core-types-internal.h b/libnm-core/nm-core-types-internal.h index cc9e16a1..346458d3 100644 --- a/libnm-core/nm-core-types-internal.h +++ b/libnm-core/nm-core-types-internal.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ diff --git a/libnm-core/nm-core-types.h b/libnm-core/nm-core-types.h index 80466e35..bf0c2a99 100644 --- a/libnm-core/nm-core-types.h +++ b/libnm-core/nm-core-types.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2014 - 2018 Red Hat, Inc. */ @@ -28,6 +28,7 @@ typedef struct _NMSettingDummy NMSettingDummy; typedef struct _NMSettingEthtool NMSettingEthtool; typedef struct _NMSettingGeneric NMSettingGeneric; typedef struct _NMSettingGsm NMSettingGsm; +typedef struct _NMSettingHostname NMSettingHostname; typedef struct _NMSettingIP4Config NMSettingIP4Config; typedef struct _NMSettingIP6Config NMSettingIP6Config; typedef struct _NMSettingIPConfig NMSettingIPConfig; @@ -39,6 +40,7 @@ typedef struct _NMSettingMatch NMSettingMatch; typedef struct _NMSettingOlpcMesh NMSettingOlpcMesh; typedef struct _NMSettingOvsBridge NMSettingOvsBridge; typedef struct _NMSettingOvsDpdk NMSettingOvsDpdk; +typedef struct _NMSettingOvsExternalIDs NMSettingOvsExternalIDs; typedef struct _NMSettingOvsInterface NMSettingOvsInterface; typedef struct _NMSettingOvsPatch NMSettingOvsPatch; typedef struct _NMSettingOvsPort NMSettingOvsPort; @@ -52,6 +54,7 @@ typedef struct _NMSettingTeam NMSettingTeam; typedef struct _NMSettingTeamPort NMSettingTeamPort; typedef struct _NMSettingTun NMSettingTun; typedef struct _NMSettingUser NMSettingUser; +typedef struct _NMSettingVeth NMSettingVeth; typedef struct _NMSettingVlan NMSettingVlan; typedef struct _NMSettingVpn NMSettingVpn; typedef struct _NMSettingVrf NMSettingVrf; diff --git a/libnm-core/nm-crypto-gnutls.c b/libnm-core/nm-crypto-gnutls.c index 6d9aa080..17c5d1dc 100644 --- a/libnm-core/nm-crypto-gnutls.c +++ b/libnm-core/nm-crypto-gnutls.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Dan Williams * Copyright (C) 2007 - 2015 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-crypto-impl.h" diff --git a/libnm-core/nm-crypto-impl.h b/libnm-core/nm-crypto-impl.h index cccf1c02..185f11da 100644 --- a/libnm-core/nm-crypto-impl.h +++ b/libnm-core/nm-crypto-impl.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Dan Williams * Copyright (C) 2007 - 2018 Red Hat, Inc. diff --git a/libnm-core/nm-crypto-nss.c b/libnm-core/nm-crypto-nss.c index ef9c5620..8cbb4daf 100644 --- a/libnm-core/nm-crypto-nss.c +++ b/libnm-core/nm-crypto-nss.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Dan Williams * Copyright (C) 2007 - 2009 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-crypto-impl.h" diff --git a/libnm-core/nm-crypto.c b/libnm-core/nm-crypto.c index d90f6ac4..0eaeeb72 100644 --- a/libnm-core/nm-crypto.c +++ b/libnm-core/nm-crypto.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Dan Williams * Copyright (C) 2007 - 2018 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-crypto.h" diff --git a/libnm-core/nm-crypto.h b/libnm-core/nm-crypto.h index 7a0e6b5c..97bd4628 100644 --- a/libnm-core/nm-crypto.h +++ b/libnm-core/nm-crypto.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Dan Williams * Copyright (C) 2007 - 2014 Red Hat, Inc. diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index eaa4c1b5..295a22a1 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2004 - 2018 Red Hat, Inc. */ @@ -94,7 +94,7 @@ * @NM_CAPABILITY_TEAM: Teams can be managed. This means the team device plugin * is loaded. * @NM_CAPABILITY_OVS: OpenVSwitch can be managed. This means the OVS device plugin - * is loaded. Since: 1.24 + * is loaded. Since: 1.24. * * #NMCapability names the numbers in the Capabilities property. * Capabilities are positive numbers. They are part of stable API @@ -214,8 +214,8 @@ typedef enum { * @NM_DEVICE_TYPE_WPAN: a IEEE 802.15.4 (WPAN) MAC Layer Device * @NM_DEVICE_TYPE_6LOWPAN: 6LoWPAN interface * @NM_DEVICE_TYPE_WIREGUARD: a WireGuard interface - * @NM_DEVICE_TYPE_WIFI_P2P: an 802.11 Wi-Fi P2P device (Since: 1.16) - * @NM_DEVICE_TYPE_VRF: A VRF (Virtual Routing and Forwarding) interface (Since: 1.24) + * @NM_DEVICE_TYPE_WIFI_P2P: an 802.11 Wi-Fi P2P device. Since: 1.16. + * @NM_DEVICE_TYPE_VRF: A VRF (Virtual Routing and Forwarding) interface. Since: 1.24. * * #NMDeviceType values indicate the type of hardware represented by a * device object. @@ -354,26 +354,29 @@ typedef enum { /*< underscore_name=nm_802_11_ap_flags, flags >*/ * supported * @NM_802_11_AP_SEC_KEY_MGMT_OWE_TM: WPA/RSN Opportunistic Wireless Encryption * transition mode is supported. Since: 1.26. + * @NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192: WPA3 Enterprise Suite-B 192 bit mode + * is supported. Since: 1.30. * * 802.11 access point security and authentication flags. These flags describe * the current security requirements of an access point as determined from the * access point's beacon. **/ typedef enum { /*< underscore_name=nm_802_11_ap_security_flags, flags >*/ - NM_802_11_AP_SEC_NONE = 0x00000000, - NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001, - NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002, - NM_802_11_AP_SEC_PAIR_TKIP = 0x00000004, - NM_802_11_AP_SEC_PAIR_CCMP = 0x00000008, - NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010, - NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020, - NM_802_11_AP_SEC_GROUP_TKIP = 0x00000040, - NM_802_11_AP_SEC_GROUP_CCMP = 0x00000080, - NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100, - NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200, - NM_802_11_AP_SEC_KEY_MGMT_SAE = 0x00000400, - NM_802_11_AP_SEC_KEY_MGMT_OWE = 0x00000800, - NM_802_11_AP_SEC_KEY_MGMT_OWE_TM = 0x00001000, + NM_802_11_AP_SEC_NONE = 0x00000000, + NM_802_11_AP_SEC_PAIR_WEP40 = 0x00000001, + NM_802_11_AP_SEC_PAIR_WEP104 = 0x00000002, + NM_802_11_AP_SEC_PAIR_TKIP = 0x00000004, + NM_802_11_AP_SEC_PAIR_CCMP = 0x00000008, + NM_802_11_AP_SEC_GROUP_WEP40 = 0x00000010, + NM_802_11_AP_SEC_GROUP_WEP104 = 0x00000020, + NM_802_11_AP_SEC_GROUP_TKIP = 0x00000040, + NM_802_11_AP_SEC_GROUP_CCMP = 0x00000080, + NM_802_11_AP_SEC_KEY_MGMT_PSK = 0x00000100, + NM_802_11_AP_SEC_KEY_MGMT_802_1X = 0x00000200, + NM_802_11_AP_SEC_KEY_MGMT_SAE = 0x00000400, + NM_802_11_AP_SEC_KEY_MGMT_OWE = 0x00000800, + NM_802_11_AP_SEC_KEY_MGMT_OWE_TM = 0x00001000, + NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192 = 0x00002000, } NM80211ApSecurityFlags; /** @@ -937,9 +940,9 @@ typedef enum { * @NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL: when creating * a new checkpoint, destroy all existing ones. * @NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS: upon rollback, - * delete any new connection added after the checkpoint (Since: 1.6) + * delete any new connection added after the checkpoint. Since: 1.6. * @NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES: upon rollback, - * disconnect any new device appeared after the checkpoint (Since: 1.6) + * disconnect any new device appeared after the checkpoint. Since: 1.6. * @NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING: by default, creating * a checkpoint fails if there are already existing checkoints that * reference the same devices. With this flag, creation of such @@ -951,7 +954,7 @@ typedef enum { * rolling back to an older checkpoint will invalidate all * overlapping younger checkpoints. This opts-in that the * checkpoint can be automatically destroyed by the rollback - * of an older checkpoint. (Since: 1.12) + * of an older checkpoint. Since: 1.12. * * The flags for CheckpointCreate call * @@ -1000,7 +1003,7 @@ typedef enum { /*< skip >*/ * always unsaved, but they are also no backing file on disk and are entirely * in-memory only. * @NM_SETTINGS_CONNECTION_FLAG_EXTERNAL: the profile was generated to represent - * an external configuration of a networking device. Since: 1.26 + * an external configuration of a networking device. Since: 1.26. * * Flags describing the current activation state. * @@ -1027,9 +1030,9 @@ typedef enum { /*< flags >*/ * @NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY: the lifetime * of the activation is bound to the visibility of the connection profile, * which in turn depends on "connection.permissions" and whether a session - * for the user exists. Since: 1.16 + * for the user exists. Since: 1.16. * @NM_ACTIVATION_STATE_FLAG_EXTERNAL: the active connection was generated to - * represent an external configuration of a networking device. Since: 1.26 + * represent an external configuration of a networking device. Since: 1.26. * * Flags describing the current activation state. * diff --git a/libnm-core/nm-dbus-types.xml b/libnm-core/nm-dbus-types.xml index 889aa1de..04ea87e9 100644 --- a/libnm-core/nm-dbus-types.xml +++ b/libnm-core/nm-dbus-types.xml @@ -35,7 +35,7 @@ NM_CAPABILITY_OVS = 2 - OpenVSwitch can be managed. This means the OVS device plugin is loaded. Since: 1.24 + OpenVSwitch can be managed. This means the OVS device plugin is loaded. Since: 1.24. @@ -315,12 +315,12 @@ NM_DEVICE_TYPE_WIFI_P2P = 30 - an 802.11 Wi-Fi P2P device (Since: 1.16) + an 802.11 Wi-Fi P2P device. Since: 1.16. NM_DEVICE_TYPE_VRF = 31 - A VRF (Virtual Routing and Forwarding) interface (Since: 1.24) + A VRF (Virtual Routing and Forwarding) interface. Since: 1.24. @@ -592,6 +592,11 @@ = 0x00001000 WPA/RSN Opportunistic Wireless Encryption transition mode is supported. Since: 1.26. + + NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192 + = 0x00002000 + WPA3 Enterprise Suite-B 192 bit mode is supported. Since: 1.30. + @@ -1625,17 +1630,17 @@ NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS = 0x02 - upon rollback, delete any new connection added after the checkpoint (Since: 1.6) + upon rollback, delete any new connection added after the checkpoint. Since: 1.6. NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES = 0x04 - upon rollback, disconnect any new device appeared after the checkpoint (Since: 1.6) + upon rollback, disconnect any new device appeared after the checkpoint. Since: 1.6. NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING = 0x08 - by default, creating a checkpoint fails if there are already existing checkoints that reference the same devices. With this flag, creation of such checkpoints is allowed, however, if an older checkpoint that references overlapping devices gets rolled back, it will automatically destroy this checkpoint during rollback. This allows to create several overlapping checkpoints in parallel, and rollback to them at will. With the special case that rolling back to an older checkpoint will invalidate all overlapping younger checkpoints. This opts-in that the checkpoint can be automatically destroyed by the rollback of an older checkpoint. (Since: 1.12) + by default, creating a checkpoint fails if there are already existing checkoints that reference the same devices. With this flag, creation of such checkpoints is allowed, however, if an older checkpoint that references overlapping devices gets rolled back, it will automatically destroy this checkpoint during rollback. This allows to create several overlapping checkpoints in parallel, and rollback to them at will. With the special case that rolling back to an older checkpoint will invalidate all overlapping younger checkpoints. This opts-in that the checkpoint can be automatically destroyed by the rollback of an older checkpoint. Since: 1.12. @@ -1720,7 +1725,7 @@ NM_SETTINGS_CONNECTION_FLAG_EXTERNAL = 0x08 - the profile was generated to represent an external configuration of a networking device. Since: 1.26 + the profile was generated to represent an external configuration of a networking device. Since: 1.26. @@ -1780,12 +1785,12 @@ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY = 0x40 - the lifetime of the activation is bound to the visibility of the connection profile, which in turn depends on "connection.permissions" and whether a session for the user exists. Since: 1.16 + the lifetime of the activation is bound to the visibility of the connection profile, which in turn depends on "connection.permissions" and whether a session for the user exists. Since: 1.16. NM_ACTIVATION_STATE_FLAG_EXTERNAL = 0x80 - the active connection was generated to represent an external configuration of a networking device. Since: 1.26 + the active connection was generated to represent an external configuration of a networking device. Since: 1.26. diff --git a/libnm-core/nm-dbus-utils.c b/libnm-core/nm-dbus-utils.c index 02cca67d..cf679daf 100644 --- a/libnm-core/nm-dbus-utils.c +++ b/libnm-core/nm-dbus-utils.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-core-internal.h" diff --git a/libnm-core/nm-default-libnm-core.h b/libnm-core/nm-default-libnm-core.h new file mode 100644 index 00000000..6eb84b94 --- /dev/null +++ b/libnm-core/nm-default-libnm-core.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2015 Red Hat, Inc. + */ + +#ifndef __NM_DEFAULT_LIBNM_CORE_H__ +#define __NM_DEFAULT_LIBNM_CORE_H__ + +/*****************************************************************************/ + +#include "nm-glib-aux/nm-default-glib-i18n-lib.h" + +#undef NETWORKMANAGER_COMPILATION +#define NETWORKMANAGER_COMPILATION NM_NETWORKMANAGER_COMPILATION_LIBNM_CORE + +/*****************************************************************************/ + +#include "nm-version.h" + +/*****************************************************************************/ + +#endif /* __NM_DEFAULT_LIBNM_CORE_H__ */ diff --git a/libnm-core/nm-errors.c b/libnm-core/nm-errors.c index c48276e1..02392663 100644 --- a/libnm-core/nm-errors.c +++ b/libnm-core/nm-errors.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2004 - 2014 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-errors.h" @@ -14,7 +14,6 @@ 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); diff --git a/libnm-core/nm-errors.h b/libnm-core/nm-errors.h index f9d23cfe..639c508e 100644 --- a/libnm-core/nm-errors.h +++ b/libnm-core/nm-errors.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2004 - 2014 Red Hat, Inc. */ @@ -131,7 +131,7 @@ GQuark nm_crypto_error_quark(void); * @NM_DEVICE_ERROR_VERSION_ID_MISMATCH: the version id did not match. * @NM_DEVICE_ERROR_MISSING_DEPENDENCIES: the requested operation could not * be completed due to missing dependencies. - * @NM_DEVICE_ERROR_INVALID_ARGUMENT: invalid argument. Since: 1.16 + * @NM_DEVICE_ERROR_INVALID_ARGUMENT: invalid argument. Since: 1.16. * * Device-related errors. * diff --git a/libnm-core/nm-keyfile-internal.h b/libnm-core/nm-keyfile-internal.h new file mode 100644 index 00000000..bb89214c --- /dev/null +++ b/libnm-core/nm-keyfile-internal.h @@ -0,0 +1,124 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2008 Novell, Inc. + * Copyright (C) 2015 Red Hat, Inc. + */ + +#ifndef __NM_KEYFILE_INTERNAL_H__ +#define __NM_KEYFILE_INTERNAL_H__ + +#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + #error Cannot use this header. +#endif + +#include + +#include "nm-keyfile.h" + +#include "nm-connection.h" +#include "nm-setting-8021x.h" + +#include "nm-core-internal.h" + +/*****************************************************************************/ + +#define NM_KEYFILE_CERT_SCHEME_PREFIX_PATH "file://" +#define NM_KEYFILE_CERT_SCHEME_PREFIX_PKCS11 "pkcs11:" +#define NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB "data:;base64," + +char *nm_keyfile_detect_unqualified_path_scheme(const char * base_dir, + gconstpointer pdata, + gsize data_len, + gboolean consider_exists, + gboolean * out_exists); + +gboolean nm_keyfile_read_ensure_id(NMConnection *connection, const char *fallback_id); + +gboolean nm_keyfile_read_ensure_uuid(NMConnection *connection, const char *fallback_uuid_seed); + +/*****************************************************************************/ + +/** + * NMKeyfileHandlerDataWarn: + * + * this struct is passed as @handler_data for the @NMKeyfileReadHandler of + * type %NM_KEYFILE_HANDLER_TYPE_WARN. + */ +typedef struct { + NMKeyfileWarnSeverity severity; + char * message; + const char * fmt; + va_list ap; +} NMKeyfileHandlerDataWarn; + +/** + * NMKeyfileHandlerDataWriteCert: + * + * this struct is passed as @handler_data for the @NMKeyfileWriteHandler of + * type %NM_KEYFILE_HANDLER_TYPE_WRITE_CERT. + */ +typedef struct { + const NMSetting8021xSchemeVtable *vtable; +} NMKeyfileHandlerDataWriteCert; + +struct _NMKeyfileHandlerData { + NMKeyfileHandlerType type; + + GError **p_error; + + const char *kf_group_name; + const char *kf_key; + + NMSetting * cur_setting; + const char *cur_property; + + union { + NMKeyfileHandlerDataWarn warn; + NMKeyfileHandlerDataWriteCert write_cert; + }; +}; + +/*****************************************************************************/ + +const char *_nm_keyfile_handler_data_warn_get_message(const NMKeyfileHandlerData *handler_data); + +/*****************************************************************************/ + +char * +nm_keyfile_plugin_kf_get_string(GKeyFile *kf, const char *group, const char *key, GError **error); +void nm_keyfile_plugin_kf_set_string(GKeyFile * kf, + const char *group, + const char *key, + const char *value); + +int nm_key_file_get_boolean(GKeyFile *kf, const char *group, const char *key, int default_value); + +void _nm_keyfile_copy(GKeyFile *dst, GKeyFile *src); +gboolean _nm_keyfile_a_contains_all_in_b(GKeyFile *kf_a, GKeyFile *kf_b); +gboolean _nm_keyfile_equals(GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order); +gboolean _nm_keyfile_has_values(GKeyFile *keyfile); + +/*****************************************************************************/ + +#define NM_KEYFILE_GROUP_NMMETA ".nmmeta" +#define NM_KEYFILE_KEY_NMMETA_NM_GENERATED "nm-generated" +#define NM_KEYFILE_KEY_NMMETA_VOLATILE "volatile" +#define NM_KEYFILE_KEY_NMMETA_EXTERNAL "external" +#define NM_KEYFILE_KEY_NMMETA_SHADOWED_STORAGE "shadowed-storage" +#define NM_KEYFILE_KEY_NMMETA_SHADOWED_OWNED "shadowed-owned" + +#define NM_KEYFILE_PATH_NAME_LIB NMLIBDIR "/system-connections" +#define NM_KEYFILE_PATH_NAME_ETC_DEFAULT NMCONFDIR "/system-connections" +#define NM_KEYFILE_PATH_NAME_RUN NMRUNDIR "/system-connections" + +#define NM_KEYFILE_PATH_SUFFIX_NMCONNECTION ".nmconnection" + +#define NM_KEYFILE_PATH_SUFFIX_NMMETA ".nmmeta" + +#define NM_KEYFILE_PATH_NMMETA_SYMLINK_NULL "/dev/null" + +gboolean nm_keyfile_utils_ignore_filename(const char *filename, gboolean require_extension); + +char *nm_keyfile_utils_create_filename(const char *filename, gboolean with_extension); + +#endif /* __NM_KEYFILE_INTERNAL_H__ */ diff --git a/libnm-core/nm-keyfile-utils.c b/libnm-core/nm-keyfile-utils.c new file mode 100644 index 00000000..8de4b0d2 --- /dev/null +++ b/libnm-core/nm-keyfile-utils.c @@ -0,0 +1,684 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2010 Red Hat, Inc. + */ + +#include "libnm-core/nm-default-libnm-core.h" + +#include "nm-keyfile-utils.h" + +#include + +#include "nm-glib-aux/nm-str-buf.h" + +#include "nm-keyfile.h" +#include "nm-setting-wired.h" +#include "nm-setting-wireless.h" +#include "nm-setting-wireless-security.h" + +#include "nm-keyfile-internal.h" + +/*****************************************************************************/ + +/** + * nm_key_file_get_boolean: + * @kf: the #GKeyFile + * @group: the group + * @key: the key + * @default_value: the default value if the value is set or not parsable as a boolean. + * + * Replacement for g_key_file_get_boolean() (which uses g_key_file_parse_value_as_boolean()). + * g_key_file_get_boolean() seems odd to me, because it accepts trailing ASCII whitespace, + * but not leading. + * This uses _nm_utils_ascii_str_to_bool(), which accepts trailing and leading whitespace, + * case-insensitive words, and also strings like "on" and "off". + * _nm_utils_ascii_str_to_bool() is our way to parse booleans from string, and we should + * use that one consistently. + * + * Also, it doesn't have g_key_file_get_boolean()'s odd API to require an error argument + * to detect parsing failures. + * + * Returns: either %TRUE or %FALSE if the key exists and is parsable as a boolean. + * Otherwise, @default_value. Sets errno to ENODATA, EINVAL or 0, depending on whether + * the key exists, whether the value is invalid, or success. + */ +int +nm_key_file_get_boolean(GKeyFile *kf, const char *group, const char *key, int default_value) +{ + int v; + gs_free char *value = NULL; + + value = g_key_file_get_value(kf, group, key, NULL); + + if (!value) { + errno = ENODATA; + return default_value; + } + v = _nm_utils_ascii_str_to_bool(value, -1); + if (v != -1) { + errno = 0; + return v; + } + errno = EINVAL; + return default_value; +} + +/*****************************************************************************/ + +typedef struct { + const char *setting; + const char *alias; +} SettingAlias; + +static const SettingAlias alias_list[] = { + {NM_SETTING_WIRED_SETTING_NAME, "ethernet"}, + {NM_SETTING_WIRELESS_SETTING_NAME, "wifi"}, + {NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, "wifi-security"}, +}; + +const char * +nm_keyfile_plugin_get_alias_for_setting_name(const char *setting_name) +{ + guint i; + + g_return_val_if_fail(setting_name != NULL, NULL); + + for (i = 0; i < G_N_ELEMENTS(alias_list); i++) { + if (nm_streq(setting_name, alias_list[i].setting)) + return alias_list[i].alias; + } + return NULL; +} + +const char * +nm_keyfile_plugin_get_setting_name_for_alias(const char *alias) +{ + guint i; + + g_return_val_if_fail(alias != NULL, NULL); + + for (i = 0; i < G_N_ELEMENTS(alias_list); i++) { + if (nm_streq(alias, alias_list[i].alias)) + return alias_list[i].setting; + } + return NULL; +} + +/*****************************************************************************/ + +char ** +nm_keyfile_plugin_kf_get_string_list(GKeyFile * kf, + const char *group, + const char *key, + gsize * out_length, + GError ** error) +{ + char ** list; + const char *alias; + GError * local = NULL; + gsize l; + + list = g_key_file_get_string_list(kf, group, key, &l, &local); + if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { + alias = nm_keyfile_plugin_get_alias_for_setting_name(group); + if (alias) { + g_clear_error(&local); + list = g_key_file_get_string_list(kf, alias, key, &l, &local); + } + } + if (local) + g_propagate_error(error, local); + if (!list) + l = 0; + NM_SET_OUT(out_length, l); + return list; +} + +guint * +nm_keyfile_plugin_kf_get_integer_list_uint(GKeyFile * key_file, + const char *group_name, + const char *key, + gsize * out_length, + GError ** error) +{ + GError * key_file_error = NULL; + gs_strfreev char **values = NULL; + gs_free guint *int_values = NULL; + gsize i, num_ints; + + NM_SET_OUT(out_length, 0); + + g_return_val_if_fail(key_file != NULL, NULL); + g_return_val_if_fail(group_name != NULL, NULL); + g_return_val_if_fail(key != NULL, NULL); + + values = + nm_keyfile_plugin_kf_get_string_list(key_file, group_name, key, &num_ints, &key_file_error); + + if (key_file_error) + g_propagate_error(error, key_file_error); + if (!values) + return NULL; + + int_values = g_new(guint, num_ints); + + for (i = 0; i < num_ints; i++) { + gint64 v; + + G_STATIC_ASSERT_EXPR(sizeof(v) > sizeof(guint)); + v = _nm_utils_ascii_str_to_int64(values[i], 10, 0, G_MAXUINT, -1); + if (v == -1) { + g_set_error(error, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("Value cannot be interpreted as a list of numbers.")); + return NULL; + } + + int_values[i] = v; + } + + NM_SET_OUT(out_length, num_ints); + return g_steal_pointer(&int_values); +} + +void +nm_keyfile_plugin_kf_set_string_list(GKeyFile * kf, + const char * group, + const char * key, + const char *const *list, + gsize length) +{ + const char *alias; + + alias = nm_keyfile_plugin_get_alias_for_setting_name(group); + g_key_file_set_string_list(kf, alias ?: group, key, list, length); +} + +void +nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile * kf, + const char * group, + const char * key, + const guint *data, + gsize length) +{ + nm_auto_str_buf NMStrBuf strbuf = {}; + gsize i; + + g_return_if_fail(kf); + g_return_if_fail(!length || data); + g_return_if_fail(group && group[0]); + g_return_if_fail(key && key[0]); + + nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); + for (i = 0; i < length; i++) + nm_str_buf_append_printf(&strbuf, "%u;", data[i]); + nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); +} + +void +nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile * kf, + const char * group, + const char * key, + const guint8 *data, + gsize length) +{ + nm_auto_str_buf NMStrBuf strbuf = {}; + gsize i; + + g_return_if_fail(kf); + g_return_if_fail(!length || data); + g_return_if_fail(group && group[0]); + g_return_if_fail(key && key[0]); + + nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); + for (i = 0; i < length; i++) + nm_str_buf_append_printf(&strbuf, "%u;", (guint) data[i]); + nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); +} + +#define DEFINE_KF_WRAPPER_GET(fcn_name, get_ctype, key_file_get_fcn) \ + get_ctype fcn_name(GKeyFile *kf, const char *group, const char *key, GError **error) \ + { \ + get_ctype val; \ + const char *alias; \ + GError * local = NULL; \ + \ + val = key_file_get_fcn(kf, group, key, &local); \ + if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { \ + alias = nm_keyfile_plugin_get_alias_for_setting_name(group); \ + if (alias) { \ + g_clear_error(&local); \ + val = key_file_get_fcn(kf, alias, key, &local); \ + } \ + } \ + if (local) \ + g_propagate_error(error, local); \ + return val; \ + } + +DEFINE_KF_WRAPPER_GET(nm_keyfile_plugin_kf_get_string, char *, g_key_file_get_string); +DEFINE_KF_WRAPPER_GET(nm_keyfile_plugin_kf_get_boolean, gboolean, g_key_file_get_boolean); +DEFINE_KF_WRAPPER_GET(nm_keyfile_plugin_kf_get_value, char *, g_key_file_get_value); + +#define DEFINE_KF_WRAPPER_SET(fcn_name, set_ctype, key_file_set_fcn) \ + void fcn_name(GKeyFile *kf, const char *group, const char *key, set_ctype value) \ + { \ + const char *alias; \ + \ + alias = nm_keyfile_plugin_get_alias_for_setting_name(group); \ + key_file_set_fcn(kf, alias ?: group, key, value); \ + } + +DEFINE_KF_WRAPPER_SET(nm_keyfile_plugin_kf_set_string, const char *, g_key_file_set_string); +DEFINE_KF_WRAPPER_SET(nm_keyfile_plugin_kf_set_boolean, gboolean, g_key_file_set_boolean); +DEFINE_KF_WRAPPER_SET(nm_keyfile_plugin_kf_set_value, const char *, g_key_file_set_value); + +gint64 +nm_keyfile_plugin_kf_get_int64(GKeyFile * kf, + const char *group, + const char *key, + guint base, + gint64 min, + gint64 max, + gint64 fallback, + GError ** error) +{ + gs_free char *s = NULL; + int errsv; + gint64 v; + + s = nm_keyfile_plugin_kf_get_value(kf, group, key, error); + if (!s) { + errno = ENODATA; + return fallback; + } + + v = _nm_utils_ascii_str_to_int64(s, base, min, max, fallback); + errsv = errno; + if (errsv != 0 && error) { + g_set_error(error, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value is not an integer in range [%lld, %lld]"), + (long long) min, + (long long) max); + errno = errsv; + } + return v; +} + +char ** +nm_keyfile_plugin_kf_get_keys(GKeyFile *kf, const char *group, gsize *out_length, GError **error) +{ + char ** keys; + const char *alias; + GError * local = NULL; + gsize l; + + keys = g_key_file_get_keys(kf, group, &l, &local); + if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { + alias = nm_keyfile_plugin_get_alias_for_setting_name(group); + if (alias) { + g_clear_error(&local); + keys = g_key_file_get_keys(kf, alias, &l, error ? &local : NULL); + } + } + nm_assert((!local) != (!keys)); + if (!keys) + l = 0; + nm_assert(l == NM_PTRARRAY_LEN(keys)); + NM_SET_OUT(out_length, l); + if (local) + g_propagate_error(error, local); + return keys; +} + +gboolean +nm_keyfile_plugin_kf_has_key(GKeyFile *kf, const char *group, const char *key, GError **error) +{ + gboolean has; + const char *alias; + GError * local = NULL; + + has = g_key_file_has_key(kf, group, key, &local); + if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { + alias = nm_keyfile_plugin_get_alias_for_setting_name(group); + if (alias) { + g_clear_error(&local); + has = g_key_file_has_key(kf, alias, key, &local); + } + } + if (local) + g_propagate_error(error, local); + return has; +} + +/*****************************************************************************/ + +void +_nm_keyfile_copy(GKeyFile *dst, GKeyFile *src) +{ + gs_strfreev char **groups = NULL; + guint g, k; + + groups = g_key_file_get_groups(src, NULL); + for (g = 0; groups && groups[g]; g++) { + const char * group = groups[g]; + gs_strfreev char **keys = NULL; + + keys = g_key_file_get_keys(src, group, NULL, NULL); + if (!keys) + continue; + + for (k = 0; keys[k]; k++) { + const char * key = keys[k]; + gs_free char *value = NULL; + + value = g_key_file_get_value(src, group, key, NULL); + if (value) + g_key_file_set_value(dst, group, key, value); + else + g_key_file_remove_key(dst, group, key, NULL); + } + } +} + +/*****************************************************************************/ + +gboolean +_nm_keyfile_a_contains_all_in_b(GKeyFile *kf_a, GKeyFile *kf_b) +{ + gs_strfreev char **groups = NULL; + guint i, j; + + if (kf_a == kf_b) + return TRUE; + if (!kf_a || !kf_b) + return FALSE; + + groups = g_key_file_get_groups(kf_a, NULL); + for (i = 0; groups && groups[i]; i++) { + gs_strfreev char **keys = NULL; + + keys = g_key_file_get_keys(kf_a, groups[i], NULL, NULL); + if (!keys) + continue; + + for (j = 0; keys[j]; j++) { + gs_free char *key_a = g_key_file_get_value(kf_a, groups[i], keys[j], NULL); + gs_free char *key_b = g_key_file_get_value(kf_b, groups[i], keys[j], NULL); + + if (g_strcmp0(key_a, key_b) != 0) + return FALSE; + } + } + return TRUE; +} + +static gboolean +_nm_keyfile_equals_ordered(GKeyFile *kf_a, GKeyFile *kf_b) +{ + gs_strfreev char **groups = NULL; + gs_strfreev char **groups_b = NULL; + guint i, j; + + if (kf_a == kf_b) + return TRUE; + if (!kf_a || !kf_b) + return FALSE; + + groups = g_key_file_get_groups(kf_a, NULL); + groups_b = g_key_file_get_groups(kf_b, NULL); + if (!groups && !groups_b) + return TRUE; + if (!groups || !groups_b) + return FALSE; + for (i = 0; groups[i] && groups_b[i] && !strcmp(groups[i], groups_b[i]); i++) + ; + if (groups[i] || groups_b[i]) + return FALSE; + + for (i = 0; groups[i]; i++) { + gs_strfreev char **keys = NULL; + gs_strfreev char **keys_b = NULL; + + keys = g_key_file_get_keys(kf_a, groups[i], NULL, NULL); + keys_b = g_key_file_get_keys(kf_b, groups[i], NULL, NULL); + + if ((!keys) != (!keys_b)) + return FALSE; + if (!keys) + continue; + + for (j = 0; keys[j] && keys_b[j] && !strcmp(keys[j], keys_b[j]); j++) + ; + if (keys[j] || keys_b[j]) + return FALSE; + + for (j = 0; keys[j]; j++) { + gs_free char *key_a = g_key_file_get_value(kf_a, groups[i], keys[j], NULL); + gs_free char *key_b = g_key_file_get_value(kf_b, groups[i], keys[j], NULL); + + if (g_strcmp0(key_a, key_b) != 0) + return FALSE; + } + } + return TRUE; +} + +gboolean +_nm_keyfile_equals(GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order) +{ + if (!consider_order) { + return _nm_keyfile_a_contains_all_in_b(kf_a, kf_b) + && _nm_keyfile_a_contains_all_in_b(kf_b, kf_a); + } else { + return _nm_keyfile_equals_ordered(kf_a, kf_b); + } +} + +gboolean +_nm_keyfile_has_values(GKeyFile *keyfile) +{ + gs_strfreev char **groups = NULL; + + g_return_val_if_fail(keyfile, FALSE); + + 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) +{ + NMStrBuf str; + gsize len; + gsize i; + + 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 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)); + + nm_str_buf_init(&str, len + 15u, FALSE); + + if (name[0] == ' ') { + nm_assert(i == 0); + nm_str_buf_append(&str, "\\20"); + i = 1; + } else + nm_str_buf_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')) { + nm_str_buf_append_c(&str, '\\'); + nm_str_buf_append_c_hex(&str, ch, TRUE); + } else + nm_str_buf_append_c(&str, (char) ch); + } + + return (*out_to_free = nm_str_buf_finalize(&str, NULL)); +} + +static const char * +_keyfile_key_decode(const char *key, char **out_to_free) +{ + char *out; + gsize len; + gsize i; + gsize j; + + 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)); + + out = g_new(char, len + 1u); + + memcpy(out, key, sizeof(char) * i); + + j = 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) { + out[j++] = (char) v; + i += 3; + continue; + } + } + out[j++] = ch; + i++; + } + + nm_assert(j <= len); + out[j] = '\0'; + return (*out_to_free = out); +} + +/*****************************************************************************/ + +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 identical + * 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 new file mode 100644 index 00000000..1555c112 --- /dev/null +++ b/libnm-core/nm-keyfile-utils.h @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2010 - 2015 Red Hat, Inc. + */ + +#ifndef __NM_KEYFILE_UTILS_H__ +#define __NM_KEYFILE_UTILS_H__ + +#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) + #error Cannot use this header. +#endif + +/*****************************************************************************/ + +#include "nm-glib-aux/nm-shared-utils.h" + +/*****************************************************************************/ + +#define NM_KEYFILE_GROUP_VPN_SECRETS "vpn-secrets" +#define NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER "wireguard-peer." + +#define nm_keyfile_error_is_not_found(error) \ + nm_g_error_matches(error, \ + G_KEY_FILE_ERROR, \ + G_KEY_FILE_ERROR_GROUP_NOT_FOUND, \ + G_KEY_FILE_ERROR_KEY_NOT_FOUND) + +const char *nm_keyfile_plugin_get_alias_for_setting_name(const char *setting_name); + +const char *nm_keyfile_plugin_get_setting_name_for_alias(const char *alias); + +/*****************************************************************************/ + +guint *nm_keyfile_plugin_kf_get_integer_list_uint(GKeyFile * kf, + const char *group, + const char *key, + gsize * out_length, + GError ** error); +char **nm_keyfile_plugin_kf_get_string_list(GKeyFile * kf, + const char *group, + const char *key, + gsize * out_length, + GError ** error); +char * +nm_keyfile_plugin_kf_get_string(GKeyFile *kf, const char *group, const char *key, GError **error); +gboolean +nm_keyfile_plugin_kf_get_boolean(GKeyFile *kf, const char *group, const char *key, GError **error); +char * +nm_keyfile_plugin_kf_get_value(GKeyFile *kf, const char *group, const char *key, GError **error); + +void nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile * kf, + const char * group, + const char * key, + const guint8 *list, + gsize length); +void nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile * kf, + const char * group, + const char * key, + const guint *list, + gsize length); +void nm_keyfile_plugin_kf_set_string_list(GKeyFile * kf, + const char * group, + const char * key, + const char *const *list, + gsize length); + +void nm_keyfile_plugin_kf_set_string(GKeyFile * kf, + const char *group, + const char *key, + const char *value); +void +nm_keyfile_plugin_kf_set_boolean(GKeyFile *kf, const char *group, const char *key, gboolean value); +void +nm_keyfile_plugin_kf_set_value(GKeyFile *kf, const char *group, const char *key, const char *value); + +gint64 nm_keyfile_plugin_kf_get_int64(GKeyFile * kf, + const char *group, + const char *key, + guint base, + gint64 min, + gint64 max, + gint64 fallback, + GError ** error); + +char ** +nm_keyfile_plugin_kf_get_keys(GKeyFile *kf, const char *group, gsize *out_length, GError **error); + +gboolean +nm_keyfile_plugin_kf_has_key(GKeyFile *kf, const char *group, 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.c b/libnm-core/nm-keyfile.c new file mode 100644 index 00000000..c9c8cf89 --- /dev/null +++ b/libnm-core/nm-keyfile.c @@ -0,0 +1,4443 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2008 - 2009 Novell, Inc. + * Copyright (C) 2008 - 2017 Red Hat, Inc. + */ + +#include "libnm-core/nm-default-libnm-core.h" + +#include "nm-keyfile-internal.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "nm-glib-aux/nm-str-buf.h" +#include "nm-glib-aux/nm-secret-utils.h" +#include "systemd/nm-sd-utils-shared.h" +#include "nm-libnm-core-intern/nm-common-macros.h" + +#include "nm-core-internal.h" +#include "nm-keyfile.h" +#include "nm-setting-user.h" +#include "nm-setting-ovs-external-ids.h" + +#include "nm-keyfile-utils.h" + +#define ETHERNET_S390_OPTIONS_GROUP_NAME "ethernet-s390-options" + +#define OVS_EXTERNAL_IDS_DATA_PREFIX "data." + +/*****************************************************************************/ + +typedef struct _ParseInfoProperty ParseInfoProperty; + +typedef struct { + NMConnection * connection; + GKeyFile * keyfile; + const char * base_dir; + NMKeyfileReadHandler read_handler; + void * user_data; + GError * error; + const char * group; + NMSetting * setting; +} KeyfileReaderInfo; + +typedef struct { + NMConnection * connection; + GKeyFile * keyfile; + GError * error; + NMKeyfileWriteHandler write_handler; + void * user_data; +} KeyfileWriterInfo; + +/*****************************************************************************/ + +static void +_key_file_handler_data_init(NMKeyfileHandlerData *handler_data, + NMKeyfileHandlerType handler_type, + const char * kf_group_name, + const char * kf_key, + NMSetting * cur_setting, + const char * cur_property, + GError ** p_error) +{ + nm_assert(handler_data); + nm_assert(p_error && !*p_error); + + handler_data->type = handler_type; + handler_data->p_error = p_error; + handler_data->kf_group_name = kf_group_name; + handler_data->kf_key = kf_key; + handler_data->cur_setting = cur_setting; + handler_data->cur_property = cur_property; +} + +static void +_key_file_handler_data_init_read(NMKeyfileHandlerData *handler_data, + NMKeyfileHandlerType handler_type, + KeyfileReaderInfo * info, + const char * kf_key, + const char * cur_property) +{ + _key_file_handler_data_init(handler_data, + handler_type, + info->group, + kf_key, + info->setting, + cur_property, + &info->error); +} + +static void +_key_file_handler_data_init_write(NMKeyfileHandlerData *handler_data, + NMKeyfileHandlerType handler_type, + KeyfileWriterInfo * info, + const char * kf_group, + const char * kf_key, + NMSetting * cur_setting, + const char * cur_property) +{ + _key_file_handler_data_init(handler_data, + handler_type, + kf_group, + kf_key, + cur_setting, + cur_property, + &info->error); +} + +_nm_printf(5, 6) static void _handle_warn(KeyfileReaderInfo * info, + const char * kf_key, + const char * cur_property, + NMKeyfileWarnSeverity severity, + const char * fmt, + ...) +{ + NMKeyfileHandlerData handler_data; + + _key_file_handler_data_init_read(&handler_data, + NM_KEYFILE_HANDLER_TYPE_WARN, + info, + kf_key, + cur_property); + handler_data.warn = (NMKeyfileHandlerDataWarn){ + .severity = severity, + .message = NULL, + .fmt = fmt, + }; + + va_start(handler_data.warn.ap, fmt); + + info->read_handler(info->keyfile, + info->connection, + NM_KEYFILE_HANDLER_TYPE_WARN, + &handler_data, + info->user_data); + + va_end(handler_data.warn.ap); + + g_free(handler_data.warn.message); +} + +#define handle_warn(arg_info, arg_kf_key, arg_property_name, arg_severity, ...) \ + ({ \ + KeyfileReaderInfo *_info = (arg_info); \ + \ + nm_assert(!_info->error); \ + \ + if (_info->read_handler) { \ + _handle_warn(_info, (arg_kf_key), (arg_property_name), (arg_severity), __VA_ARGS__); \ + } \ + _info->error == NULL; \ + }) + +/*****************************************************************************/ + +static gboolean +_secret_flags_persist_secret(NMSettingSecretFlags flags) +{ + return flags == NM_SETTING_SECRET_FLAG_NONE; +} + +/*****************************************************************************/ +/* Some setting properties also contain setting names, such as + * NMSettingConnection's 'type' property (which specifies the base type of the + * connection, e.g. ethernet or wifi) or 'slave-type' (specifies type of slave + * connection, e.g. bond or bridge). This function handles translating those + * properties' values to the real setting name if they are an alias. + */ +static void +setting_alias_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char * setting_name = nm_setting_get_name(setting); + const char * key_setting_name; + gs_free char *s = NULL; + + s = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + if (!s) + return; + + key_setting_name = nm_keyfile_plugin_get_setting_name_for_alias(s); + g_object_set(G_OBJECT(setting), key, key_setting_name ?: s, NULL); +} + +static void +sriov_vfs_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char * setting_name = nm_setting_get_name(setting); + gs_unref_ptrarray GPtrArray *vfs = NULL; + gs_strfreev char ** keys = NULL; + gsize n_keys = 0; + int i; + + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); + if (n_keys == 0) + return; + + vfs = g_ptr_array_new_with_free_func((GDestroyNotify) nm_sriov_vf_unref); + + for (i = 0; i < n_keys; i++) { + gs_free char *value = NULL; + NMSriovVF * vf; + const char * rest; + + if (!g_str_has_prefix(keys[i], "vf.")) + continue; + + rest = &keys[i][3]; + + if (!NM_STRCHAR_ALL(rest, ch, g_ascii_isdigit(ch))) + continue; + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, keys[i], NULL); + + vf = _nm_utils_sriov_vf_from_strparts(rest, value, TRUE, NULL); + if (vf) + g_ptr_array_add(vfs, vf); + } + + g_object_set(G_OBJECT(setting), key, vfs, NULL); +} + +static void +read_array_of_uint(GKeyFile *file, NMSetting *setting, const char *key) +{ + gs_unref_array GArray *array = NULL; + gs_free_error GError *error = NULL; + gs_free guint *tmp = NULL; + gsize length; + + tmp = nm_keyfile_plugin_kf_get_integer_list_uint(file, + nm_setting_get_name(setting), + key, + &length, + &error); + if (error) + return; + + array = g_array_sized_new(FALSE, FALSE, sizeof(guint), length); + g_array_append_vals(array, tmp, length); + g_object_set(setting, key, array, NULL); +} + +static gboolean +get_one_int(KeyfileReaderInfo *info, + const char * kf_key, + const char * property_name, + const char * str, + guint32 max_val, + guint32 * out) +{ + gint64 tmp; + + nm_assert((!info) == (!property_name)); + nm_assert((!info) == (!kf_key)); + + if (!str || !str[0]) { + if (info) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring missing number")); + } + return FALSE; + } + + tmp = _nm_utils_ascii_str_to_int64(str, 10, 0, max_val, -1); + if (tmp == -1) { + if (info) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid number '%s'"), + str); + } + return FALSE; + } + + *out = (guint32) tmp; + return TRUE; +} + +static gpointer +build_address(KeyfileReaderInfo *info, + const char * kf_key, + const char * property_name, + int family, + const char * address_str, + guint32 plen) +{ + NMIPAddress *addr; + GError * error = NULL; + + g_return_val_if_fail(address_str, NULL); + + addr = nm_ip_address_new(family, address_str, plen, &error); + if (!addr) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid %s address: %s"), + family == AF_INET ? "IPv4" : "IPv6", + error->message); + g_error_free(error); + } + + return addr; +} + +static gpointer +build_route(KeyfileReaderInfo *info, + const char * kf_key, + const char * property_name, + int family, + const char * dest_str, + guint32 plen, + const char * gateway_str, + const char * metric_str) +{ + NMIPRoute *route; + guint32 u32; + gint64 metric = -1; + GError * error = NULL; + + g_return_val_if_fail(dest_str, NULL); + + /* Next hop */ + if (gateway_str && gateway_str[0]) { + if (!nm_utils_ipaddr_is_valid(family, gateway_str)) { + /* Try workaround for routes written by broken keyfile writer. + * Due to bug bgo#719851, an older version of writer would have + * written "a:b:c:d::/plen,metric" if the gateway was ::, instead + * of "a:b:c:d::/plen,,metric" or "a:b:c:d::/plen,::,metric" + * Try workaround by interpreting gateway_str as metric to accept such + * invalid routes. This broken syntax should not be not officially + * supported. + **/ + if (family == AF_INET6 && !metric_str + && get_one_int(NULL, NULL, NULL, gateway_str, G_MAXUINT32, &u32)) { + metric = u32; + gateway_str = NULL; + } else { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid gateway '%s' for %s route"), + gateway_str, + family == AF_INET ? "IPv4" : "IPv6"); + return NULL; + } + } + } else + gateway_str = NULL; + + /* parse metric, default to -1 */ + if (metric_str) { + if (!get_one_int(info, kf_key, property_name, metric_str, G_MAXUINT32, &u32)) + return NULL; + metric = u32; + } + + route = nm_ip_route_new(family, dest_str, plen, gateway_str, metric, &error); + if (!route) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid %s route: %s"), + family == AF_INET ? "IPv4" : "IPv6", + error->message); + g_error_free(error); + } + + return route; +} + +/* On success, returns pointer to the zero-terminated field (original @current). + * The @current * pointer target is set to point to the rest of the input + * or %NULL if there is no more input. Sets error to %NULL for convenience. + * + * On failure, returns %NULL (unspecified). The @current pointer target is + * resets to its original value to allow skipping fields. The @error target + * is set to the character that breaks the parsing or %NULL if @current was %NULL. + * + * When @current target is %NULL, gracefully fail returning %NULL while + * leaving the @current target %NULL end setting @error to %NULL; + */ +static const char * +read_field(char **current, const char **out_err_str, const char *characters, const char *delimiters) +{ + const char *start; + + nm_assert(current); + nm_assert(out_err_str); + nm_assert(characters); + nm_assert(delimiters); + + *out_err_str = NULL; + + if (!*current) { + /* graceful failure, leave '*current' NULL */ + return NULL; + } + + /* fail on empty input */ + if (!**current) + return NULL; + + /* remember beginning of input */ + start = *current; + + while (**current && strchr(characters, **current)) + (*current)++; + if (**current) + if (strchr(delimiters, **current)) { + /* success, more data available */ + *(*current)++ = '\0'; + return start; + } else { + /* error, bad character */ + *out_err_str = *current; + *current = (char *) start; + return NULL; + } + else { + /* success, end of input */ + *current = NULL; + return start; + } +} + +/*****************************************************************************/ + +#define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect" +#define NM_OPENCONNECT_KEY_GATEWAY "gateway" +#define NM_OPENCONNECT_KEY_COOKIE "cookie" +#define NM_OPENCONNECT_KEY_GWCERT "gwcert" +#define NM_OPENCONNECT_KEY_XMLCONFIG "xmlconfig" +#define NM_OPENCONNECT_KEY_LASTHOST "lasthost" +#define NM_OPENCONNECT_KEY_AUTOCONNECT "autoconnect" +#define NM_OPENCONNECT_KEY_CERTSIGS "certsigs" + +static void +openconnect_fix_secret_flags(NMSetting *setting) +{ + NMSettingVpn * s_vpn; + NMSettingSecretFlags flags; + + /* Huge hack. There were some openconnect changes that needed to happen + * pretty late, too late to get into distros. Migration has already + * happened for many people, and their secret flags are wrong. But we + * don't want to require re-migration, so we have to fix it up here. Ugh. + */ + + if (!NM_IS_SETTING_VPN(setting)) + return; + + s_vpn = NM_SETTING_VPN(setting); + + if (!nm_streq0(nm_setting_vpn_get_service_type(s_vpn), NM_DBUS_SERVICE_OPENCONNECT)) + return; + + /* These are different for every login session, and should not be stored */ + flags = NM_SETTING_SECRET_FLAG_NOT_SAVED; + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_GATEWAY, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_COOKIE, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_GWCERT, flags, NULL); + + /* These are purely internal data for the auth-dialog, and should be stored */ + flags = 0; + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_XMLCONFIG, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_LASTHOST, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_AUTOCONNECT, flags, NULL); + nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_CERTSIGS, flags, NULL); +} + +/*****************************************************************************/ + +#define IP_ADDRESS_CHARS "0123456789abcdefABCDEF:.%" +#define DIGITS "0123456789" +#define DELIMITERS "/;," + +/* The following IPv4 and IPv6 address formats are supported: + * + * address (DEPRECATED) + * address/plen + * address/gateway (DEPRECATED) + * address/plen,gateway + * + * The following IPv4 and IPv6 route formats are supported: + * + * address/plen (NETWORK dev DEVICE) + * address/plen,gateway (NETWORK via GATEWAY dev DEVICE) + * address/plen,,metric (NETWORK dev DEVICE metric METRIC) + * address/plen,gateway,metric (NETWORK via GATEWAY dev DEVICE metric METRIC) + * + * For backward, forward and sideward compatibility, slash (/), + * semicolon (;) and comma (,) are interchangeable. The choice of + * separator in the above examples is therefore not significant. + * + * Leaving out the prefix length is discouraged and DEPRECATED. The + * default value of IPv6 prefix length was 64 and has not been + * changed. The default for IPv4 is now 24, which is the closest + * IPv4 equivalent. These defaults may just as well be changed to + * match the iproute2 defaults (32 for IPv4 and 128 for IPv6). + */ +static gpointer +read_one_ip_address_or_route(KeyfileReaderInfo *info, + const char * property_name, + const char * setting_name, + const char * kf_key, + gboolean ipv6, + gboolean route, + char ** out_gateway, + NMSetting * setting) +{ + guint plen; + gpointer result; + const char * address_str; + const char * plen_str; + const char * gateway_str; + const char * metric_str; + const char * err_str = NULL; + char * current; + gs_free char *value = NULL; + gs_free char *value_orig = NULL; + +#define VALUE_ORIG() \ + (value_orig \ + ?: (value_orig = \ + nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, kf_key, NULL))) + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, kf_key, NULL); + if (!value) + return NULL; + + current = value; + + /* get address field */ + address_str = read_field(¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS); + if (err_str) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("unexpected character '%c' for address %s: '%s' (position %td)"), + *err_str, + kf_key, + VALUE_ORIG(), + err_str - current); + return NULL; + } + /* get prefix length field (skippable) */ + plen_str = read_field(¤t, &err_str, DIGITS, DELIMITERS); + /* get gateway field */ + gateway_str = read_field(¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS); + if (err_str) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("unexpected character '%c' for %s: '%s' (position %td)"), + *err_str, + kf_key, + VALUE_ORIG(), + err_str - current); + return NULL; + } + /* for routes, get metric */ + if (route) { + metric_str = read_field(¤t, &err_str, DIGITS, DELIMITERS); + if (err_str) { + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("unexpected character '%c' in prefix length for %s: '%s' (position %td)"), + *err_str, + kf_key, + VALUE_ORIG(), + err_str - current); + return NULL; + } + } else + metric_str = NULL; + if (current) { + /* there is still some data */ + if (*current) { + /* another field follows */ + handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("garbage at the end of value %s: '%s'"), + kf_key, + VALUE_ORIG()); + return NULL; + } else { + /* semicolon at the end of input */ + if (!handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_INFO, + _("deprecated semicolon at the end of value %s: '%s'"), + kf_key, + VALUE_ORIG())) + return NULL; + } + } + +#define DEFAULT_PREFIX(for_route, for_ipv6) \ + ((for_route) ? ((for_ipv6) ? 128 : 24) : ((for_ipv6) ? 64 : 24)) + + /* parse plen, fallback to defaults */ + if (plen_str) { + if (!get_one_int(info, kf_key, property_name, plen_str, ipv6 ? 128 : 32, &plen)) { + plen = DEFAULT_PREFIX(route, ipv6); + if (info->error + || !handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid prefix length for %s '%s', defaulting to %d"), + kf_key, + VALUE_ORIG(), + plen)) + return NULL; + } + } else { + plen = DEFAULT_PREFIX(route, ipv6); + if (!handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("missing prefix length for %s '%s', defaulting to %d"), + kf_key, + VALUE_ORIG(), + plen)) + return NULL; + } + + /* build the appropriate data structure for NetworkManager settings */ + if (route) { + result = build_route(info, + kf_key, + property_name, + ipv6 ? AF_INET6 : AF_INET, + address_str, + plen, + gateway_str, + metric_str); + } else { + result = build_address(info, + kf_key, + property_name, + ipv6 ? AF_INET6 : AF_INET, + address_str, + plen); + if (!result) + return NULL; + if (gateway_str) + NM_SET_OUT(out_gateway, g_strdup(gateway_str)); + } + +#undef VALUE_ORIG + + return result; +} + +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)); + } + } +} + +typedef struct { + const char *s_key; + gint32 key_idx; + gint8 key_type; +} BuildListData; + +typedef enum { + BUILD_LIST_TYPE_ADDRESSES, + BUILD_LIST_TYPE_ROUTES, + BUILD_LIST_TYPE_ROUTING_RULES, +} BuildListType; + +static int +_build_list_data_cmp(gconstpointer p_a, gconstpointer p_b, gpointer user_data) +{ + const BuildListData *a = p_a; + const BuildListData *b = p_b; + + NM_CMP_FIELD(a, b, key_idx); + NM_CMP_FIELD(a, b, key_type); + NM_CMP_FIELD_STR(a, b, s_key); + return 0; +} + +static gboolean +_build_list_data_is_shadowed(const BuildListData *build_list, gsize build_list_len, gsize idx) +{ + /* the keyfile contains duplicate keys, which are both returned + * by g_key_file_get_keys() (WHY??). + * + * Skip the earlier one. */ + return idx + 1 < build_list_len && build_list[idx].key_idx == build_list[idx + 1].key_idx + && build_list[idx].key_type == build_list[idx + 1].key_type + && nm_streq(build_list[idx].s_key, build_list[idx + 1].s_key); +} + +static gboolean +_build_list_match_key_w_name_impl(const char *key, + const char *base_name, + gsize base_name_l, + gint32 * out_key_idx) +{ + gint64 v; + + /* some very strict parsing. */ + + /* the key must start with base_name. */ + if (strncmp(key, base_name, base_name_l) != 0) + return FALSE; + + key += base_name_l; + if (key[0] == '\0') { + /* if key is identical to base_name, that's good. */ + NM_SET_OUT(out_key_idx, -1); + return TRUE; + } + + /* if base_name is followed by a zero, then it must be + * only a zero, nothing else. */ + if (key[0] == '0') { + if (key[1] != '\0') + return FALSE; + NM_SET_OUT(out_key_idx, 0); + return TRUE; + } + + /* otherwise, it can only be followed by a non-zero decimal. */ + if (!(key[0] >= '1' && key[0] <= '9')) + return FALSE; + /* and all remaining chars must be decimals too. */ + if (!NM_STRCHAR_ALL(&key[1], ch, g_ascii_isdigit(ch))) + return FALSE; + + /* and it must be convertible to a (positive) int. */ + v = _nm_utils_ascii_str_to_int64(key, 10, 0, G_MAXINT32, -1); + if (v < 0) + return FALSE; + + /* good */ + NM_SET_OUT(out_key_idx, v); + return TRUE; +} + +#define _build_list_match_key_w_name(key, base_name, out_key_idx) \ + _build_list_match_key_w_name_impl(key, base_name, NM_STRLEN(base_name), out_key_idx) + +static BuildListData * +_build_list_create(GKeyFile * keyfile, + const char * group_name, + BuildListType build_list_type, + gsize * out_build_list_len, + char *** out_keys_strv) +{ + gs_strfreev char **keys = NULL; + gsize i_keys, n_keys; + gs_free BuildListData *build_list = NULL; + gsize build_list_len = 0; + + nm_assert(out_build_list_len && *out_build_list_len == 0); + nm_assert(out_keys_strv && !*out_keys_strv); + + keys = nm_keyfile_plugin_kf_get_keys(keyfile, group_name, &n_keys, NULL); + if (n_keys == 0) + return NULL; + + for (i_keys = 0; i_keys < n_keys; i_keys++) { + const char *s_key = keys[i_keys]; + gint32 key_idx; + gint8 key_type = 0; + + switch (build_list_type) { + case BUILD_LIST_TYPE_ROUTES: + if (_build_list_match_key_w_name(s_key, "route", &key_idx)) + key_type = 0; + else if (_build_list_match_key_w_name(s_key, "routes", &key_idx)) + key_type = 1; + else + continue; + break; + case BUILD_LIST_TYPE_ADDRESSES: + if (_build_list_match_key_w_name(s_key, "address", &key_idx)) + key_type = 0; + else if (_build_list_match_key_w_name(s_key, "addresses", &key_idx)) + key_type = 1; + else + continue; + break; + case BUILD_LIST_TYPE_ROUTING_RULES: + if (_build_list_match_key_w_name(s_key, "routing-rule", &key_idx)) + key_type = 0; + else + continue; + break; + default: + nm_assert_not_reached(); + break; + } + + if (G_UNLIKELY(!build_list)) + build_list = g_new(BuildListData, n_keys - i_keys); + + build_list[build_list_len++] = (BuildListData){ + .s_key = s_key, + .key_idx = key_idx, + .key_type = key_type, + }; + } + + if (build_list_len == 0) + return NULL; + + if (build_list_len > 1) { + g_qsort_with_data(build_list, + build_list_len, + sizeof(BuildListData), + _build_list_data_cmp, + NULL); + } + + *out_build_list_len = build_list_len; + *out_keys_strv = g_steal_pointer(&keys); + return g_steal_pointer(&build_list); +} + +static void +ip_address_or_route_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *setting_key) +{ + const char * setting_name = nm_setting_get_name(setting); + gboolean is_ipv6 = nm_streq(setting_name, "ipv6"); + gboolean is_routes = nm_streq(setting_key, "routes"); + gs_free char * gateway = NULL; + gs_unref_ptrarray GPtrArray *list = NULL; + gs_strfreev char ** keys = NULL; + gs_free BuildListData *build_list = NULL; + gsize i_build_list, build_list_len = 0; + + build_list = _build_list_create(info->keyfile, + setting_name, + is_routes ? BUILD_LIST_TYPE_ROUTES : BUILD_LIST_TYPE_ADDRESSES, + &build_list_len, + &keys); + if (!build_list) + return; + + list = g_ptr_array_new_with_free_func(is_routes ? (GDestroyNotify) nm_ip_route_unref + : (GDestroyNotify) nm_ip_address_unref); + + for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) { + const char *s_key; + gpointer item; + + if (_build_list_data_is_shadowed(build_list, build_list_len, i_build_list)) + continue; + + s_key = build_list[i_build_list].s_key; + item = read_one_ip_address_or_route(info, + setting_key, + setting_name, + s_key, + is_ipv6, + is_routes, + gateway ? NULL : &gateway, + setting); + if (item && is_routes) { + char options_key[128]; + + nm_sprintf_buf(options_key, "%s_options", s_key); + fill_route_attributes(info->keyfile, + item, + setting_name, + options_key, + is_ipv6 ? AF_INET6 : AF_INET); + } + + if (info->error) + return; + + if (item) + g_ptr_array_add(list, item); + } + + if (list->len >= 1) + g_object_set(setting, setting_key, list, NULL); + + if (gateway) + g_object_set(setting, "gateway", gateway, NULL); +} + +static void +ip_routing_rule_parser_full(KeyfileReaderInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) +{ + const char * setting_name = nm_setting_get_name(setting); + gboolean is_ipv6 = nm_streq(setting_name, "ipv6"); + gs_strfreev char **keys = NULL; + gs_free BuildListData *build_list = NULL; + gsize i_build_list, build_list_len = 0; + + build_list = _build_list_create(info->keyfile, + setting_name, + BUILD_LIST_TYPE_ROUTING_RULES, + &build_list_len, + &keys); + if (!build_list) + return; + + for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) { + nm_auto_unref_ip_routing_rule NMIPRoutingRule *rule = NULL; + gs_free char * value = NULL; + gs_free_error GError *local = NULL; + + if (_build_list_data_is_shadowed(build_list, build_list_len, i_build_list)) + continue; + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, + setting_name, + build_list[i_build_list].s_key, + NULL); + if (!value) + continue; + + rule = nm_ip_routing_rule_from_string( + value, + (NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE + | (is_ipv6 ? NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET6 + : NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET)), + NULL, + &local); + if (!rule) { + if (!handle_warn(info, + build_list[i_build_list].s_key, + property_info->name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid value for \"%s\": %s"), + build_list[i_build_list].s_key, + local->message)) + return; + continue; + } + + nm_setting_ip_config_add_routing_rule(NM_SETTING_IP_CONFIG(setting), rule); + } +} + +static void +_parser_full_ovs_external_ids_data(KeyfileReaderInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) +{ + const char * setting_name = NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME; + gs_strfreev char **keys = NULL; + gsize n_keys; + gsize i; + + nm_assert(NM_IS_SETTING_OVS_EXTERNAL_IDS(setting)); + nm_assert(nm_streq(property_info->name, NM_SETTING_OVS_EXTERNAL_IDS_DATA)); + nm_assert(nm_streq(setting_name, setting_info->setting_name)); + nm_assert(nm_streq(setting_name, nm_setting_get_name(setting))); + + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); + + for (i = 0; i < n_keys; i++) { + const char * key = keys[i]; + gs_free char *name_to_free = NULL; + gs_free char *value = NULL; + const char * name; + + if (!NM_STR_HAS_PREFIX(key, OVS_EXTERNAL_IDS_DATA_PREFIX)) + continue; + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + if (!value) + continue; + + name = &key[NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)]; + name = nm_keyfile_key_decode(name, &name_to_free); + nm_setting_ovs_external_ids_set_data(NM_SETTING_OVS_EXTERNAL_IDS(setting), name, value); + } +} + +static void +ip_dns_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + int addr_family; + gs_strfreev char **list = NULL; + gsize i, n, length; + + nm_assert(NM_IS_SETTING_IP4_CONFIG(setting) || NM_IS_SETTING_IP6_CONFIG(setting)); + + list = nm_keyfile_plugin_kf_get_string_list(info->keyfile, + nm_setting_get_name(setting), + key, + &length, + NULL); + nm_assert(length == NM_PTRARRAY_LEN(list)); + if (length == 0) + return; + + addr_family = NM_IS_SETTING_IP4_CONFIG(setting) ? AF_INET : AF_INET6; + + n = 0; + for (i = 0; i < length; i++) { + NMIPAddr addr; + + if (inet_pton(addr_family, list[i], &addr) <= 0) { + if (!handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid DNS server IPv%c address '%s'"), + nm_utils_addr_family_to_char(addr_family), + list[i])) { + do { + nm_clear_g_free(&list[i]); + } while (++i < length); + return; + } + nm_clear_g_free(&list[i]); + continue; + } + + if (n != i) + list[n] = g_steal_pointer(&list[i]); + n++; + } + + g_object_set(setting, key, list, NULL); +} + +static void +ip6_addr_gen_mode_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + NMSettingIP6ConfigAddrGenMode addr_gen_mode; + const char * setting_name = nm_setting_get_name(setting); + gs_free char * s = NULL; + + s = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + if (s) { + if (!nm_utils_enum_from_str(nm_setting_ip6_config_addr_gen_mode_get_type(), + s, + (int *) &addr_gen_mode, + NULL)) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid option '%s', use one of [%s]"), + s, + "eui64,stable-privacy"); + return; + } + } else + addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; + + g_object_set(G_OBJECT(setting), key, (int) addr_gen_mode, NULL); +} + +static void +mac_address_parser(KeyfileReaderInfo *info, + NMSetting * setting, + const char * key, + gsize addr_len, + gboolean cloned_mac_addr) +{ + const char * setting_name = nm_setting_get_name(setting); + char addr_str[NM_UTILS_HWADDR_LEN_MAX * 3]; + guint8 addr_bin[NM_UTILS_HWADDR_LEN_MAX]; + gs_free char *tmp_string = NULL; + gs_free guint *int_list = NULL; + const char * mac_str; + gsize int_list_len; + gsize i; + + nm_assert(addr_len > 0); + nm_assert(addr_len <= NM_UTILS_HWADDR_LEN_MAX); + + tmp_string = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + + if (cloned_mac_addr && NM_CLONED_MAC_IS_SPECIAL(tmp_string)) { + mac_str = tmp_string; + goto out; + } + + if (tmp_string && nm_utils_hwaddr_aton(tmp_string, addr_bin, addr_len)) + goto good_addr_bin; + + /* Old format; list of ints */ + int_list = nm_keyfile_plugin_kf_get_integer_list_uint(info->keyfile, + setting_name, + key, + &int_list_len, + NULL); + if (int_list_len == addr_len) { + for (i = 0; i < addr_len; i++) { + const guint val = int_list[i]; + + if (val > 255) + break; + addr_bin[i] = (guint8) val; + } + if (i == addr_len) + goto good_addr_bin; + } + + handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("ignoring invalid MAC address")); + return; + +good_addr_bin: + nm_utils_bin2hexstr_full(addr_bin, addr_len, ':', TRUE, addr_str); + mac_str = addr_str; + +out: + g_object_set(setting, key, mac_str, NULL); +} + +static void +mac_address_parser_ETHER(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + mac_address_parser(info, setting, key, ETH_ALEN, FALSE); +} + +static void +mac_address_parser_ETHER_cloned(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + mac_address_parser(info, setting, key, ETH_ALEN, TRUE); +} + +static void +mac_address_parser_INFINIBAND(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + mac_address_parser(info, setting, key, INFINIBAND_ALEN, FALSE); +} + +static void +read_hash_of_string(KeyfileReaderInfo *info, + GKeyFile * file, + NMSetting * setting, + const char * kf_group) +{ + gs_strfreev char **keys = NULL; + const char *const *iter; + const char * setting_name = nm_setting_get_name(setting); + gboolean is_vpn; + gsize n_keys; + + nm_assert((NM_IS_SETTING_VPN(setting) && nm_streq(kf_group, NM_SETTING_VPN_DATA)) + || (NM_IS_SETTING_VPN(setting) && nm_streq(kf_group, NM_SETTING_VPN_SECRETS)) + || (NM_IS_SETTING_BOND(setting) && nm_streq(kf_group, NM_SETTING_BOND_OPTIONS)) + || (NM_IS_SETTING_USER(setting) && nm_streq(kf_group, NM_SETTING_USER_DATA))); + + keys = nm_keyfile_plugin_kf_get_keys(file, setting_name, &n_keys, NULL); + if (n_keys == 0) + return; + + if ((is_vpn = NM_IS_SETTING_VPN(setting)) || NM_IS_SETTING_BOND(setting)) { + for (iter = (const char *const *) keys; *iter; iter++) { + const char * kf_key = *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, kf_key, NULL); + if (!value) + continue; + + name = nm_keyfile_key_decode(kf_key, &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 (!nm_streq(name, "interface-name")) { + gs_free_error GError *error = NULL; + + if (!_nm_setting_bond_validate_option(name, value, &error)) { + if (!handle_warn(info, + kf_key, + name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid bond option %s%s%s = %s%s%s: %s"), + NM_PRINT_FMT_QUOTE_STRING(name), + NM_PRINT_FMT_QUOTE_STRING(value), + error->message)) + return; + } else + nm_setting_bond_add_option(NM_SETTING_BOND(setting), name, value); + } + } + } + openconnect_fix_secret_flags(setting); + return; + } + + if (NM_IS_SETTING_USER(setting)) { + gs_unref_hashtable GHashTable *data = NULL; + + data = g_hash_table_new_full(nm_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_object_set(setting, NM_SETTING_USER_DATA, data, NULL); + return; + } + + nm_assert_not_reached(); +} + +static gsize +unescape_semicolons(char *str) +{ + gsize i, j; + + for (i = 0, j = 0; str[i];) { + if (str[i] == '\\' && str[i + 1] == ';') + i++; + str[j++] = str[i++]; + } + nm_explicit_bzero(&str[j], i - j); + return j; +} + +static GBytes * +get_bytes(KeyfileReaderInfo *info, + const char * setting_name, + const char * key, + gboolean zero_terminate, + gboolean unescape_semicolon) +{ + nm_auto_free_secret char *tmp_string = NULL; + gboolean may_be_int_list = TRUE; + gsize length; + GBytes * result; + + /* New format: just a string + * Old format: integer list; e.g. 11;25;38; + */ + tmp_string = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + if (!tmp_string) + return NULL; + + /* if the string is empty, we return an empty GBytes array. + * Note that for NM_SETTING_802_1X_PASSWORD_RAW both %NULL and + * an empty GBytes are valid, and shall be destinguished. */ + if (!tmp_string[0]) { + /* note that even if @zero_terminate is TRUE, we return an empty + * byte-array. The reason is that zero_terminate is there to terminate + * *valid* strings. It's not there to terminated invalid (empty) strings. + */ + return g_bytes_new_static("", 0); + } + + for (length = 0; tmp_string[length]; length++) { + const char ch = tmp_string[length]; + + if (!g_ascii_isspace(ch) && !g_ascii_isdigit(ch) && ch != ';') { + may_be_int_list = FALSE; + length += strlen(&tmp_string[length]); + break; + } + } + + /* Try to parse the string as a integer list. */ + if (may_be_int_list && length > 0) { + nm_auto_free_secret_buf NMSecretBuf *bin = NULL; + const char *const s = tmp_string; + gsize i, d; + + bin = nm_secret_buf_new(length / 2 + 3); + +#define DIGIT(c) ((c) - '0') + i = 0; + d = 0; + while (TRUE) { + int n; + + /* leading whitespace */ + while (g_ascii_isspace(s[i])) + i++; + if (s[i] == '\0') + break; + /* then expect 1 to 3 digits */ + if (!g_ascii_isdigit(s[i])) { + d = 0; + break; + } + n = DIGIT(s[i]); + i++; + if (g_ascii_isdigit(s[i])) { + n = 10 * n + DIGIT(s[i]); + i++; + if (g_ascii_isdigit(s[i])) { + n = 10 * n + DIGIT(s[i]); + i++; + } + } + if (n > 255) { + d = 0; + break; + } + + nm_assert(d < bin->len); + bin->bin[d++] = n; + + /* allow whitespace after the digit. */ + while (g_ascii_isspace(s[i])) + i++; + /* need a semicolon as separator. */ + if (s[i] != ';') { + d = 0; + break; + } + i++; + } +#undef DIGIT + + /* Old format; list of ints. We already did a strict validation of the + * string format before. We expect that this conversion cannot fail. */ + if (d > 0) { + /* note that @zero_terminate does not add a terminating '\0' to + * binary data as an integer list. If the bytes are expressed as + * an integer list, all potential NUL characters are supposed to + * be included there explicitly. + * + * However, in the spirit of defensive programming, we do append a + * NUL character to the buffer, although this character is hidden + * and only a mitigation for bugs. */ + + if (d + 10 < bin->len) { + /* hm, too much unused memory. Copy the memory to a suitable + * sized buffer. */ + return nm_secret_copy_to_gbytes(bin->bin, d); + } + + nm_assert(d < bin->len); + bin->bin[d] = '\0'; + return nm_secret_buf_to_gbytes_take(g_steal_pointer(&bin), d); + } + } + + /* Handle as a simple string (ie, new format) */ + if (unescape_semicolon) + length = unescape_semicolons(tmp_string); + if (zero_terminate) + length++; + if (length == 0) + return NULL; + + result = + g_bytes_new_with_free_func(tmp_string, length, (GDestroyNotify) nm_free_secret, tmp_string); + tmp_string = NULL; + return result; +} + +static void +ssid_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char * setting_name = nm_setting_get_name(setting); + gs_unref_bytes GBytes *bytes = NULL; + + bytes = get_bytes(info, setting_name, key, FALSE, TRUE); + if (!bytes) { + handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("ignoring invalid SSID")); + return; + } + g_object_set(setting, key, bytes, NULL); +} + +static void +password_raw_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char * setting_name = nm_setting_get_name(setting); + gs_unref_bytes GBytes *bytes = NULL; + + bytes = get_bytes(info, setting_name, key, FALSE, TRUE); + if (!bytes) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid raw password")); + return; + } + g_object_set(setting, key, bytes, NULL); +} + +static char * +get_cert_path(const char *base_dir, const guint8 *cert_path, gsize cert_path_len) +{ + const char *base; + char * p = NULL, *path, *tmp; + + g_return_val_if_fail(base_dir != NULL, NULL); + g_return_val_if_fail(cert_path != NULL, NULL); + + path = g_strndup((char *) cert_path, cert_path_len); + + if (path[0] == '/') + return path; + + base = path; + p = strrchr(path, '/'); + if (p) + base = p + 1; + + tmp = g_build_path("/", base_dir, base, NULL); + g_free(path); + return tmp; +} + +static const char *certext[] = {".pem", ".cert", ".crt", ".cer", ".p12", ".der", ".key"}; + +static gboolean +has_cert_ext(const char *path) +{ + int i; + + for (i = 0; i < G_N_ELEMENTS(certext); i++) { + if (g_str_has_suffix(path, certext[i])) + return TRUE; + } + return FALSE; +} + +char * +nm_keyfile_detect_unqualified_path_scheme(const char * base_dir, + gconstpointer pdata, + gsize data_len, + gboolean consider_exists, + gboolean * out_exists) +{ + const char * data = pdata; + gboolean exists = FALSE; + gsize validate_len; + gsize path_len, pathuri_len; + gs_free char *path = NULL; + gs_free char *pathuri = NULL; + + g_return_val_if_fail(base_dir && base_dir[0] == '/', NULL); + + if (!pdata) + return NULL; + if (data_len == -1) + data_len = strlen(data); + if (data_len > 500 || data_len < 1) + return NULL; + + /* If there's a trailing zero tell g_utf8_validate() to validate until the zero */ + if (data[data_len - 1] == '\0') { + /* setting it to -1, would mean we accept data to contain NUL characters before the + * end. Don't accept any NUL in [0 .. data_len-1[ . */ + validate_len = data_len - 1; + } else + validate_len = data_len; + if (validate_len == 0 || g_utf8_validate((const char *) data, validate_len, NULL) == FALSE) + return NULL; + + /* Might be a bare path without the file:// prefix; in that case + * if it's an absolute path, use that, otherwise treat it as a + * relative path to the current directory. + */ + + path = get_cert_path(base_dir, (const guint8 *) data, data_len); + + /* FIXME(keyfile-parse-in-memory): it is wrong that keyfile reader makes decisions based on + * the file systems content. The serialization/parsing should be entirely in-memory. */ + if (!memchr(data, '/', data_len) && !has_cert_ext(path)) { + if (!consider_exists) + return NULL; + exists = g_file_test(path, G_FILE_TEST_EXISTS); + if (!exists) + return NULL; + } else if (out_exists) + exists = g_file_test(path, G_FILE_TEST_EXISTS); + + /* Construct the proper value as required for the PATH scheme. + * + * When returning TRUE, we must also be sure that @data_len does not look like + * the deprecated format of list of integers. With this implementation that is the + * case, as long as @consider_exists is FALSE. */ + path_len = strlen(path); + pathuri_len = (NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) + 1) + path_len; + pathuri = g_new(char, pathuri_len); + memcpy(pathuri, + NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, + NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)); + memcpy(&pathuri[NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)], path, path_len + 1); + if (nm_setting_802_1x_check_cert_scheme(pathuri, pathuri_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_PATH) + return NULL; + + NM_SET_OUT(out_exists, exists); + return g_steal_pointer(&pathuri); +} + +#define HAS_SCHEME_PREFIX(bin, bin_len, scheme) \ + ({ \ + const char *const _bin = (bin); \ + const gsize _bin_len = (bin_len); \ + \ + nm_assert(_bin &&_bin_len > 0); \ + \ + (_bin_len > NM_STRLEN(scheme) + 1 && _bin[_bin_len - 1] == '\0' \ + && memcmp(_bin, scheme, NM_STRLEN(scheme)) == 0); \ + }) + +static void +cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char * setting_name = nm_setting_get_name(setting); + gs_unref_bytes GBytes *bytes = NULL; + const char * bin = NULL; + gsize bin_len = 0; + char * path; + gboolean path_exists; + + bytes = get_bytes(info, setting_name, key, TRUE, FALSE); + if (bytes) + bin = g_bytes_get_data(bytes, &bin_len); + if (bin_len == 0) { + if (!info->error) { + handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("invalid key/cert value")); + } + return; + } + + if (HAS_SCHEME_PREFIX(bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)) { + const char * path2 = &bin[NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)]; + gs_free char *path2_free = NULL; + + if (nm_setting_802_1x_check_cert_scheme(bin, bin_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_PATH) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value path \"%s\""), + bin); + return; + } + + g_object_set(setting, key, bytes, NULL); + + if (path2[0] != '/') { + /* we want to read absolute paths because we use keyfile as exchange + * between different processes which might not have the same cwd. */ + path2_free = get_cert_path(info->base_dir, + (const guint8 *) path2, + bin_len - NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) - 1); + path2 = path2_free; + } + + /* FIXME(keyfile-parse-in-memory): keyfile reader must not access the file system and + * (in a first step) only operate in memory-only. If the presence of files should be checked, + * then by invoking a callback (and possibly keyfile settings plugin would + * collect the file names to be checked and check them later). */ + if (!g_file_test(path2, G_FILE_TEST_EXISTS)) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, + _("certificate or key file '%s' does not exist"), + path2); + } + return; + } + + if (HAS_SCHEME_PREFIX(bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_PKCS11)) { + if (nm_setting_802_1x_check_cert_scheme(bin, bin_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_PKCS11) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid PKCS#11 URI \"%s\""), + bin); + return; + } + + g_object_set(setting, key, bytes, NULL); + return; + } + + if (HAS_SCHEME_PREFIX(bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB)) { + const char *cdata = bin + NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB); + gsize cdata_len = bin_len - NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB) - 1; + gs_free guchar *bin_decoded = NULL; + gsize bin_decoded_len = 0; + gsize i; + gboolean valid_base64; + gs_unref_bytes GBytes *val = NULL; + + /* Let's be strict here. We expect valid base64, no funny stuff!! + * We didn't write such invalid data ourselfes and refuse to read it as blob. */ + if ((valid_base64 = (cdata_len % 4 == 0))) { + for (i = 0; i < cdata_len; i++) { + char c = cdata[i]; + + if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') + || (c == '+' || c == '/'))) { + if (c != '=' || i < cdata_len - 2) + valid_base64 = FALSE; + else { + for (; i < cdata_len; i++) { + if (cdata[i] != '=') + valid_base64 = FALSE; + } + } + break; + } + } + } + if (valid_base64) + bin_decoded = g_base64_decode(cdata, &bin_decoded_len); + + if (bin_decoded_len == 0) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value data:;base64, is not base64")); + return; + } + + if (nm_setting_802_1x_check_cert_scheme(bin_decoded, bin_decoded_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_BLOB) { + /* The blob probably starts with "file://". Setting the cert data will confuse NMSetting8021x. + * In fact this is a limitation of NMSetting8021x which does not support setting blobs that start + * with file://. Just warn and return TRUE to signal that we ~handled~ the setting. */ + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value data:;base64,file://")); + return; + } + + val = g_bytes_new_take(g_steal_pointer(&bin_decoded), bin_decoded_len); + g_object_set(setting, key, val, NULL); + return; + } + + /* If not, it might be a plain path */ + path = + nm_keyfile_detect_unqualified_path_scheme(info->base_dir, bin, bin_len, TRUE, &path_exists); + if (path) { + gs_unref_bytes GBytes *val = NULL; + + /* Construct the proper value as required for the PATH scheme */ + val = g_bytes_new_take(path, strlen(path) + 1); + g_object_set(setting, key, val, NULL); + + /* Warn if the certificate didn't exist */ + if (!path_exists) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, + _("certificate or key file '%s' does not exist"), + path); + } + return; + } + + if (nm_setting_802_1x_check_cert_scheme(bin, bin_len, NULL) + != NM_SETTING_802_1X_CK_SCHEME_BLOB) { + /* The blob probably starts with "file://" but contains invalid characters for a path. + * Setting the cert data will confuse NMSetting8021x. + * In fact, NMSetting8021x does not support setting such binary data, so just warn and + * continue. */ + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value is not a valid blob")); + return; + } + + g_object_set(setting, key, bytes, NULL); +} + +static int +_parity_from_char(int ch) +{ +#if NM_MORE_ASSERTS > 5 + { + static char check = 0; + + if (check == 0) { + nm_auto_unref_gtypeclass GEnumClass *klass = + g_type_class_ref(NM_TYPE_SETTING_SERIAL_PARITY); + guint i; + + check = 1; + + /* In older versions, parity was G_TYPE_CHAR/gint8, and the character + * value was stored as integer. + * For example parity=69 equals parity=E, meaning NM_SETTING_SERIAL_PARITY_EVEN. + * + * That means, certain values are reserved. Assert that these numbers + * are not reused when we extend NMSettingSerialParity enum. + * Actually, since NM_SETTING_SERIAL_PARITY is g_param_spec_enum(), + * we anyway cannot extend the enum without breaking API... + * + * [1] commit "a91e60902e libnm-core: make NMSettingSerial:parity an enum" + * [2] https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=a91e60902eabae1de93d61323dae6ac894b5d40f + */ + g_assert(G_IS_ENUM_CLASS(klass)); + for (i = 0; i < klass->n_values; i++) { + const GEnumValue *v = &klass->values[i]; + int num = v->value; + + g_assert(_parity_from_char(num) == -1); + g_assert(!NM_IN_SET(num, 'e', 'E', 'o', 'O', 'n', 'N')); + } + } + } +#endif + + switch (ch) { + case 'E': + case 'e': + return NM_SETTING_SERIAL_PARITY_EVEN; + case 'O': + case 'o': + return NM_SETTING_SERIAL_PARITY_ODD; + case 'N': + case 'n': + return NM_SETTING_SERIAL_PARITY_NONE; + } + + return -1; +} + +static void +parity_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char * setting_name = nm_setting_get_name(setting); + gs_free_error GError *err = NULL; + int parity; + gs_free char * tmp_str = NULL; + gint64 i64; + + /* Keyfile traditionally stored this as the ASCII value for 'E', 'o', or 'n'. + * We now accept either that or the (case-insensitive) character itself (but + * still always write it the old way, for backward compatibility). + */ + tmp_str = nm_keyfile_plugin_kf_get_value(info->keyfile, setting_name, key, &err); + if (err) + goto out_err; + + if (tmp_str && tmp_str[0] != '\0' && tmp_str[1] == '\0') { + /* the ASCII characters like 'E' are taken directly... */ + parity = _parity_from_char(tmp_str[0]); + if (parity >= 0) + goto parity_good; + } + + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT, G_MAXINT, G_MININT64); + if (i64 != G_MININT64 && errno == 0) { + if ((parity = _parity_from_char(i64)) >= 0) { + /* another oddity: the string is a valid number. However, if the numeric values + * is one of the supported ASCII codes, accept it (like 69 for 'E'). + */ + goto parity_good; + } + + /* Finally, take the numeric value as is. */ + parity = i64; + goto parity_good; + } + + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid parity value '%s'"), + tmp_str ?: ""); + return; + +parity_good: + nm_g_object_set_property_enum(G_OBJECT(setting), + key, + NM_TYPE_SETTING_SERIAL_PARITY, + parity, + &err); + +out_err: + if (!err) + return; + if (nm_keyfile_error_is_not_found(err)) { + /* ignore such errors. The key is not present. */ + return; + } + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid setting: %s"), + err->message); +} + +static void +team_config_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char * setting_name = nm_setting_get_name(setting); + gs_free char *conf = NULL; + gs_free_error GError *error = NULL; + + conf = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); + + g_object_set(G_OBJECT(setting), key, conf, NULL); + + if (conf && !nm_setting_verify(setting, NULL, &error)) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid team configuration: %s"), + error->message); + g_object_set(G_OBJECT(setting), key, NULL, NULL); + } +} + +static void +bridge_vlan_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + gs_unref_ptrarray GPtrArray *vlans = NULL; + gs_free char * value = NULL; + gs_free const char ** strv = NULL; + const char *const * iter; + GError * local = NULL; + NMBridgeVlan * vlan; + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, nm_setting_get_name(setting), key, NULL); + if (!value || !value[0]) + return; + + vlans = g_ptr_array_new_with_free_func((GDestroyNotify) nm_bridge_vlan_unref); + + strv = nm_utils_escaped_tokens_split(value, ","); + if (strv) { + for (iter = strv; *iter; iter++) { + vlan = nm_bridge_vlan_from_str(*iter, &local); + if (!vlan) { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + "invalid bridge VLAN: %s", + local->message); + g_clear_error(&local); + continue; + } + g_ptr_array_add(vlans, vlan); + } + } + + if (vlans->len > 0) + g_object_set(setting, key, vlans, NULL); +} + +static void +qdisc_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char * setting_name = nm_setting_get_name(setting); + gs_unref_ptrarray GPtrArray *qdiscs = NULL; + gs_strfreev char ** keys = NULL; + gsize n_keys = 0; + int i; + + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); + if (n_keys == 0) + return; + + qdiscs = g_ptr_array_new_with_free_func((GDestroyNotify) nm_tc_qdisc_unref); + + for (i = 0; i < n_keys; i++) { + NMTCQdisc * qdisc; + const char * qdisc_parent; + gs_free char *qdisc_rest = NULL; + gs_free char *qdisc_str = NULL; + gs_free_error GError *err = NULL; + + if (!g_str_has_prefix(keys[i], "qdisc.")) + continue; + + qdisc_parent = keys[i] + sizeof("qdisc.") - 1; + qdisc_rest = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, keys[i], NULL); + qdisc_str = g_strdup_printf( + "%s%s %s", + _nm_utils_parse_tc_handle(qdisc_parent, NULL) != TC_H_UNSPEC ? "parent " : "", + qdisc_parent, + qdisc_rest); + + qdisc = nm_utils_tc_qdisc_from_str(qdisc_str, &err); + if (!qdisc) { + handle_warn(info, + keys[i], + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid qdisc: %s"), + err->message); + } else { + g_ptr_array_add(qdiscs, qdisc); + } + } + + if (qdiscs->len >= 1) + g_object_set(setting, key, qdiscs, NULL); +} + +static void +tfilter_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) +{ + const char * setting_name = nm_setting_get_name(setting); + gs_unref_ptrarray GPtrArray *tfilters = NULL; + gs_strfreev char ** keys = NULL; + gsize n_keys = 0; + int i; + + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); + if (n_keys == 0) + return; + + tfilters = g_ptr_array_new_with_free_func((GDestroyNotify) nm_tc_tfilter_unref); + + for (i = 0; i < n_keys; i++) { + NMTCTfilter * tfilter; + const char * tfilter_parent; + gs_free char *tfilter_rest = NULL; + gs_free char *tfilter_str = NULL; + gs_free_error GError *err = NULL; + + if (!g_str_has_prefix(keys[i], "tfilter.")) + continue; + + tfilter_parent = keys[i] + sizeof("tfilter.") - 1; + tfilter_rest = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, keys[i], NULL); + tfilter_str = g_strdup_printf( + "%s%s %s", + _nm_utils_parse_tc_handle(tfilter_parent, NULL) != TC_H_UNSPEC ? "parent " : "", + tfilter_parent, + tfilter_rest); + + tfilter = nm_utils_tc_tfilter_from_str(tfilter_str, &err); + if (!tfilter) { + handle_warn(info, + keys[i], + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid tfilter: %s"), + err->message); + } else { + g_ptr_array_add(tfilters, tfilter); + } + } + + if (tfilters->len >= 1) + g_object_set(setting, key, tfilters, NULL); +} + +/*****************************************************************************/ + +/* Some setting properties also contain setting names, such as + * NMSettingConnection's 'type' property (which specifies the base type of the + * connection, eg ethernet or wifi) or the 802-11-wireless setting's + * 'security' property which specifies whether or not the AP requires + * encryption. This function handles translating those properties' values + * from the real setting name to the more-readable alias. + */ +static void +setting_alias_writer(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value) +{ + const char *str, *alias; + + str = g_value_get_string(value); + alias = nm_keyfile_plugin_get_alias_for_setting_name(str); + nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, alias ?: str); +} + +static void +sriov_vfs_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) +{ + GPtrArray *vfs; + guint i; + + vfs = g_value_get_boxed(value); + if (!vfs) + return; + + for (i = 0; i < vfs->len; i++) { + const NMSriovVF *vf = vfs->pdata[i]; + gs_free char * kf_value = NULL; + char kf_key[32]; + + kf_value = nm_utils_sriov_vf_to_str(vf, TRUE, NULL); + if (!kf_value) + continue; + + nm_sprintf_buf(kf_key, "vf.%u", nm_sriov_vf_get_index(vf)); + + nm_keyfile_plugin_kf_set_string(info->keyfile, + nm_setting_get_name(setting), + kf_key, + kf_value); + } +} + +static void +write_array_of_uint(GKeyFile *file, NMSetting *setting, const char *key, const GValue *value) +{ + GArray *array; + + array = g_value_get_boxed(value); + + nm_assert(!array || g_array_get_element_size(array) == sizeof(guint)); + + if (!array || !array->len) + return; + + nm_keyfile_plugin_kf_set_integer_list_uint(file, + nm_setting_get_name(setting), + key, + (const guint *) array->data, + array->len); +} + +static void +dns_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) +{ + char **list; + + list = g_value_get_boxed(value); + if (list && list[0]) { + nm_keyfile_plugin_kf_set_string_list(info->keyfile, + nm_setting_get_name(setting), + key, + (const char **) list, + g_strv_length(list)); + } +} + +static void +ip6_addr_gen_mode_writer(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value) +{ + NMSettingIP6ConfigAddrGenMode addr_gen_mode; + gs_free char * str = NULL; + + addr_gen_mode = (NMSettingIP6ConfigAddrGenMode) g_value_get_int(value); + str = nm_utils_enum_to_str(nm_setting_ip6_config_addr_gen_mode_get_type(), addr_gen_mode); + nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, str); +} + +static void +write_ip_values(GKeyFile * file, + const char *setting_name, + GPtrArray * array, + const char *gateway, + gboolean is_route) +{ + if (array->len > 0) { + nm_auto_str_buf NMStrBuf output = NM_STR_BUF_INIT(2 * INET_ADDRSTRLEN + 10, FALSE); + int addr_family; + guint i; + const char * addr; + const char * gw; + guint32 plen; + char key_name[64]; + char * key_name_idx; + + addr_family = + nm_streq(setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME) ? AF_INET : AF_INET6; + + strcpy(key_name, is_route ? "route" : "address"); + key_name_idx = key_name + strlen(key_name); + + for (i = 0; i < array->len; i++) { + gint64 metric = -1; + + if (is_route) { + NMIPRoute *route = array->pdata[i]; + + addr = nm_ip_route_get_dest(route); + plen = nm_ip_route_get_prefix(route); + gw = nm_ip_route_get_next_hop(route); + metric = nm_ip_route_get_metric(route); + } else { + NMIPAddress *address = array->pdata[i]; + + addr = nm_ip_address_get_address(address); + plen = nm_ip_address_get_prefix(address); + gw = (i == 0) ? gateway : NULL; + } + + nm_str_buf_set_size(&output, 0, FALSE, FALSE); + nm_str_buf_append_printf(&output, "%s/%u", addr, plen); + if (metric != -1 || gw) { + /* Older versions of the plugin do not support the form + * "a.b.c.d/plen,,metric", so, we always have to write the + * gateway, even if there isn't one. + * The current version supports reading of the above form. + */ + if (!gw) { + if (addr_family == AF_INET) + gw = "0.0.0.0"; + else + gw = "::"; + } + + nm_str_buf_append_c(&output, ','); + nm_str_buf_append(&output, gw); + if (is_route && metric != -1) + nm_str_buf_append_printf(&output, ",%lu", (unsigned long) metric); + } + + sprintf(key_name_idx, "%u", i + 1); + nm_keyfile_plugin_kf_set_string(file, + setting_name, + key_name, + nm_str_buf_get_str(&output)); + + if (is_route) { + gs_free char *attributes = NULL; + + attributes = + nm_utils_format_variant_attributes(_nm_ip_route_get_attributes(array->pdata[i]), + ',', + '='); + if (attributes) { + g_strlcat(key_name, "_options", sizeof(key_name)); + nm_keyfile_plugin_kf_set_string(file, setting_name, key_name, attributes); + } + } + } + } +} + +static void +addr_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) +{ + GPtrArray * array; + const char *setting_name = nm_setting_get_name(setting); + const char *gateway = nm_setting_ip_config_get_gateway(NM_SETTING_IP_CONFIG(setting)); + + array = (GPtrArray *) g_value_get_boxed(value); + if (array && array->len) + write_ip_values(info->keyfile, setting_name, array, gateway, FALSE); +} + +static void +route_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) +{ + GPtrArray * array; + const char *setting_name = nm_setting_get_name(setting); + + array = (GPtrArray *) g_value_get_boxed(value); + if (array && array->len) + write_ip_values(info->keyfile, setting_name, array, NULL, TRUE); +} + +static void +bridge_vlan_writer(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value) +{ + GPtrArray *vlans; + + vlans = g_value_get_boxed(value); + if (vlans && vlans->len > 0) { + const guint string_initial_size = vlans->len * 10u; + nm_auto_str_buf NMStrBuf string = NM_STR_BUF_INIT(string_initial_size, FALSE); + guint i; + + for (i = 0; i < vlans->len; i++) { + gs_free char *vlan_str = NULL; + + vlan_str = nm_bridge_vlan_to_str(vlans->pdata[i], NULL); + if (i > 0) + nm_str_buf_append_c(&string, ','); + nm_utils_escaped_tokens_escape_strbuf_assert(vlan_str, ",", &string); + } + + nm_keyfile_plugin_kf_set_string(info->keyfile, + nm_setting_get_name(setting), + "vlans", + nm_str_buf_get_str(&string)); + } +} + +static void +wired_s390_options_parser_full(KeyfileReaderInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) +{ + NMSettingWired * s_wired = NM_SETTING_WIRED(setting); + gs_strfreev char **keys = NULL; + gsize n_keys; + gsize i; + + keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, + ETHERNET_S390_OPTIONS_GROUP_NAME, + &n_keys, + NULL); + for (i = 0; i < n_keys; i++) { + gs_free char *value = NULL; + gs_free char *key_to_free = NULL; + + value = nm_keyfile_plugin_kf_get_string(info->keyfile, + ETHERNET_S390_OPTIONS_GROUP_NAME, + keys[i], + NULL); + if (!value) + continue; + + nm_setting_wired_add_s390_option(s_wired, + nm_keyfile_key_decode(keys[i], &key_to_free), + value); + } +} + +static void +wired_s390_options_writer_full(KeyfileWriterInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) +{ + NMSettingWired *s_wired = NM_SETTING_WIRED(setting); + guint i, n; + + n = nm_setting_wired_get_num_s390_options(s_wired); + for (i = 0; i < n; i++) { + gs_free char *key_to_free = NULL; + const char * opt_key; + const char * opt_val; + + nm_setting_wired_get_s390_option(s_wired, i, &opt_key, &opt_val); + nm_keyfile_plugin_kf_set_string(info->keyfile, + ETHERNET_S390_OPTIONS_GROUP_NAME, + nm_keyfile_key_encode(opt_key, &key_to_free), + opt_val); + } +} + +static void +ip_routing_rule_writer_full(KeyfileWriterInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) +{ + const char * setting_name = nm_setting_get_name(setting); + NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG(setting); + guint i, j, n; + char key_name_full[100] = "routing-rule"; + char * key_name_num = &key_name_full[NM_STRLEN("routing-rule")]; + + n = nm_setting_ip_config_get_num_routing_rules(s_ip); + j = 0; + for (i = 0; i < n; i++) { + NMIPRoutingRule *rule = nm_setting_ip_config_get_routing_rule(s_ip, i); + gs_free char * str = NULL; + + str = + nm_ip_routing_rule_to_string(rule, NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE, NULL, NULL); + if (!str) + continue; + + sprintf(key_name_num, "%u", ++j); + nm_keyfile_plugin_kf_set_string(info->keyfile, setting_name, key_name_full, str); + } +} + +static void +qdisc_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) +{ + nm_auto_free_gstring GString *key_name = NULL; + nm_auto_free_gstring GString *value_str = NULL; + GPtrArray * array; + guint i; + + array = g_value_get_boxed(value); + if (!array || !array->len) + return; + + for (i = 0; i < array->len; i++) { + NMTCQdisc *qdisc = array->pdata[i]; + + nm_gstring_prepare(&key_name); + nm_gstring_prepare(&value_str); + + g_string_append(key_name, "qdisc."); + _nm_utils_string_append_tc_parent(key_name, NULL, nm_tc_qdisc_get_parent(qdisc)); + _nm_utils_string_append_tc_qdisc_rest(value_str, qdisc); + + nm_keyfile_plugin_kf_set_string(info->keyfile, + NM_SETTING_TC_CONFIG_SETTING_NAME, + key_name->str, + value_str->str); + } +} + +static void +tfilter_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) +{ + nm_auto_free_gstring GString *key_name = NULL; + nm_auto_free_gstring GString *value_str = NULL; + GPtrArray * array; + guint i; + + array = g_value_get_boxed(value); + if (!array || !array->len) + return; + + for (i = 0; i < array->len; i++) { + NMTCTfilter *tfilter = array->pdata[i]; + + nm_gstring_prepare(&key_name); + nm_gstring_prepare(&value_str); + + g_string_append(key_name, "tfilter."); + _nm_utils_string_append_tc_parent(key_name, NULL, nm_tc_tfilter_get_parent(tfilter)); + _nm_utils_string_append_tc_tfilter_rest(value_str, tfilter, NULL); + + nm_keyfile_plugin_kf_set_string(info->keyfile, + NM_SETTING_TC_CONFIG_SETTING_NAME, + key_name->str, + value_str->str); + } +} + +static void +_writer_full_ovs_external_ids_data(KeyfileWriterInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting) +{ + GHashTable * hash; + NMUtilsNamedValue data_static[300u / sizeof(NMUtilsNamedValue)]; + gs_free NMUtilsNamedValue *data_free = NULL; + const NMUtilsNamedValue * data; + guint data_len; + char full_key_static[NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX) + 300u]; + guint i; + + nm_assert(NM_IS_SETTING_OVS_EXTERNAL_IDS(setting)); + nm_assert(nm_streq(property_info->name, NM_SETTING_OVS_EXTERNAL_IDS_DATA)); + + hash = _nm_setting_ovs_external_ids_get_data(NM_SETTING_OVS_EXTERNAL_IDS(setting)); + if (!hash) + return; + + data = nm_utils_named_values_from_strdict(hash, &data_len, data_static, &data_free); + if (data_len == 0) + return; + + memcpy(full_key_static, OVS_EXTERNAL_IDS_DATA_PREFIX, NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)); + + for (i = 0; i < data_len; i++) { + const char * key = data[i].name; + const char * val = data[i].value_str; + gs_free char *escaped_key_to_free = NULL; + const char * escaped_key; + gsize len; + gs_free char *full_key_free = NULL; + char * full_key = full_key_static; + + escaped_key = nm_keyfile_key_encode(key, &escaped_key_to_free); + + len = strlen(escaped_key) + 1u; + if (len >= G_N_ELEMENTS(full_key_static) - NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)) { + full_key_free = g_new(char, NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX) + len); + full_key = full_key_free; + memcpy(full_key, OVS_EXTERNAL_IDS_DATA_PREFIX, NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)); + } + memcpy(&full_key[NM_STRLEN(OVS_EXTERNAL_IDS_DATA_PREFIX)], escaped_key, len); + + nm_keyfile_plugin_kf_set_string(info->keyfile, + NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME, + full_key, + val); + } +} + +static void +write_hash_of_string(GKeyFile *file, NMSetting *setting, const char *key, const GValue *value) +{ + GHashTable * hash; + const char * group_name = nm_setting_get_name(setting); + gboolean vpn_secrets = FALSE; + gs_free const char **keys = NULL; + guint i, l; + + nm_assert((NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_DATA)) + || (NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_SECRETS)) + || (NM_IS_SETTING_BOND(setting) && nm_streq(key, NM_SETTING_BOND_OPTIONS)) + || (NM_IS_SETTING_USER(setting) && nm_streq(key, NM_SETTING_USER_DATA))); + + /* Write VPN secrets out to a different group to keep them separate */ + if (NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_SECRETS)) { + group_name = NM_KEYFILE_GROUP_VPN_SECRETS; + vpn_secrets = TRUE; + } + + hash = g_value_get_boxed(value); + + keys = nm_utils_strdict_get_keys(hash, TRUE, &l); + for (i = 0; i < l; i++) { + gs_free char *to_free = NULL; + const char * property, *data; + + property = keys[i]; + + /* Handle VPN secrets specially; they are nested in the property's hash; + * we don't want to write them if the secret is not saved, not required, + * or owned by a user's secret agent. + */ + if (vpn_secrets) { + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + if (!nm_setting_get_secret_flags(setting, property, &secret_flags, NULL)) + nm_assert_not_reached(); + if (!_secret_flags_persist_secret(secret_flags)) + continue; + } + + data = g_hash_table_lookup(hash, property); + nm_keyfile_plugin_kf_set_string(file, + group_name, + nm_keyfile_key_encode(property, &to_free), + data); + } +} + +static void +ssid_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) +{ + GBytes * bytes; + const guint8 *ssid_data; + gsize ssid_len; + const char * setting_name = nm_setting_get_name(setting); + gboolean new_format = TRUE; + gsize semicolons = 0; + gsize i; + + g_return_if_fail(G_VALUE_HOLDS(value, G_TYPE_BYTES)); + + bytes = g_value_get_boxed(value); + if (!bytes) + return; + ssid_data = g_bytes_get_data(bytes, &ssid_len); + if (!ssid_data || !ssid_len) { + nm_keyfile_plugin_kf_set_string(info->keyfile, setting_name, key, ""); + return; + } + + /* Check whether each byte is printable. If not, we have to use an + * integer list, otherwise we can just use a string. + */ + for (i = 0; i < ssid_len; i++) { + const char c = ssid_data[i]; + + if (!g_ascii_isprint(c)) { + new_format = FALSE; + break; + } + if (c == ';') + semicolons++; + } + + if (new_format) { + gs_free char *ssid = NULL; + + if (semicolons == 0) + ssid = g_strndup((char *) ssid_data, ssid_len); + else { + /* Escape semicolons with backslashes to make strings + * containing ';', such as '16;17;' unambiguous */ + gsize j = 0; + + ssid = g_malloc(ssid_len + semicolons + 1); + for (i = 0; i < ssid_len; i++) { + if (ssid_data[i] == ';') + ssid[j++] = '\\'; + ssid[j++] = ssid_data[i]; + } + ssid[j] = '\0'; + } + nm_keyfile_plugin_kf_set_string(info->keyfile, setting_name, key, ssid); + } else + nm_keyfile_plugin_kf_set_integer_list_uint8(info->keyfile, + setting_name, + key, + ssid_data, + ssid_len); +} + +static void +password_raw_writer(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value) +{ + const char * setting_name = nm_setting_get_name(setting); + GBytes * array; + gsize len; + const guint8 *data; + + g_return_if_fail(G_VALUE_HOLDS(value, G_TYPE_BYTES)); + + array = (GBytes *) g_value_get_boxed(value); + if (!array) + return; + data = g_bytes_get_data(array, &len); + if (!data) + len = 0; + nm_keyfile_plugin_kf_set_integer_list_uint8(info->keyfile, setting_name, key, data, len); +} + +/*****************************************************************************/ + +static void +cert_writer_default(NMConnection * connection, + GKeyFile * file, + NMSetting8021x * setting, + const char * setting_name, + const NMSetting8021xSchemeVtable *vtable) +{ + NMSetting8021xCKScheme scheme; + + scheme = vtable->scheme_func(setting); + if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { + gs_free char *path_free = NULL; + gs_free char *base_dir = NULL; + gs_free char *tmp = NULL; + const char * path; + + path = vtable->path_func(setting); + g_assert(path); + + /* If the path is relative, make it an absolute path. + * Relative paths make a keyfile not easily usable in another + * context. */ + if (path[0] && path[0] != '/') { + base_dir = g_get_current_dir(); + path_free = g_strconcat(base_dir, "/", path, NULL); + path = path_free; + } else + base_dir = g_path_get_dirname(path); + + /* path cannot start with "file://" or "data:;base64,", because it is an absolute path. + * Still, make sure that a prefix-less path will be recognized. This can happen + * for example if the path is longer then 500 chars. */ + tmp = nm_keyfile_detect_unqualified_path_scheme(base_dir, path, -1, FALSE, NULL); + if (tmp) + nm_clear_g_free(&tmp); + else { + tmp = g_strconcat(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL); + path = tmp; + } + + /* 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, vtable->setting_key, path); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { + GBytes * blob; + const guint8 *blob_data; + gsize blob_len; + gs_free char *blob_base64 = NULL; + gs_free char *val = NULL; + + blob = vtable->blob_func(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, vtable->setting_key, val); + } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { + nm_keyfile_plugin_kf_set_string(file, + setting_name, + vtable->setting_key, + vtable->uri_func(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 + * case, we don't expect the writer to be called, because the default value + * will not be serialized. + * The only other reason for the scheme to be UNKNOWN is an invalid cert. + * But our connection verifies, so that cannot happen either. */ + g_return_if_reached(); + } +} + +static void +cert_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) +{ + const NMSetting8021xSchemeVtable *vtable = NULL; + const char * setting_name; + guint i; + + for (i = 0; nm_setting_8021x_scheme_vtable[i].setting_key; i++) { + if (nm_streq0(nm_setting_8021x_scheme_vtable[i].setting_key, key)) { + vtable = &nm_setting_8021x_scheme_vtable[i]; + break; + } + } + if (!vtable) + g_return_if_reached(); + + setting_name = nm_setting_get_name(NM_SETTING(setting)); + + if (info->write_handler) { + NMKeyfileHandlerData handler_data; + + _key_file_handler_data_init_write(&handler_data, + NM_KEYFILE_HANDLER_TYPE_WRITE_CERT, + info, + setting_name, + vtable->setting_key, + setting, + key); + handler_data.write_cert = (NMKeyfileHandlerDataWriteCert){ + .vtable = vtable, + }; + + if (info->write_handler(info->connection, + info->keyfile, + NM_KEYFILE_HANDLER_TYPE_WRITE_CERT, + &handler_data, + info->user_data)) + return; + if (info->error) + return; + } + + cert_writer_default(info->connection, + info->keyfile, + NM_SETTING_802_1X(setting), + setting_name, + vtable); +} + +/*****************************************************************************/ + +struct _ParseInfoProperty { + const char *property_name; + union { + void (*parser)(KeyfileReaderInfo *info, NMSetting *setting, const char *key); + void (*parser_full)(KeyfileReaderInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting); + }; + union { + void (*writer)(KeyfileWriterInfo *info, + NMSetting * setting, + const char * key, + const GValue * value); + void (*writer_full)(KeyfileWriterInfo * info, + const NMMetaSettingInfo * setting_info, + const NMSettInfoProperty *property_info, + const ParseInfoProperty * pip, + NMSetting * setting); + }; + bool parser_skip; + bool parser_no_check_key : 1; + bool writer_skip : 1; + bool has_writer_full : 1; + bool has_parser_full : 1; + + /* usually, we skip to write values that have their + * default value. By setting this flag to TRUE, also + * default values are written. */ + bool writer_persist_default : 1; +}; + +#define PARSE_INFO_PROPERTY(_property_name, ...) \ + (&((const ParseInfoProperty){.property_name = _property_name, __VA_ARGS__})) + +#define PARSE_INFO_PROPERTIES(...) \ + .properties = ((const ParseInfoProperty *const[]){ \ + __VA_ARGS__ NULL, \ + }) + +typedef struct { + const ParseInfoProperty *const *properties; +} ParseInfoSetting; + +#define PARSE_INFO_SETTING(setting_type, ...) \ + [setting_type] = (&((const ParseInfoSetting){__VA_ARGS__})) + +static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_WIRELESS, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_BSSID, .parser = mac_address_parser_ETHER, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, + .parser = mac_address_parser_ETHER_cloned, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_MAC_ADDRESS, + .parser = mac_address_parser_ETHER, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_SSID, + .parser = ssid_parser, + .writer = ssid_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_802_1X, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_802_1X_CA_CERT, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_CLIENT_CERT, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PASSWORD_RAW, + .parser = password_raw_parser, + .writer = password_raw_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PHASE2_CA_CERT, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PHASE2_CLIENT_CERT, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, + .parser = cert_parser, + .writer = cert_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PRIVATE_KEY, + .parser = cert_parser, + .writer = cert_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_WIRED, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_WIRED_CLONED_MAC_ADDRESS, + .parser = mac_address_parser_ETHER_cloned, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRED_MAC_ADDRESS, .parser = mac_address_parser_ETHER, ), + PARSE_INFO_PROPERTY(NM_SETTING_WIRED_S390_OPTIONS, + .parser_no_check_key = TRUE, + .parser_full = wired_s390_options_parser_full, + .writer_full = wired_s390_options_writer_full, + .has_parser_full = TRUE, + .has_writer_full = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_BLUETOOTH, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BLUETOOTH_BDADDR, + .parser = mac_address_parser_ETHER, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_BOND, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_BOND_OPTIONS, .parser_no_check_key = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_BRIDGE, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_MAC_ADDRESS, + .parser = mac_address_parser_ETHER, ), + PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_VLANS, + .parser_no_check_key = TRUE, + .parser = bridge_vlan_parser, + .writer = bridge_vlan_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_BRIDGE_PORT, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_PORT_VLANS, + .parser_no_check_key = TRUE, + .parser = bridge_vlan_parser, + .writer = bridge_vlan_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_CONNECTION, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_CONNECTION_READ_ONLY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_CONNECTION_TYPE, + .parser = setting_alias_parser, + .writer = setting_alias_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_INFINIBAND, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_INFINIBAND_MAC_ADDRESS, + .parser = mac_address_parser_INFINIBAND, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_IP4_CONFIG, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ADDRESSES, + .parser_no_check_key = TRUE, + .parser = ip_address_or_route_parser, + .writer = addr_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS, + .parser_no_check_key = TRUE, + .parser = ip_dns_parser, + .writer = dns_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, + .parser_no_check_key = TRUE, + .parser = ip_address_or_route_parser, + .writer = route_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTING_RULES, + .parser_no_check_key = TRUE, + .parser_full = ip_routing_rule_parser_full, + .writer_full = ip_routing_rule_writer_full, + .has_parser_full = TRUE, + .has_writer_full = TRUE, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_IP6_CONFIG, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, + .parser_no_check_key = TRUE, + .parser = ip6_addr_gen_mode_parser, + .writer = ip6_addr_gen_mode_writer, + .writer_persist_default = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ADDRESSES, + .parser_no_check_key = TRUE, + .parser = ip_address_or_route_parser, + .writer = addr_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS, + .parser_no_check_key = TRUE, + .parser = ip_dns_parser, + .writer = dns_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, + .parser_no_check_key = TRUE, + .parser = ip_address_or_route_parser, + .writer = route_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTING_RULES, + .parser_no_check_key = TRUE, + .parser_full = ip_routing_rule_parser_full, + .writer_full = ip_routing_rule_writer_full, + .has_parser_full = TRUE, + .has_writer_full = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_OVS_EXTERNAL_IDS_DATA, + .parser_no_check_key = TRUE, + .parser_full = _parser_full_ovs_external_ids_data, + .writer_full = _writer_full_ovs_external_ids_data, + .has_parser_full = TRUE, + .has_writer_full = TRUE, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_SERIAL, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_SERIAL_PARITY, + .parser = parity_parser, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_SRIOV, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_SRIOV_VFS, + .parser_no_check_key = TRUE, + .parser = sriov_vfs_parser, + .writer = sriov_vfs_writer, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_TC_CONFIG, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_TC_CONFIG_QDISCS, + .parser_no_check_key = TRUE, + .parser = qdisc_parser, + .writer = qdisc_writer, ), + PARSE_INFO_PROPERTY(NM_SETTING_TC_CONFIG_TFILTERS, + .parser_no_check_key = TRUE, + .parser = tfilter_parser, + .writer = tfilter_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_TEAM, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_CONFIG, .parser = team_config_parser, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_LINK_WATCHERS, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_MCAST_REJOIN_COUNT, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER, .parser_skip = TRUE, .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_ACTIVE, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_FAST_RATE, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_MIN_PORTS, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_SYS_PRIO, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_TX_BALANCER, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_TX_HASH, + .parser_skip = TRUE, + .writer_skip = TRUE, ), ), ), + PARSE_INFO_SETTING(NM_META_SETTING_TYPE_TEAM_PORT, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_TEAM_CONFIG, + .parser = team_config_parser, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_LACP_KEY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_LACP_PRIO, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_LINK_WATCHERS, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_PRIO, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_QUEUE_ID, + .parser_skip = TRUE, + .writer_skip = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_STICKY, + .parser_skip = TRUE, + .writer_skip = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_USER, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_USER_DATA, .parser_no_check_key = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_VLAN, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_VLAN_FLAGS, .writer_persist_default = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_VPN, + PARSE_INFO_PROPERTIES( + PARSE_INFO_PROPERTY(NM_SETTING_VPN_DATA, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_PERSISTENT, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_SECRETS, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_SERVICE_TYPE, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_TIMEOUT, .parser_no_check_key = TRUE, ), + PARSE_INFO_PROPERTY(NM_SETTING_VPN_USER_NAME, .parser_no_check_key = TRUE, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_WIMAX, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_WIMAX_MAC_ADDRESS, + .parser = mac_address_parser_ETHER, ), ), ), +}; + +static void +_parse_info_find(NMSetting * setting, + const char * property_name, + const NMMetaSettingInfo **out_setting_info, + const ParseInfoSetting ** out_parse_info_setting, + const ParseInfoProperty **out_parse_info_property) +{ + const NMMetaSettingInfo *setting_info; + const ParseInfoSetting * pis; + const ParseInfoProperty *pip; + +#if NM_MORE_ASSERTS > 10 + { + guint i, j; + static int asserted = FALSE; + + if (!asserted) { + for (i = 0; i < G_N_ELEMENTS(parse_infos); i++) { + pis = parse_infos[i]; + + if (!pis) + continue; + if (!pis->properties) + continue; + + g_assert(pis->properties[0]); + for (j = 0; pis->properties[j]; j++) { + const ParseInfoProperty *pip0; + const ParseInfoProperty *pipj = pis->properties[j]; + + g_assert(pipj->property_name); + if (j > 0 && (pip0 = pis->properties[j - 1]) + && strcmp(pip0->property_name, pipj->property_name) >= 0) { + g_error("Wrong order at index #%d.%d: \"%s.%s\" before \"%s.%s\"", + i, + j - 1, + nm_meta_setting_infos[i].setting_name, + pip0->property_name, + nm_meta_setting_infos[i].setting_name, + pipj->property_name); + } + } + } + asserted = TRUE; + } + } +#endif + + if (!NM_IS_SETTING(setting) || !(setting_info = NM_SETTING_GET_CLASS(setting)->setting_info)) { + /* handle invalid setting objects gracefully. */ + NM_SET_OUT(out_setting_info, NULL); + NM_SET_OUT(out_parse_info_setting, NULL); + NM_SET_OUT(out_parse_info_property, NULL); + return; + } + + nm_assert(setting_info->setting_name); + nm_assert(_NM_INT_NOT_NEGATIVE(setting_info->meta_type)); + nm_assert(setting_info->meta_type < G_N_ELEMENTS(parse_infos)); + + pis = parse_infos[setting_info->meta_type]; + + pip = NULL; + if (pis && property_name) { + gssize idx; + + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(ParseInfoProperty, property_name) == 0); + + idx = nm_utils_ptrarray_find_binary_search((gconstpointer *) pis->properties, + NM_PTRARRAY_LEN(pis->properties), + &property_name, + nm_strcmp_p_with_data, + NULL, + NULL, + NULL); + if (idx >= 0) + pip = pis->properties[idx]; + } + + NM_SET_OUT(out_setting_info, setting_info); + NM_SET_OUT(out_parse_info_setting, pis); + NM_SET_OUT(out_parse_info_property, pip); +} + +/*****************************************************************************/ + +static void +read_one_setting_value(KeyfileReaderInfo * info, + NMSetting * setting, + const NMSettInfoProperty *property_info) +{ + GKeyFile * keyfile = info->keyfile; + gs_free_error GError * err = NULL; + const NMMetaSettingInfo *setting_info; + const ParseInfoProperty *pip; + gs_free char * tmp_str = NULL; + const char * key; + GType type; + guint64 u64; + gint64 i64; + + nm_assert(!info->error); + nm_assert(!property_info->param_spec + || nm_streq(property_info->param_spec->name, property_info->name)); + + key = property_info->name; + + _parse_info_find(setting, key, &setting_info, NULL, &pip); + + nm_assert(setting_info); + + if (!pip) { + if (nm_streq(key, NM_SETTING_NAME)) + return; + if (!property_info->param_spec) + return; + if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) + != G_PARAM_WRITABLE) + return; + } else { + if (pip->parser_skip) + return; + if (pip->has_parser_full) { + pip->parser_full(info, setting_info, property_info, pip, setting); + return; + } + } + + nm_assert(property_info->param_spec); + nm_assert((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) + == G_PARAM_WRITABLE); + + /* Check for the exact key in the GKeyFile if required. Most setting + * properties map 1:1 to a key in the GKeyFile, but for those properties + * like IP addresses and routes where more than one value is actually + * encoded by the setting property, this won't be true. + */ + if ((!pip || !pip->parser_no_check_key) + && !nm_keyfile_plugin_kf_has_key(keyfile, setting_info->setting_name, key, &err)) { + /* Key doesn't exist or an error occurred, thus nothing to do. */ + if (err) { + if (!handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("error loading setting value: %s"), + err->message)) + return; + } + return; + } + + if (pip && pip->parser) { + pip->parser(info, setting, key); + return; + } + + type = G_PARAM_SPEC_VALUE_TYPE(property_info->param_spec); + + if (type == G_TYPE_STRING) { + gs_free char *str_val = NULL; + + str_val = nm_keyfile_plugin_kf_get_string(keyfile, setting_info->setting_name, key, &err); + if (!err) + nm_g_object_set_property_string_take(G_OBJECT(setting), + key, + g_steal_pointer(&str_val), + &err); + } else if (type == G_TYPE_UINT) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + u64 = _nm_utils_ascii_str_to_uint64(tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64); + if (u64 == G_MAXUINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_uint(G_OBJECT(setting), key, u64, &err); + } + } else if (type == G_TYPE_INT) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT, G_MAXINT, G_MININT64); + if (i64 == G_MININT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_int(G_OBJECT(setting), key, i64, &err); + } + } else if (type == G_TYPE_BOOLEAN) { + gboolean bool_val; + + bool_val = nm_keyfile_plugin_kf_get_boolean(keyfile, setting_info->setting_name, key, &err); + if (!err) + nm_g_object_set_property_boolean(G_OBJECT(setting), key, bool_val, &err); + } else if (type == G_TYPE_CHAR) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + /* As documented by glib, G_TYPE_CHAR is really a (signed!) gint8. */ + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT8, G_MAXINT8, G_MININT64); + if (i64 == G_MININT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_char(G_OBJECT(setting), key, i64, &err); + } + } else if (type == G_TYPE_UINT64) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + u64 = _nm_utils_ascii_str_to_uint64(tmp_str, 0, 0, G_MAXUINT64, G_MAXUINT64); + if (u64 == G_MAXUINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_uint64(G_OBJECT(setting), key, u64, &err); + } + } else if (type == G_TYPE_INT64) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT64, G_MAXINT64, G_MAXINT64); + if (i64 == G_MAXINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_int64(G_OBJECT(setting), key, i64, &err); + } + } else if (type == G_TYPE_BYTES) { + nm_auto_unref_bytearray GByteArray *array = NULL; + gs_unref_bytes GBytes *bytes = NULL; + gs_free guint *tmp = NULL; + gsize length; + int i; + gboolean already_warned = FALSE; + + tmp = nm_keyfile_plugin_kf_get_integer_list_uint(keyfile, + setting_info->setting_name, + key, + &length, + NULL); + + array = g_byte_array_sized_new(length); + for (i = 0; i < length; i++) { + const guint val = tmp[i]; + unsigned char v = (unsigned char) (val & 0xFF); + + if (val > 255u) { + if (!already_warned + && !handle_warn( + info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid byte element '%u' (not between 0 and 255 inclusive)"), + val)) + return; + already_warned = TRUE; + } else + g_byte_array_append(array, (const unsigned char *) &v, sizeof(v)); + } + + bytes = g_byte_array_free_to_bytes(g_steal_pointer(&array)); + g_object_set(setting, key, bytes, NULL); + } else if (type == G_TYPE_STRV) { + gs_strfreev char **sa = NULL; + gsize length; + + sa = nm_keyfile_plugin_kf_get_string_list(keyfile, + setting_info->setting_name, + key, + &length, + NULL); + g_object_set(setting, key, sa, NULL); + } else if (type == G_TYPE_HASH_TABLE) { + read_hash_of_string(info, keyfile, setting, key); + } else if (type == G_TYPE_ARRAY) { + read_array_of_uint(keyfile, setting, key); + } else if (G_TYPE_IS_FLAGS(type)) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + u64 = _nm_utils_ascii_str_to_uint64(tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64); + if (u64 == G_MAXUINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_flags(G_OBJECT(setting), key, type, u64, &err); + } + } else if (G_TYPE_IS_ENUM(type)) { + tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); + if (!err) { + i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT, G_MAXINT, G_MAXINT64); + if (i64 == G_MAXINT64 && errno != 0) { + g_set_error_literal(&err, + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_INVALID_VALUE, + _("value cannot be interpreted as integer")); + } else + nm_g_object_set_property_enum(G_OBJECT(setting), key, type, i64, &err); + } + } else + g_return_if_reached(); + + if (err) { + if (nm_keyfile_error_is_not_found(err)) { + /* ignore such errors. The key is not present. */ + } else { + handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid setting: %s"), + err->message); + } + } +} + +static void +_read_setting(KeyfileReaderInfo *info) +{ + const NMSettInfoSetting *sett_info; + gs_unref_object NMSetting *setting = NULL; + const char * alias; + GType type; + guint i; + + alias = nm_keyfile_plugin_get_setting_name_for_alias(info->group); + if (!alias) + alias = info->group; + + type = nm_setting_lookup_type(alias); + if (!type) { + handle_warn(info, + NULL, + NULL, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid setting name '%s'"), + info->group); + return; + } + + setting = g_object_new(type, NULL); + + info->setting = setting; + + sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting)); + + if (sett_info->detail.gendata_info) { + gs_free char **keys = NULL; + gsize k, n_keys; + + keys = g_key_file_get_keys(info->keyfile, info->group, &n_keys, NULL); + if (!keys) + n_keys = 0; + if (n_keys > 0) { + GHashTable *h = _nm_setting_option_hash(setting, TRUE); + + nm_utils_strv_sort(keys, n_keys); + for (k = 0; k < n_keys; k++) { + gs_free char *key = keys[k]; + gs_free_error GError *local = NULL; + const GVariantType * variant_type; + GVariant * variant; + + /* a GKeyFile can return duplicate keys, there is just no API to make sense + * of them. Skip them. */ + if (k + 1 < n_keys && nm_streq(key, keys[k + 1])) + continue; + + /* currently, the API is very simple. The setting class just returns + * the desired variant type, and keyfile reader will try to parse + * it accordingly. Note, that this does currently not allow, that + * a particular key can contain different variant types, nor is it + * very flexible in general. + * + * We add flexibility when we need it. Keep it simple for now. */ + variant_type = + sett_info->detail.gendata_info->get_variant_type(sett_info, key, &local); + if (!variant_type) { + if (!handle_warn(info, + key, + NULL, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key '%s.%s'"), + info->group, + key)) + break; + continue; + } + + if (g_variant_type_equal(variant_type, G_VARIANT_TYPE_BOOLEAN)) { + gboolean v; + + v = g_key_file_get_boolean(info->keyfile, info->group, key, &local); + if (local) { + if (!handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not boolean"), + info->group, + key)) + break; + continue; + } + variant = g_variant_new_boolean(v); + } else if (g_variant_type_equal(variant_type, G_VARIANT_TYPE_UINT32)) { + guint64 v; + + v = g_key_file_get_uint64(info->keyfile, info->group, key, &local); + + if (local) { + if (!handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a uint32"), + info->group, + key)) + break; + continue; + } + variant = g_variant_new_uint32((guint32) v); + } else { + nm_assert_not_reached(); + continue; + } + + g_hash_table_insert(h, g_steal_pointer(&key), g_variant_take_ref(variant)); + } + for (; k < n_keys; k++) + g_free(keys[k]); + } + } + + for (i = 0; i < sett_info->property_infos_len; i++) { + read_one_setting_value(info, setting, &sett_info->property_infos[i]); + if (info->error) + goto out; + } + +out: + info->setting = NULL; + if (!info->error) + nm_connection_add_setting(info->connection, g_steal_pointer(&setting)); +} + +static void +_read_setting_wireguard_peer(KeyfileReaderInfo *info) +{ + gs_unref_object NMSettingWireGuard *s_wg_new = NULL; + nm_auto_unref_wgpeer NMWireGuardPeer *peer = NULL; + gs_free_error GError *error = NULL; + NMSettingWireGuard * s_wg; + gs_free char * str = NULL; + const char * cstr = NULL; + const char * key; + gint64 i64; + gs_strfreev char ** sa = NULL; + gsize n_sa; + + peer = nm_wireguard_peer_new(); + + nm_assert(g_str_has_prefix(info->group, NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)); + cstr = &info->group[NM_STRLEN(NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)]; + if (!nm_utils_base64secret_normalize(cstr, NM_WIREGUARD_PUBLIC_KEY_LEN, &str) + || !nm_streq0(str, cstr)) { + /* the group name must be identical to the normalized(!) key, so that it + * is uniquely identified. */ + handle_warn(info, + NULL, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid peer public key in section '%s'"), + info->group); + return; + } + nm_wireguard_peer_set_public_key(peer, cstr, TRUE); + nm_clear_g_free(&str); + + key = NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY; + str = nm_keyfile_plugin_kf_get_string(info->keyfile, info->group, key, NULL); + if (str) { + if (!nm_wireguard_peer_set_preshared_key(peer, str, FALSE)) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a valid 256 bit key in base64 encoding"), + info->group, + key)) + return; + } + nm_clear_g_free(&str); + } + + key = NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS; + i64 = nm_keyfile_plugin_kf_get_int64(info->keyfile, + info->group, + key, + 0, + 0, + NM_SETTING_SECRET_FLAG_ALL, + -1, + NULL); + if (errno != ENODATA) { + if (i64 == -1 || !_nm_setting_secret_flags_valid(i64)) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a valid secret flag"), + info->group, + key)) + return; + } else + nm_wireguard_peer_set_preshared_key_flags(peer, i64); + } + + key = NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE; + i64 = nm_keyfile_plugin_kf_get_int64(info->keyfile, + info->group, + key, + 0, + 0, + G_MAXUINT32, + -1, + NULL); + if (errno != ENODATA) { + if (i64 == -1) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a integer in range 0 to 2^32"), + info->group, + key)) + return; + } else + nm_wireguard_peer_set_persistent_keepalive(peer, i64); + } + + key = NM_WIREGUARD_PEER_ATTR_ENDPOINT; + str = nm_keyfile_plugin_kf_get_string(info->keyfile, info->group, key, NULL); + if (str && str[0]) { + if (!nm_wireguard_peer_set_endpoint(peer, str, FALSE)) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a valid endpoint"), + info->group, + key)) + return; + } + } + nm_clear_g_free(&str); + + key = NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS; + sa = nm_keyfile_plugin_kf_get_string_list(info->keyfile, info->group, key, &n_sa, NULL); + if (n_sa > 0) { + gboolean has_error = FALSE; + gsize i; + + for (i = 0; i < n_sa; i++) { + if (!nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, sa[i], NULL, NULL, NULL)) { + has_error = TRUE; + continue; + } + nm_wireguard_peer_append_allowed_ip(peer, sa[i], TRUE); + } + if (has_error) { + if (!handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' has invalid allowed-ips"), + info->group, + key)) + return; + } + } + + if (info->error) + return; + + if (!nm_wireguard_peer_is_valid(peer, TRUE, TRUE, &error)) { + handle_warn(info, + NULL, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("peer '%s' is invalid: %s"), + info->group, + error->message); + return; + } + + s_wg = NM_SETTING_WIREGUARD( + nm_connection_get_setting(info->connection, NM_TYPE_SETTING_WIREGUARD)); + if (!s_wg) { + s_wg_new = NM_SETTING_WIREGUARD(nm_setting_wireguard_new()); + s_wg = s_wg_new; + } + + nm_setting_wireguard_append_peer(s_wg, peer); + + if (s_wg_new) { + nm_connection_add_setting(info->connection, NM_SETTING(g_steal_pointer(&s_wg_new))); + } +} + +static void +_read_setting_vpn_secrets(KeyfileReaderInfo *info) +{ + gs_strfreev char **keys = NULL; + gsize i, n_keys; + NMSettingVpn * s_vpn; + + s_vpn = nm_connection_get_setting_vpn(info->connection); + if (!s_vpn) { + /* if we don't also have a [vpn] section (which must be parsed earlier), + * we don't do anything. */ + nm_assert(!g_key_file_has_group(info->keyfile, "vpn")); + return; + } + + keys = + nm_keyfile_plugin_kf_get_keys(info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, &n_keys, NULL); + for (i = 0; i < n_keys; i++) { + gs_free char *secret = NULL; + + secret = nm_keyfile_plugin_kf_get_string(info->keyfile, + NM_KEYFILE_GROUP_VPN_SECRETS, + keys[i], + NULL); + if (secret) + nm_setting_vpn_add_secret(s_vpn, keys[i], secret); + } +} + +gboolean +nm_keyfile_read_ensure_id(NMConnection *connection, const char *fallback_id) +{ + NMSettingConnection *s_con; + + g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); + g_return_val_if_fail(fallback_id, FALSE); + + s_con = nm_connection_get_setting_connection(connection); + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(s_con), FALSE); + + if (nm_setting_connection_get_id(s_con)) + return FALSE; + + g_object_set(s_con, NM_SETTING_CONNECTION_ID, fallback_id, NULL); + return TRUE; +} + +gboolean +nm_keyfile_read_ensure_uuid(NMConnection *connection, const char *fallback_uuid_seed) +{ + NMSettingConnection *s_con; + gs_free char * hashed_uuid = NULL; + + g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); + g_return_val_if_fail(fallback_uuid_seed, FALSE); + + s_con = nm_connection_get_setting_connection(connection); + g_return_val_if_fail(NM_IS_SETTING_CONNECTION(s_con), FALSE); + + if (nm_setting_connection_get_uuid(s_con)) + return FALSE; + + hashed_uuid = _nm_utils_uuid_generate_from_strings("keyfile", fallback_uuid_seed, NULL); + g_object_set(s_con, NM_SETTING_CONNECTION_UUID, hashed_uuid, NULL); + return TRUE; +} + +/** + * nm_keyfile_read: + * @keyfile: the keyfile from which to create the connection + * @base_dir: when reading certificates from files with relative name, + * the relative path is made absolute using @base_dir. This must + * be an absolute path. + * @handler_flags: the #NMKeyfileHandlerFlags. + * @handler: (allow-none) (scope call): read handler + * @user_data: user data for read handler + * @error: (allow-none) (out): error + * + * Tries to create a NMConnection from a keyfile. The resulting keyfile is + * not normalized and might not even verify. + * + * Returns: (transfer full): on success, returns the created connection. + * + * Since: 1.30 + */ +NMConnection * +nm_keyfile_read(GKeyFile * keyfile, + const char * base_dir, + NMKeyfileHandlerFlags handler_flags, + NMKeyfileReadHandler handler, + void * user_data, + GError ** error) +{ + gs_unref_object NMConnection *connection = NULL; + NMSettingConnection * s_con; + gs_strfreev char ** groups = NULL; + gsize n_groups; + gsize i; + gboolean vpn_secrets = FALSE; + KeyfileReaderInfo info; + + g_return_val_if_fail(keyfile, NULL); + g_return_val_if_fail(!error || !*error, NULL); + g_return_val_if_fail(base_dir && base_dir[0] == '/', NULL); + g_return_val_if_fail(handler_flags == NM_KEYFILE_HANDLER_FLAGS_NONE, NULL); + + connection = nm_simple_connection_new(); + + info = (KeyfileReaderInfo){ + .connection = connection, + .keyfile = keyfile, + .base_dir = base_dir, + .read_handler = handler, + .user_data = user_data, + }; + + groups = g_key_file_get_groups(keyfile, &n_groups); + if (!groups) + n_groups = 0; + + for (i = 0; i < n_groups; i++) { + info.group = groups[i]; + + if (nm_streq(groups[i], NM_KEYFILE_GROUP_VPN_SECRETS)) { + /* Only read out secrets when needed */ + vpn_secrets = TRUE; + } else if (NM_STR_HAS_PREFIX(groups[i], NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)) + _read_setting_wireguard_peer(&info); + else if (NM_IN_STRSET(groups[i], + NM_KEYFILE_GROUP_NMMETA, + ETHERNET_S390_OPTIONS_GROUP_NAME)) { + /* pass */ + } else + _read_setting(&info); + + info.group = NULL; + + if (info.error) + goto out_with_info_error; + } + + s_con = nm_connection_get_setting_connection(connection); + if (!s_con) { + s_con = NM_SETTING_CONNECTION(nm_setting_connection_new()); + nm_connection_add_setting(connection, NM_SETTING(s_con)); + } + + /* Make sure that we have 'interface-name' even if it was specified in the + * "wrong" (ie, deprecated) group. + */ + if (!nm_setting_connection_get_interface_name(s_con) + && nm_setting_connection_get_connection_type(s_con)) { + gs_free char *interface_name = NULL; + + interface_name = g_key_file_get_string(keyfile, + nm_setting_connection_get_connection_type(s_con), + "interface-name", + NULL); + if (interface_name) + g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL); + } + + if (vpn_secrets) { + info.group = NM_KEYFILE_GROUP_VPN_SECRETS; + _read_setting_vpn_secrets(&info); + info.group = NULL; + if (info.error) + goto out_with_info_error; + } + + return g_steal_pointer(&connection); + +out_with_info_error: + g_propagate_error(error, info.error); + return NULL; +} + +/*****************************************************************************/ + +static void +write_setting_value(KeyfileWriterInfo * info, + NMSetting * setting, + const NMSettInfoProperty *property_info) +{ + const NMMetaSettingInfo *setting_info; + const ParseInfoProperty *pip; + const char * key; + char numstr[64]; + GValue value; + GType type; + + nm_assert(!info->error); + nm_assert(!property_info->param_spec + || nm_streq(property_info->param_spec->name, property_info->name)); + + key = property_info->name; + + _parse_info_find(setting, key, &setting_info, NULL, &pip); + + if (!pip) { + if (!setting_info) { + /* the setting type is unknown. That is highly unexpected + * (and as this is currently only called from NetworkManager + * daemon, not possible). + * + * Still, handle it gracefully, because later keyfile writer will become + * public API of libnm, where @setting is (untrusted) user input. + * + * Gracefully here just means: ignore the setting. */ + return; + } + if (!property_info->param_spec) + return; + if (nm_streq(key, NM_SETTING_NAME)) + return; + } else { + if (pip->has_writer_full) { + pip->writer_full(info, setting_info, property_info, pip, setting); + return; + } + if (pip->writer_skip) + return; + } + + nm_assert(property_info->param_spec); + + /* Don't write secrets that are owned by user secret agents or aren't + * supposed to be saved. VPN secrets are handled specially though since + * the secret flags there are in a third-level hash in the 'secrets' + * property. + */ + if ((property_info->param_spec->flags & NM_SETTING_PARAM_SECRET) + && !NM_IS_SETTING_VPN(setting)) { + NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; + + if (!nm_setting_get_secret_flags(setting, key, &secret_flags, NULL)) + g_return_if_reached(); + if (!_secret_flags_persist_secret(secret_flags)) + return; + } + + value = (GValue){0}; + + g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(property_info->param_spec)); + g_object_get_property(G_OBJECT(setting), property_info->param_spec->name, &value); + + if ((!pip || !pip->writer_persist_default) + && g_param_value_defaults(property_info->param_spec, &value)) { + nm_assert(!g_key_file_has_key(info->keyfile, setting_info->setting_name, key, NULL)); + goto out_unset_value; + } + + if (pip && pip->writer) { + pip->writer(info, setting, key, &value); + goto out_unset_value; + } + + type = G_VALUE_TYPE(&value); + if (type == G_TYPE_STRING) { + const char *str; + + str = g_value_get_string(&value); + if (str) + nm_keyfile_plugin_kf_set_string(info->keyfile, setting_info->setting_name, key, str); + } else if (type == G_TYPE_UINT) { + nm_sprintf_buf(numstr, "%u", g_value_get_uint(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_INT) { + nm_sprintf_buf(numstr, "%d", g_value_get_int(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_UINT64) { + nm_sprintf_buf(numstr, "%" G_GUINT64_FORMAT, g_value_get_uint64(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_INT64) { + nm_sprintf_buf(numstr, "%" G_GINT64_FORMAT, g_value_get_int64(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_BOOLEAN) { + nm_keyfile_plugin_kf_set_value(info->keyfile, + setting_info->setting_name, + key, + g_value_get_boolean(&value) ? "true" : "false"); + } else if (type == G_TYPE_CHAR) { + nm_sprintf_buf(numstr, "%d", (int) g_value_get_schar(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (type == G_TYPE_BYTES) { + GBytes * bytes; + const guint8 *data; + gsize len = 0; + + bytes = g_value_get_boxed(&value); + data = bytes ? g_bytes_get_data(bytes, &len) : NULL; + + if (data != NULL && len > 0) + nm_keyfile_plugin_kf_set_integer_list_uint8(info->keyfile, + setting_info->setting_name, + key, + data, + len); + } else if (type == G_TYPE_STRV) { + char **array; + + array = (char **) g_value_get_boxed(&value); + nm_keyfile_plugin_kf_set_string_list(info->keyfile, + setting_info->setting_name, + key, + (const char **const) array, + g_strv_length(array)); + } else if (type == G_TYPE_HASH_TABLE) { + write_hash_of_string(info->keyfile, setting, key, &value); + } else if (type == G_TYPE_ARRAY) { + write_array_of_uint(info->keyfile, setting, key, &value); + } else if (G_VALUE_HOLDS_FLAGS(&value)) { + nm_sprintf_buf(numstr, "%u", g_value_get_flags(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else if (G_VALUE_HOLDS_ENUM(&value)) { + nm_sprintf_buf(numstr, "%d", g_value_get_enum(&value)); + nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); + } else + g_return_if_reached(); + +out_unset_value: + g_value_unset(&value); +} + +static void +_write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info) +{ + NMSettingWireGuard *s_wg; + guint i_peer, n_peers; + + s_wg = NM_SETTING_WIREGUARD(setting); + + n_peers = nm_setting_wireguard_get_peers_len(s_wg); + for (i_peer = 0; i_peer < n_peers; i_peer++) { + NMWireGuardPeer * peer = nm_setting_wireguard_get_peer(s_wg, i_peer); + const char * public_key; + char group[NM_STRLEN(NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER) + 200]; + NMSettingSecretFlags secret_flags; + gboolean any_key = FALSE; + guint i_aip, n_aip; + const char * cstr; + guint32 u32; + + public_key = nm_wireguard_peer_get_public_key(peer); + if (!public_key || !public_key[0] + || !NM_STRCHAR_ALL(public_key, ch, nm_sd_utils_unbase64char(ch, TRUE) >= 0)) { + /* invalid peer. Skip it */ + continue; + } + + if (g_snprintf(group, + sizeof(group), + "%s%s", + NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER, + nm_wireguard_peer_get_public_key(peer)) + >= sizeof(group)) { + /* Too long. Not a valid public key. Skip the peer. */ + continue; + } + + cstr = nm_wireguard_peer_get_endpoint(peer); + if (cstr) { + g_key_file_set_string(info->keyfile, group, NM_WIREGUARD_PEER_ATTR_ENDPOINT, cstr); + any_key = TRUE; + } + + secret_flags = nm_wireguard_peer_get_preshared_key_flags(peer); + if (_secret_flags_persist_secret(secret_flags)) { + cstr = nm_wireguard_peer_get_preshared_key(peer); + if (cstr) { + g_key_file_set_string(info->keyfile, + group, + NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY, + cstr); + any_key = TRUE; + } + } + + /* usually, we don't persist the secret-flags 0 (because they are the default). + * For WireGuard peers, the default secret-flags for preshared-key are 4 (not-required). + * So, in this case behave differently: a missing preshared-key-flag setting means + * "not-required". */ + if (secret_flags != NM_SETTING_SECRET_FLAG_NOT_REQUIRED) { + g_key_file_set_int64(info->keyfile, + group, + NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS, + secret_flags); + any_key = TRUE; + } + + u32 = nm_wireguard_peer_get_persistent_keepalive(peer); + if (u32) { + g_key_file_set_uint64(info->keyfile, + group, + NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE, + u32); + any_key = TRUE; + } + + n_aip = nm_wireguard_peer_get_allowed_ips_len(peer); + if (n_aip > 0) { + gs_free const char **strv = NULL; + + strv = g_new(const char *, ((gsize) n_aip) + 1); + for (i_aip = 0; i_aip < n_aip; i_aip++) + strv[i_aip] = nm_wireguard_peer_get_allowed_ip(peer, i_aip, NULL); + strv[n_aip] = NULL; + g_key_file_set_string_list(info->keyfile, + group, + NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS, + strv, + n_aip); + any_key = TRUE; + } + + if (!any_key) { + /* we cannot omit all keys. At an empty endpoint. */ + g_key_file_set_string(info->keyfile, group, NM_WIREGUARD_PEER_ATTR_ENDPOINT, ""); + } + } +} + +/** + * nm_keyfile_write: + * @connection: the #NMConnection to persist to keyfile. + * @handler_flags: the #NMKeyfileHandlerFlags. + * @handler: (allow-none) (scope call): optional handler for events and + * to override the default behavior. + * @user_data: argument for @handler. + * @error: the #GError in case writing fails. + * + * @connection must verify as a valid profile according to + * nm_connection_verify(). + * + * Returns: (transfer full): a new #GKeyFile or %NULL on error. + * + * Since: 1.30 + */ +GKeyFile * +nm_keyfile_write(NMConnection * connection, + NMKeyfileHandlerFlags handler_flags, + NMKeyfileWriteHandler handler, + void * user_data, + GError ** error) +{ + nm_auto_unref_keyfile GKeyFile *keyfile = NULL; + GError * local = NULL; + KeyfileWriterInfo info; + gs_free NMSetting **settings = NULL; + guint n_settings = 0; + guint i; + guint j; + + g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL); + g_return_val_if_fail(!error || !*error, NULL); + g_return_val_if_fail(handler_flags == NM_KEYFILE_HANDLER_FLAGS_NONE, NULL); + + /* Technically, we might not require that a profile is valid in + * order to serialize it. Like also nm_keyfile_read() does not + * ensure that the read profile validates. + * + * However, if the profile does not validate, then there might be + * unexpected edge cases when we try to serialize it. Edge cases + * that might result in dangerous crash. + * + * So, for now we require valid profiles. */ + if (!nm_connection_verify(connection, error ? &local : NULL)) { + if (error) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("the profile is not valid: %s"), + local->message); + g_error_free(local); + } else + nm_assert(!local); + return NULL; + } + + keyfile = g_key_file_new(); + + info = (KeyfileWriterInfo){ + .connection = connection, + .keyfile = keyfile, + .error = NULL, + .write_handler = handler, + .user_data = user_data, + }; + + settings = nm_connection_get_settings(connection, &n_settings); + for (i = 0; i < n_settings; i++) { + const NMSettInfoSetting *sett_info; + NMSetting * setting = settings[i]; + const char * setting_name; + const char * setting_alias; + + sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting)); + + setting_name = sett_info->setting_class->setting_info->setting_name; + + if (sett_info->detail.gendata_info) { + guint k, n_keys; + const char *const *keys; + + nm_assert(!nm_keyfile_plugin_get_alias_for_setting_name( + sett_info->setting_class->setting_info->setting_name)); + + n_keys = _nm_setting_option_get_all(setting, &keys, NULL); + + if (n_keys > 0) { + GHashTable *h = _nm_setting_option_hash(setting, FALSE); + + for (k = 0; k < n_keys; k++) { + const char *key = keys[k]; + GVariant * v; + + v = g_hash_table_lookup(h, key); + + if (g_variant_is_of_type(v, G_VARIANT_TYPE_BOOLEAN)) { + g_key_file_set_boolean(info.keyfile, + setting_name, + key, + g_variant_get_boolean(v)); + } else if (g_variant_is_of_type(v, G_VARIANT_TYPE_UINT32)) { + g_key_file_set_uint64(info.keyfile, + setting_name, + key, + (guint64) g_variant_get_uint32(v)); + } else { + /* BUG: The variant type is not implemented. Since the connection + * verifies, this can only mean we either wrongly didn't reject + * the connection as invalid, or we didn't properly implement the + * variant type. */ + nm_assert_not_reached(); + continue; + } + } + } + } + + for (j = 0; j < sett_info->property_infos_len; j++) { + const NMSettInfoProperty *property_info = + _nm_sett_info_property_info_get_sorted(sett_info, j); + + write_setting_value(&info, setting, property_info); + if (info.error) + goto out_with_info_error; + } + + setting_alias = nm_keyfile_plugin_get_alias_for_setting_name(setting_name); + if ((setting_alias && g_key_file_has_group(info.keyfile, setting_alias)) + || g_key_file_has_group(info.keyfile, setting_name)) { + /* we have a section for the setting. Nothing to do. */ + } else { + /* ensure the group is present. There is no API for that, so add and remove + * a dummy key. */ + g_key_file_set_value(info.keyfile, setting_alias ?: setting_name, ".X", "1"); + g_key_file_remove_key(info.keyfile, setting_alias ?: setting_name, ".X", NULL); + } + + if (NM_IS_SETTING_WIREGUARD(setting)) { + _write_setting_wireguard(setting, &info); + if (info.error) + goto out_with_info_error; + } + + nm_assert(!info.error); + } + + nm_assert(!info.error); + + return g_steal_pointer(&keyfile); + +out_with_info_error: + g_propagate_error(error, info.error); + return NULL; +} + +/*****************************************************************************/ + +static const char temp_letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + +/* + * Check '.[a-zA-Z0-9]{6}' file suffix used for temporary files by g_file_set_contents() (mkstemp()). + */ +static gboolean +check_mkstemp_suffix(const char *path) +{ + const char *ptr; + + nm_assert(path); + + /* Matches *.[a-zA-Z0-9]{6} suffix of mkstemp()'s temporary files */ + ptr = strrchr(path, '.'); + if (ptr && strspn(&ptr[1], temp_letters) == 6 && ptr[7] == '\0') + return TRUE; + return FALSE; +} + +#define SWP_TAG ".swp" +#define SWPX_TAG ".swpx" +#define PEM_TAG ".pem" +#define DER_TAG ".der" + +gboolean +nm_keyfile_utils_ignore_filename(const char *filename, gboolean require_extension) +{ + const char *base; + gsize l; + + /* ignore_filename() must mirror nm_keyfile_utils_create_filename() */ + + g_return_val_if_fail(filename, TRUE); + + base = strrchr(filename, '/'); + if (base) + base++; + else + base = filename; + + if (!base[0]) { + /* this check above with strrchr() also rejects "/some/path/with/trailing/slash/", + * but that is fine, because such a path would name a directory, and we are not + * interested in directories. */ + return TRUE; + } + + if (base[0] == '.') { + /* don't allow hidden files */ + return TRUE; + } + + if (require_extension) { + if (!NM_STR_HAS_SUFFIX_WITH_MORE(base, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)) + return TRUE; + return FALSE; + } + + l = strlen(base); + + /* Ignore backup files */ + if (base[l - 1] == '~') + return TRUE; + + /* Ignore temporary files + * + * This check is also important to ignore .nmload files (see + * %NM_KEYFILE_PATH_SUFFIX_NMMETA). */ + if (check_mkstemp_suffix(base)) + return TRUE; + + /* Ignore 802.1x certificates and keys */ + if (NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(base, PEM_TAG) + || NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(base, DER_TAG)) + return TRUE; + + return FALSE; +} + +char * +nm_keyfile_utils_create_filename(const char *name, gboolean with_extension) +{ + /* keyfile used to escape with '*', do not change that behavior. + * + * But for newly added escapings, use '_' instead. + * Also, @with_extension is new-style. */ + const char ESCAPE_CHAR = with_extension ? '_' : '*'; + const char ESCAPE_CHAR2 = '_'; + NMStrBuf str; + char * p; + gsize len; + gsize i; + + g_return_val_if_fail(name && name[0], NULL); + + nm_str_buf_init(&str, 0, FALSE); + + len = strlen(name); + + p = nm_str_buf_append_len0(&str, name, len); + + /* Convert '/' to ESCAPE_CHAR */ + for (i = 0; i < len; i++) { + if (p[i] == '/') + p[i] = ESCAPE_CHAR; + } + + /* nm_keyfile_utils_create_filename() must avoid anything that ignore_filename() would reject. + * We can escape here more aggressively then what we would read back. */ + if (p[0] == '.') + p[0] = ESCAPE_CHAR2; + if (p[str.len - 1] == '~') + p[str.len - 1] = ESCAPE_CHAR2; + + if (check_mkstemp_suffix(p) || NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(p, PEM_TAG) + || NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(p, DER_TAG)) + nm_str_buf_append_c(&str, ESCAPE_CHAR2); + + if (with_extension) + nm_str_buf_append(&str, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION); + + p = nm_str_buf_finalize(&str, NULL); + + /* nm_keyfile_utils_create_filename() must mirror ignore_filename() */ + nm_assert(!strchr(p, '/')); + nm_assert(!nm_keyfile_utils_ignore_filename(p, with_extension)); + + return p; +} + +/*****************************************************************************/ + +/** + * nm_keyfile_handler_data_fail_with_error: + * @handler_data: the #NMKeyfileHandlerData + * @src: (transfer full): error to move into the return location + * + * Set the error for the handler. This lets the operation fail + * with the provided error. You may only set the error once. + * + * @src must be non-%NULL. + * + * Note that @src is no longer valid after this call. If you want + * to keep using the same GError*, you need to set it to %NULL + * after calling this function on it. + * + * Since: 1.30 + */ +void +nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GError *src) +{ + g_return_if_fail(handler_data); + g_return_if_fail(handler_data->p_error && !*handler_data->p_error); + g_return_if_fail(src); + + *handler_data->p_error = src; +} + +/** + * nm_keyfile_handler_data_get_context: + * @handler_data: the #NMKeyfileHandlerData for any event. + * @out_kf_group_name: (out) (allow-none) (transfer none): if the event is in the + * context of a keyfile group, the group name. + * @out_kf_key_name: (out) (allow-none) (transfer none): if the event is in the + * context of a keyfile value, the key name. + * @out_cur_setting: (out) (allow-none) (transfer none): if the event happens while + * handling a particular #NMSetting instance. + * @out_cur_property_name: (out) (allow-none) (transfer none): the property name if applicable. + * + * Get context information of the current event. This function can be called + * on all events, but the context information may be unset. + * + * Since: 1.30 + */ +void +nm_keyfile_handler_data_get_context(const NMKeyfileHandlerData *handler_data, + const char ** out_kf_group_name, + const char ** out_kf_key_name, + NMSetting ** out_cur_setting, + const char ** out_cur_property_name) +{ + g_return_if_fail(handler_data); + + NM_SET_OUT(out_kf_group_name, handler_data->kf_group_name); + NM_SET_OUT(out_kf_key_name, handler_data->kf_key); + NM_SET_OUT(out_cur_setting, handler_data->cur_setting); + NM_SET_OUT(out_cur_property_name, handler_data->cur_property); +} + +const char * +_nm_keyfile_handler_data_warn_get_message(const NMKeyfileHandlerData *handler_data) +{ + nm_assert(handler_data); + nm_assert(handler_data->type == NM_KEYFILE_HANDLER_TYPE_WARN); + + if (!handler_data->warn.message) { + /* we cast the const away. @handler_data is const w.r.t. visible mutations + * from POV of the user. Internally, we construct the message in + * a lazy manner. It's like a mutable field in C++. */ + NM_PRAGMA_WARNING_DISABLE("-Wformat-nonliteral") + ((NMKeyfileHandlerData *) handler_data)->warn.message = + g_strdup_vprintf(handler_data->warn.fmt, + ((NMKeyfileHandlerData *) handler_data)->warn.ap); + NM_PRAGMA_WARNING_REENABLE + } + return handler_data->warn.message; +} + +/** + * nm_keyfile_handler_data_warn_get: + * @handler_data: the #NMKeyfileHandlerData for a %NM_KEYFILE_HANDLER_TYPE_WARN + * event. + * @out_message: (out) (allow-none) (transfer none): the warning message. + * @out_severity: (out) (allow-none): the #NMKeyfileWarnSeverity warning severity. + * + * Since: 1.30 + */ +void +nm_keyfile_handler_data_warn_get(const NMKeyfileHandlerData *handler_data, + const char ** out_message, + NMKeyfileWarnSeverity * out_severity) +{ + g_return_if_fail(handler_data); + g_return_if_fail(handler_data->type == NM_KEYFILE_HANDLER_TYPE_WARN); + + NM_SET_OUT(out_message, _nm_keyfile_handler_data_warn_get_message(handler_data)); + NM_SET_OUT(out_severity, handler_data->warn.severity); +} diff --git a/libnm-core/nm-keyfile.h b/libnm-core/nm-keyfile.h new file mode 100644 index 00000000..28c052f9 --- /dev/null +++ b/libnm-core/nm-keyfile.h @@ -0,0 +1,165 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NM_KEYFILE_H__ +#define __NM_KEYFILE_H__ + +#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION) + #error "Only can be included directly." +#endif + +#include "nm-core-types.h" + +G_BEGIN_DECLS + +/** + * NMKeyfileHandlerFlags: + * @NM_KEYFILE_HANDLER_FLAGS_NONE: no flags set. + * + * Flags for customizing nm_keyfile_read() and nm_keyfile_write(). + * + * Currently no flags are implemented. + * + * Since: 1.30 + */ +typedef enum { /*< flags >*/ + NM_KEYFILE_HANDLER_FLAGS_NONE = 0, +} NMKeyfileHandlerFlags; + +/** + * NMKeyfileHandlerType: + * @NM_KEYFILE_HANDLER_TYPE_WARN: a warning. + * @NM_KEYFILE_HANDLER_TYPE_WRITE_CERT: for handling certificates while writing + * a connection to keyfile. + * + * The type of the callback for %NMKeyfileReadHandler and %NMKeyfileWriteHandler. + * Depending on the type, you can interpret %NMKeyfileHandlerData. + * + * Since: 1.30 + */ +typedef enum { + NM_KEYFILE_HANDLER_TYPE_WARN = 1, + NM_KEYFILE_HANDLER_TYPE_WRITE_CERT = 2, +} NMKeyfileHandlerType; + +/** + * NMKeyfileHandlerData: + * + * Opaque type with parameters for the callback. The actual content + * depends on the %NMKeyfileHandlerType. + * + * Since: 1.30 + */ +typedef struct _NMKeyfileHandlerData NMKeyfileHandlerData; + +/** + * NMKeyfileReadHandler: + * @keyfile: the #GKeyFile that is currently read + * @connection: the #NMConnection that is being constructed. + * @handler_type: the %NMKeyfileHandlerType that indicates which type + * the request is. + * @handler_data: the #NMKeyfileHandlerData. What you can do with it + * depends on the @handler_type. + * @user_data: the user-data argument to nm_keyfile_read(). + * + * Hook to nm_keyfile_read(). + * + * The callee may abort the reading by setting an error via nm_keyfile_handler_data_fail_with_error(). + * + * Returns: the callee should return TRUE, if the event was handled and/or recognized. + * Otherwise, a default action will be performed that depends on the @type. + * For %NM_KEYFILE_HANDLER_TYPE_WARN type, the default action is doing nothing. + * + * Since: 1.30 + */ +typedef gboolean (*NMKeyfileReadHandler)(GKeyFile * keyfile, + NMConnection * connection, + NMKeyfileHandlerType handler_type, + NMKeyfileHandlerData *handler_data, + void * user_data); + +NM_AVAILABLE_IN_1_30 +NMConnection *nm_keyfile_read(GKeyFile * keyfile, + const char * base_dir, + NMKeyfileHandlerFlags handler_flags, + NMKeyfileReadHandler handler, + void * user_data, + GError ** error); + +/** + * NMKeyfileWriteHandler: + * @connection: the #NMConnection that is currently written. + * @keyfile: the #GKeyFile that is currently constructed. + * @handler_type: the %NMKeyfileHandlerType that indicates which type + * the request is. + * @handler_data: the #NMKeyfileHandlerData. What you can do with it + * depends on the @handler_type. + * @user_data: the user-data argument to nm_keyfile_read(). + * + * This is a hook to tweak the serialization. + * + * Handler for certain properties or events that are not entirely contained + * within the keyfile or that might be serialized differently. The @type and + * @handler_data arguments tell which kind of argument we have at hand. + * + * Currently only the type %NM_KEYFILE_HANDLER_TYPE_WRITE_CERT is supported. + * + * The callee may call nm_keyfile_handler_data_fail_with_error() to abort + * the writing with error. + * + * Returns: the callee should return %TRUE if the event was handled. If the + * event was unhandled, a default action will be performed that depends on + * the @handler_type. + * + * Since: 1.30 + */ +typedef gboolean (*NMKeyfileWriteHandler)(NMConnection * connection, + GKeyFile * keyfile, + NMKeyfileHandlerType handler_type, + NMKeyfileHandlerData *handler_data, + void * user_data); + +NM_AVAILABLE_IN_1_30 +GKeyFile *nm_keyfile_write(NMConnection * connection, + NMKeyfileHandlerFlags handler_flags, + NMKeyfileWriteHandler handler, + void * user_data, + GError ** error); + +/*****************************************************************************/ + +NM_AVAILABLE_IN_1_30 +void nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GError *src); + +NM_AVAILABLE_IN_1_30 +void nm_keyfile_handler_data_get_context(const NMKeyfileHandlerData *handler_data, + const char ** out_kf_group_name, + const char ** out_kf_key_name, + NMSetting ** out_cur_setting, + const char ** out_cur_property_name); + +/** + * NMKeyfileWarnSeverity: + * @NM_KEYFILE_WARN_SEVERITY_DEBUG: debug message + * @NM_KEYFILE_WARN_SEVERITY_INFO: info message + * @NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE: info message about a missing file + * @NM_KEYFILE_WARN_SEVERITY_WARN: a warning message + * + * The severity level of %NM_KEYFILE_HANDLER_TYPE_WARN events. + * + * Since: 1.30 + */ +typedef enum { + NM_KEYFILE_WARN_SEVERITY_DEBUG = 1000, + NM_KEYFILE_WARN_SEVERITY_INFO = 2000, + NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE = 2901, + NM_KEYFILE_WARN_SEVERITY_WARN = 3000, +} NMKeyfileWarnSeverity; + +NM_AVAILABLE_IN_1_30 +void nm_keyfile_handler_data_warn_get(const NMKeyfileHandlerData *handler_data, + const char ** out_message, + NMKeyfileWarnSeverity * out_severity); + +G_END_DECLS + +#endif /* __NM_KEYFILE_H__ */ diff --git a/libnm-core/nm-keyfile/nm-keyfile-internal.h b/libnm-core/nm-keyfile/nm-keyfile-internal.h deleted file mode 100644 index 77372f3a..00000000 --- a/libnm-core/nm-keyfile/nm-keyfile-internal.h +++ /dev/null @@ -1,213 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2008 Novell, Inc. - * Copyright (C) 2015 Red Hat, Inc. - */ - -#ifndef __NM_KEYFILE_INTERNAL_H__ -#define __NM_KEYFILE_INTERNAL_H__ - -#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) - #error Cannot use this header. -#endif - -#include - -#include "nm-connection.h" -#include "nm-setting-8021x.h" - -#include "nm-core-internal.h" -#include "nm-meta-setting.h" - -/*****************************************************************************/ - -#define NM_KEYFILE_CERT_SCHEME_PREFIX_PATH "file://" -#define NM_KEYFILE_CERT_SCHEME_PREFIX_PKCS11 "pkcs11:" -#define NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB "data:;base64," - -char *nm_keyfile_detect_unqualified_path_scheme(const char * base_dir, - gconstpointer pdata, - gsize data_len, - gboolean consider_exists, - gboolean * out_exists); - -typedef enum { /*< flags >*/ - NM_KEYFILE_HANDLER_FLAGS_NONE = 0, -} NMKeyfileHandlerFlags; - -typedef enum { - NM_KEYFILE_HANDLER_TYPE_WARN = 1, - NM_KEYFILE_HANDLER_TYPE_WRITE_CERT = 2, -} NMKeyfileHandlerType; - -typedef struct _NMKeyfileHandlerData NMKeyfileHandlerData; - -/** - * NMKeyfileReadHandler: - * - * Hook to nm_keyfile_read(). The user might fail the reading by setting - * @error. - * - * Returns: should return TRUE, if the reading was handled. Otherwise, - * a default action will be performed that depends on the @handler_type. - * For %NM_KEYFILE_HANDLER_TYPE_WARN handler_type, the default action is doing nothing. - */ -typedef gboolean (*NMKeyfileReadHandler)(GKeyFile * keyfile, - NMConnection * connection, - NMKeyfileHandlerType handler_type, - NMKeyfileHandlerData *handler_data, - void * user_data); - -typedef enum { - NM_KEYFILE_WARN_SEVERITY_DEBUG = 1000, - NM_KEYFILE_WARN_SEVERITY_INFO = 2000, - NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE = 2901, - NM_KEYFILE_WARN_SEVERITY_WARN = 3000, -} NMKeyfileWarnSeverity; - -NMConnection *nm_keyfile_read(GKeyFile * keyfile, - const char * base_dir, - NMKeyfileHandlerFlags handler_flags, - NMKeyfileReadHandler handler, - void * user_data, - GError ** error); - -gboolean nm_keyfile_read_ensure_id(NMConnection *connection, const char *fallback_id); - -gboolean nm_keyfile_read_ensure_uuid(NMConnection *connection, const char *fallback_uuid_seed); - -/*****************************************************************************/ - -/** - * NMKeyfileWriteHandler: - * - * This is a hook to tweak the serialization. - * - * Handler for certain properties or events that are not entirely contained - * within the keyfile or that might be serialized differently. The @handler_type and - * @handler_data arguments tell which kind of argument we have at hand. - * - * Currently only the handler_type %NM_KEYFILE_HANDLER_TYPE_WRITE_CERT is supported, which provides - * @handler_data as %NMKeyfileHandlerDataWriteCert. However, this handler should be generic enough - * to support other types as well. - * - * This don't have to be only "properties". For example, nm_keyfile_read() uses - * a similar handler to push warnings to the caller. - * - * If the handler raises an error, it should set the @error value. This causes - * the an overall failure. - * - * Returns: whether the issue was handled. If the type was unhandled, - * a default action will be performed. This might be raise an error, - * do some fallback parsing, or do nothing. - */ -typedef gboolean (*NMKeyfileWriteHandler)(NMConnection * connection, - GKeyFile * keyfile, - NMKeyfileHandlerType handler_type, - NMKeyfileHandlerData *handler_data, - void * user_data); - -GKeyFile *nm_keyfile_write(NMConnection * connection, - NMKeyfileHandlerFlags handler_flags, - NMKeyfileWriteHandler handler, - void * user_data, - GError ** error); - -/*****************************************************************************/ - -/** - * NMKeyfileHandlerDataWarn: - * - * this struct is passed as @handler_data for the @NMKeyfileReadHandler of - * handler_type %NM_KEYFILE_HANDLER_TYPE_WARN. - */ -typedef struct { - NMKeyfileWarnSeverity severity; - char * message; - const char * fmt; - va_list ap; -} NMKeyfileHandlerDataWarn; - -/** - * NMKeyfileHandlerDataWriteCert: - * - * this struct is passed as @handler_data for the @NMKeyfileWriteHandler of - * handler_type %NM_KEYFILE_HANDLER_TYPE_WRITE_CERT. - */ -typedef struct { - const NMSetting8021xSchemeVtable *vtable; -} NMKeyfileHandlerDataWriteCert; - -struct _NMKeyfileHandlerData { - NMKeyfileHandlerType type; - - GError **p_error; - - const char *kf_group_name; - const char *kf_key; - - NMSetting * cur_setting; - const char *cur_property; - - union { - NMKeyfileHandlerDataWarn warn; - NMKeyfileHandlerDataWriteCert write_cert; - }; -}; - -/*****************************************************************************/ - -void nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GError *src); - -void nm_keyfile_handler_data_get_context(const NMKeyfileHandlerData *handler_data, - const char ** out_kf_group_name, - const char ** out_kf_key_name, - NMSetting ** out_cur_setting, - const char ** out_cur_property_name); - -void nm_keyfile_handler_data_warn_get(const NMKeyfileHandlerData *handler_data, - const char ** out_message, - NMKeyfileWarnSeverity * out_severity); - -const char *_nm_keyfile_handler_data_warn_get_message(const NMKeyfileHandlerData *handler_data); - -/*****************************************************************************/ - -char * -nm_keyfile_plugin_kf_get_string(GKeyFile *kf, const char *group, const char *key, GError **error); -void nm_keyfile_plugin_kf_set_string(GKeyFile * kf, - const char *group, - const char *key, - const char *value); - -int nm_key_file_get_boolean(GKeyFile *kf, const char *group, const char *key, int default_value); - -void _nm_keyfile_copy(GKeyFile *dst, GKeyFile *src); -gboolean _nm_keyfile_a_contains_all_in_b(GKeyFile *kf_a, GKeyFile *kf_b); -gboolean _nm_keyfile_equals(GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order); -gboolean _nm_keyfile_has_values(GKeyFile *keyfile); - -/*****************************************************************************/ - -#define NM_KEYFILE_GROUP_NMMETA ".nmmeta" -#define NM_KEYFILE_KEY_NMMETA_NM_GENERATED "nm-generated" -#define NM_KEYFILE_KEY_NMMETA_VOLATILE "volatile" -#define NM_KEYFILE_KEY_NMMETA_EXTERNAL "external" -#define NM_KEYFILE_KEY_NMMETA_SHADOWED_STORAGE "shadowed-storage" -#define NM_KEYFILE_KEY_NMMETA_SHADOWED_OWNED "shadowed-owned" - -#define NM_KEYFILE_PATH_NAME_LIB NMLIBDIR "/system-connections" -#define NM_KEYFILE_PATH_NAME_ETC_DEFAULT NMCONFDIR "/system-connections" -#define NM_KEYFILE_PATH_NAME_RUN NMRUNDIR "/system-connections" - -#define NM_KEYFILE_PATH_SUFFIX_NMCONNECTION ".nmconnection" - -#define NM_KEYFILE_PATH_SUFFIX_NMMETA ".nmmeta" - -#define NM_KEYFILE_PATH_NMMETA_SYMLINK_NULL "/dev/null" - -gboolean nm_keyfile_utils_ignore_filename(const char *filename, gboolean require_extension); - -char *nm_keyfile_utils_create_filename(const char *filename, gboolean with_extension); - -#endif /* __NM_KEYFILE_INTERNAL_H__ */ diff --git a/libnm-core/nm-keyfile/nm-keyfile-utils.c b/libnm-core/nm-keyfile/nm-keyfile-utils.c deleted file mode 100644 index be12f8a8..00000000 --- a/libnm-core/nm-keyfile/nm-keyfile-utils.c +++ /dev/null @@ -1,682 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2010 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-keyfile-utils.h" - -#include - -#include "nm-glib-aux/nm-str-buf.h" - -#include "nm-keyfile-internal.h" -#include "nm-setting-wired.h" -#include "nm-setting-wireless.h" -#include "nm-setting-wireless-security.h" - -/*****************************************************************************/ - -/** - * nm_key_file_get_boolean: - * @kf: the #GKeyFile - * @group: the group - * @key: the key - * @default_value: the default value if the value is set or not parsable as a boolean. - * - * Replacement for g_key_file_get_boolean() (which uses g_key_file_parse_value_as_boolean()). - * g_key_file_get_boolean() seems odd to me, because it accepts trailing ASCII whitespace, - * but not leading. - * This uses _nm_utils_ascii_str_to_bool(), which accepts trailing and leading whitespace, - * case-insensitive words, and also strings like "on" and "off". - * _nm_utils_ascii_str_to_bool() is our way to parse booleans from string, and we should - * use that one consistently. - * - * Also, it doesn't have g_key_file_get_boolean()'s odd API to require an error argument - * to detect parsing failures. - * - * Returns: either %TRUE or %FALSE if the key exists and is parsable as a boolean. - * Otherwise, @default_value. Sets errno to ENODATA, EINVAL or 0, depending on whether - * the key exists, whether the value is invalid, or success. - */ -int -nm_key_file_get_boolean(GKeyFile *kf, const char *group, const char *key, int default_value) -{ - int v; - gs_free char *value = NULL; - - value = g_key_file_get_value(kf, group, key, NULL); - - if (!value) { - errno = ENODATA; - return default_value; - } - v = _nm_utils_ascii_str_to_bool(value, -1); - if (v != -1) { - errno = 0; - return v; - } - errno = EINVAL; - return default_value; -} - -/*****************************************************************************/ - -typedef struct { - const char *setting; - const char *alias; -} SettingAlias; - -static const SettingAlias alias_list[] = { - {NM_SETTING_WIRED_SETTING_NAME, "ethernet"}, - {NM_SETTING_WIRELESS_SETTING_NAME, "wifi"}, - {NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, "wifi-security"}, -}; - -const char * -nm_keyfile_plugin_get_alias_for_setting_name(const char *setting_name) -{ - guint i; - - g_return_val_if_fail(setting_name != NULL, NULL); - - for (i = 0; i < G_N_ELEMENTS(alias_list); i++) { - if (nm_streq(setting_name, alias_list[i].setting)) - return alias_list[i].alias; - } - return NULL; -} - -const char * -nm_keyfile_plugin_get_setting_name_for_alias(const char *alias) -{ - guint i; - - g_return_val_if_fail(alias != NULL, NULL); - - for (i = 0; i < G_N_ELEMENTS(alias_list); i++) { - if (nm_streq(alias, alias_list[i].alias)) - return alias_list[i].setting; - } - return NULL; -} - -/*****************************************************************************/ - -char ** -nm_keyfile_plugin_kf_get_string_list(GKeyFile * kf, - const char *group, - const char *key, - gsize * out_length, - GError ** error) -{ - char ** list; - const char *alias; - GError * local = NULL; - gsize l; - - list = g_key_file_get_string_list(kf, group, key, &l, &local); - if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); - if (alias) { - g_clear_error(&local); - list = g_key_file_get_string_list(kf, alias, key, &l, &local); - } - } - if (local) - g_propagate_error(error, local); - if (!list) - l = 0; - NM_SET_OUT(out_length, l); - return list; -} - -guint * -nm_keyfile_plugin_kf_get_integer_list_uint(GKeyFile * key_file, - const char *group_name, - const char *key, - gsize * out_length, - GError ** error) -{ - GError * key_file_error = NULL; - gs_strfreev char **values = NULL; - gs_free guint *int_values = NULL; - gsize i, num_ints; - - NM_SET_OUT(out_length, 0); - - g_return_val_if_fail(key_file != NULL, NULL); - g_return_val_if_fail(group_name != NULL, NULL); - g_return_val_if_fail(key != NULL, NULL); - - values = - nm_keyfile_plugin_kf_get_string_list(key_file, group_name, key, &num_ints, &key_file_error); - - if (key_file_error) - g_propagate_error(error, key_file_error); - if (!values) - return NULL; - - int_values = g_new(guint, num_ints); - - for (i = 0; i < num_ints; i++) { - gint64 v; - - G_STATIC_ASSERT_EXPR(sizeof(v) > sizeof(guint)); - v = _nm_utils_ascii_str_to_int64(values[i], 10, 0, G_MAXUINT, -1); - if (v == -1) { - g_set_error(error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("Value cannot be interpreted as a list of numbers.")); - return NULL; - } - - int_values[i] = v; - } - - NM_SET_OUT(out_length, num_ints); - return g_steal_pointer(&int_values); -} - -void -nm_keyfile_plugin_kf_set_string_list(GKeyFile * kf, - const char * group, - const char * key, - const char *const *list, - gsize length) -{ - const char *alias; - - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); - g_key_file_set_string_list(kf, alias ?: group, key, list, length); -} - -void -nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile * kf, - const char * group, - const char * key, - const guint *data, - gsize length) -{ - nm_auto_str_buf NMStrBuf strbuf = {}; - gsize i; - - g_return_if_fail(kf); - g_return_if_fail(!length || data); - g_return_if_fail(group && group[0]); - g_return_if_fail(key && key[0]); - - nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); - for (i = 0; i < length; i++) - nm_str_buf_append_printf(&strbuf, "%u;", data[i]); - nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); -} - -void -nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile * kf, - const char * group, - const char * key, - const guint8 *data, - gsize length) -{ - nm_auto_str_buf NMStrBuf strbuf = {}; - gsize i; - - g_return_if_fail(kf); - g_return_if_fail(!length || data); - g_return_if_fail(group && group[0]); - g_return_if_fail(key && key[0]); - - nm_str_buf_init(&strbuf, length * 4u + 2u, FALSE); - for (i = 0; i < length; i++) - nm_str_buf_append_printf(&strbuf, "%u;", (guint) data[i]); - nm_keyfile_plugin_kf_set_value(kf, group, key, nm_str_buf_get_str(&strbuf)); -} - -#define DEFINE_KF_WRAPPER_GET(fcn_name, get_ctype, key_file_get_fcn) \ - get_ctype fcn_name(GKeyFile *kf, const char *group, const char *key, GError **error) \ - { \ - get_ctype val; \ - const char *alias; \ - GError * local = NULL; \ - \ - val = key_file_get_fcn(kf, group, key, &local); \ - if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { \ - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); \ - if (alias) { \ - g_clear_error(&local); \ - val = key_file_get_fcn(kf, alias, key, &local); \ - } \ - } \ - if (local) \ - g_propagate_error(error, local); \ - return val; \ - } - -DEFINE_KF_WRAPPER_GET(nm_keyfile_plugin_kf_get_string, char *, g_key_file_get_string); -DEFINE_KF_WRAPPER_GET(nm_keyfile_plugin_kf_get_boolean, gboolean, g_key_file_get_boolean); -DEFINE_KF_WRAPPER_GET(nm_keyfile_plugin_kf_get_value, char *, g_key_file_get_value); - -#define DEFINE_KF_WRAPPER_SET(fcn_name, set_ctype, key_file_set_fcn) \ - void fcn_name(GKeyFile *kf, const char *group, const char *key, set_ctype value) \ - { \ - const char *alias; \ - \ - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); \ - key_file_set_fcn(kf, alias ?: group, key, value); \ - } - -DEFINE_KF_WRAPPER_SET(nm_keyfile_plugin_kf_set_string, const char *, g_key_file_set_string); -DEFINE_KF_WRAPPER_SET(nm_keyfile_plugin_kf_set_boolean, gboolean, g_key_file_set_boolean); -DEFINE_KF_WRAPPER_SET(nm_keyfile_plugin_kf_set_value, const char *, g_key_file_set_value); - -gint64 -nm_keyfile_plugin_kf_get_int64(GKeyFile * kf, - const char *group, - const char *key, - guint base, - gint64 min, - gint64 max, - gint64 fallback, - GError ** error) -{ - gs_free char *s = NULL; - int errsv; - gint64 v; - - s = nm_keyfile_plugin_kf_get_value(kf, group, key, error); - if (!s) { - errno = ENODATA; - return fallback; - } - - v = _nm_utils_ascii_str_to_int64(s, base, min, max, fallback); - errsv = errno; - if (errsv != 0 && error) { - g_set_error(error, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("value is not an integer in range [%lld, %lld]"), - (long long) min, - (long long) max); - errno = errsv; - } - return v; -} - -char ** -nm_keyfile_plugin_kf_get_keys(GKeyFile *kf, const char *group, gsize *out_length, GError **error) -{ - char ** keys; - const char *alias; - GError * local = NULL; - gsize l; - - keys = g_key_file_get_keys(kf, group, &l, &local); - if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); - if (alias) { - g_clear_error(&local); - keys = g_key_file_get_keys(kf, alias, &l, error ? &local : NULL); - } - } - nm_assert((!local) != (!keys)); - if (!keys) - l = 0; - nm_assert(l == NM_PTRARRAY_LEN(keys)); - NM_SET_OUT(out_length, l); - if (local) - g_propagate_error(error, local); - return keys; -} - -gboolean -nm_keyfile_plugin_kf_has_key(GKeyFile *kf, const char *group, const char *key, GError **error) -{ - gboolean has; - const char *alias; - GError * local = NULL; - - has = g_key_file_has_key(kf, group, key, &local); - if (nm_g_error_matches(local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_GROUP_NOT_FOUND)) { - alias = nm_keyfile_plugin_get_alias_for_setting_name(group); - if (alias) { - g_clear_error(&local); - has = g_key_file_has_key(kf, alias, key, &local); - } - } - if (local) - g_propagate_error(error, local); - return has; -} - -/*****************************************************************************/ - -void -_nm_keyfile_copy(GKeyFile *dst, GKeyFile *src) -{ - gs_strfreev char **groups = NULL; - guint g, k; - - groups = g_key_file_get_groups(src, NULL); - for (g = 0; groups && groups[g]; g++) { - const char * group = groups[g]; - gs_strfreev char **keys = NULL; - - keys = g_key_file_get_keys(src, group, NULL, NULL); - if (!keys) - continue; - - for (k = 0; keys[k]; k++) { - const char * key = keys[k]; - gs_free char *value = NULL; - - value = g_key_file_get_value(src, group, key, NULL); - if (value) - g_key_file_set_value(dst, group, key, value); - else - g_key_file_remove_key(dst, group, key, NULL); - } - } -} - -/*****************************************************************************/ - -gboolean -_nm_keyfile_a_contains_all_in_b(GKeyFile *kf_a, GKeyFile *kf_b) -{ - gs_strfreev char **groups = NULL; - guint i, j; - - if (kf_a == kf_b) - return TRUE; - if (!kf_a || !kf_b) - return FALSE; - - groups = g_key_file_get_groups(kf_a, NULL); - for (i = 0; groups && groups[i]; i++) { - gs_strfreev char **keys = NULL; - - keys = g_key_file_get_keys(kf_a, groups[i], NULL, NULL); - if (!keys) - continue; - - for (j = 0; keys[j]; j++) { - gs_free char *key_a = g_key_file_get_value(kf_a, groups[i], keys[j], NULL); - gs_free char *key_b = g_key_file_get_value(kf_b, groups[i], keys[j], NULL); - - if (g_strcmp0(key_a, key_b) != 0) - return FALSE; - } - } - return TRUE; -} - -static gboolean -_nm_keyfile_equals_ordered(GKeyFile *kf_a, GKeyFile *kf_b) -{ - gs_strfreev char **groups = NULL; - gs_strfreev char **groups_b = NULL; - guint i, j; - - if (kf_a == kf_b) - return TRUE; - if (!kf_a || !kf_b) - return FALSE; - - groups = g_key_file_get_groups(kf_a, NULL); - groups_b = g_key_file_get_groups(kf_b, NULL); - if (!groups && !groups_b) - return TRUE; - if (!groups || !groups_b) - return FALSE; - for (i = 0; groups[i] && groups_b[i] && !strcmp(groups[i], groups_b[i]); i++) - ; - if (groups[i] || groups_b[i]) - return FALSE; - - for (i = 0; groups[i]; i++) { - gs_strfreev char **keys = NULL; - gs_strfreev char **keys_b = NULL; - - keys = g_key_file_get_keys(kf_a, groups[i], NULL, NULL); - keys_b = g_key_file_get_keys(kf_b, groups[i], NULL, NULL); - - if ((!keys) != (!keys_b)) - return FALSE; - if (!keys) - continue; - - for (j = 0; keys[j] && keys_b[j] && !strcmp(keys[j], keys_b[j]); j++) - ; - if (keys[j] || keys_b[j]) - return FALSE; - - for (j = 0; keys[j]; j++) { - gs_free char *key_a = g_key_file_get_value(kf_a, groups[i], keys[j], NULL); - gs_free char *key_b = g_key_file_get_value(kf_b, groups[i], keys[j], NULL); - - if (g_strcmp0(key_a, key_b) != 0) - return FALSE; - } - } - return TRUE; -} - -gboolean -_nm_keyfile_equals(GKeyFile *kf_a, GKeyFile *kf_b, gboolean consider_order) -{ - if (!consider_order) { - return _nm_keyfile_a_contains_all_in_b(kf_a, kf_b) - && _nm_keyfile_a_contains_all_in_b(kf_b, kf_a); - } else { - return _nm_keyfile_equals_ordered(kf_a, kf_b); - } -} - -gboolean -_nm_keyfile_has_values(GKeyFile *keyfile) -{ - gs_strfreev char **groups = NULL; - - g_return_val_if_fail(keyfile, FALSE); - - 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) -{ - NMStrBuf str; - gsize len; - gsize i; - - 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 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)); - - nm_str_buf_init(&str, len + 15u, FALSE); - - if (name[0] == ' ') { - nm_assert(i == 0); - nm_str_buf_append(&str, "\\20"); - i = 1; - } else - nm_str_buf_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')) { - nm_str_buf_append_c(&str, '\\'); - nm_str_buf_append_c_hex(&str, ch, TRUE); - } else - nm_str_buf_append_c(&str, (char) ch); - } - - return (*out_to_free = nm_str_buf_finalize(&str, NULL)); -} - -static const char * -_keyfile_key_decode(const char *key, char **out_to_free) -{ - char *out; - gsize len; - gsize i; - gsize j; - - 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)); - - out = g_new(char, len + 1u); - - memcpy(out, key, sizeof(char) * i); - - j = 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) { - out[j++] = (char) v; - i += 3; - continue; - } - } - out[j++] = ch; - i++; - } - - nm_assert(j <= len); - out[j] = '\0'; - return (*out_to_free = out); -} - -/*****************************************************************************/ - -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 identical - * 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/nm-keyfile-utils.h b/libnm-core/nm-keyfile/nm-keyfile-utils.h deleted file mode 100644 index efad8317..00000000 --- a/libnm-core/nm-keyfile/nm-keyfile-utils.h +++ /dev/null @@ -1,95 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2010 - 2015 Red Hat, Inc. - */ - -#ifndef __NM_KEYFILE_UTILS_H__ -#define __NM_KEYFILE_UTILS_H__ - -#if !((NETWORKMANAGER_COMPILATION) &NM_NETWORKMANAGER_COMPILATION_WITH_LIBNM_CORE_INTERNAL) - #error Cannot use this header. -#endif - -/*****************************************************************************/ - -#include "nm-glib-aux/nm-shared-utils.h" - -/*****************************************************************************/ - -#define NM_KEYFILE_GROUP_VPN_SECRETS "vpn-secrets" -#define NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER "wireguard-peer." - -#define nm_keyfile_error_is_not_found(error) \ - nm_g_error_matches(error, \ - G_KEY_FILE_ERROR, \ - G_KEY_FILE_ERROR_GROUP_NOT_FOUND, \ - G_KEY_FILE_ERROR_KEY_NOT_FOUND) - -const char *nm_keyfile_plugin_get_alias_for_setting_name(const char *setting_name); - -const char *nm_keyfile_plugin_get_setting_name_for_alias(const char *alias); - -/*****************************************************************************/ - -guint *nm_keyfile_plugin_kf_get_integer_list_uint(GKeyFile * kf, - const char *group, - const char *key, - gsize * out_length, - GError ** error); -char **nm_keyfile_plugin_kf_get_string_list(GKeyFile * kf, - const char *group, - const char *key, - gsize * out_length, - GError ** error); -char * -nm_keyfile_plugin_kf_get_string(GKeyFile *kf, const char *group, const char *key, GError **error); -gboolean -nm_keyfile_plugin_kf_get_boolean(GKeyFile *kf, const char *group, const char *key, GError **error); -char * -nm_keyfile_plugin_kf_get_value(GKeyFile *kf, const char *group, const char *key, GError **error); - -void nm_keyfile_plugin_kf_set_integer_list_uint8(GKeyFile * kf, - const char * group, - const char * key, - const guint8 *list, - gsize length); -void nm_keyfile_plugin_kf_set_integer_list_uint(GKeyFile * kf, - const char * group, - const char * key, - const guint *list, - gsize length); -void nm_keyfile_plugin_kf_set_string_list(GKeyFile * kf, - const char * group, - const char * key, - const char *const *list, - gsize length); - -void nm_keyfile_plugin_kf_set_string(GKeyFile * kf, - const char *group, - const char *key, - const char *value); -void -nm_keyfile_plugin_kf_set_boolean(GKeyFile *kf, const char *group, const char *key, gboolean value); -void -nm_keyfile_plugin_kf_set_value(GKeyFile *kf, const char *group, const char *key, const char *value); - -gint64 nm_keyfile_plugin_kf_get_int64(GKeyFile * kf, - const char *group, - const char *key, - guint base, - gint64 min, - gint64 max, - gint64 fallback, - GError ** error); - -char ** -nm_keyfile_plugin_kf_get_keys(GKeyFile *kf, const char *group, gsize *out_length, GError **error); - -gboolean -nm_keyfile_plugin_kf_has_key(GKeyFile *kf, const char *group, 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/nm-keyfile.c b/libnm-core/nm-keyfile/nm-keyfile.c deleted file mode 100644 index 395af1db..00000000 --- a/libnm-core/nm-keyfile/nm-keyfile.c +++ /dev/null @@ -1,4272 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2008 - 2009 Novell, Inc. - * Copyright (C) 2008 - 2017 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-keyfile-internal.h" - -#include -#include -#include -#include -#include -#include -#include - -#include "nm-glib-aux/nm-str-buf.h" -#include "nm-glib-aux/nm-secret-utils.h" -#include "systemd/nm-sd-utils-shared.h" -#include "nm-libnm-core-intern/nm-common-macros.h" -#include "nm-core-internal.h" -#include "nm-keyfile-utils.h" - -#include "nm-setting-user.h" - -/*****************************************************************************/ - -typedef struct _ParseInfoProperty ParseInfoProperty; - -typedef struct { - NMConnection * connection; - GKeyFile * keyfile; - const char * base_dir; - NMKeyfileReadHandler read_handler; - void * user_data; - GError * error; - const char * group; - NMSetting * setting; -} KeyfileReaderInfo; - -typedef struct { - NMConnection * connection; - GKeyFile * keyfile; - GError * error; - NMKeyfileWriteHandler write_handler; - void * user_data; -} KeyfileWriterInfo; - -/*****************************************************************************/ - -static void -_key_file_handler_data_init(NMKeyfileHandlerData *handler_data, - NMKeyfileHandlerType handler_type, - const char * kf_group_name, - const char * kf_key, - NMSetting * cur_setting, - const char * cur_property, - GError ** p_error) -{ - nm_assert(handler_data); - nm_assert(p_error && !*p_error); - - handler_data->type = handler_type; - handler_data->p_error = p_error; - handler_data->kf_group_name = kf_group_name; - handler_data->kf_key = kf_key; - handler_data->cur_setting = cur_setting; - handler_data->cur_property = cur_property; -} - -static void -_key_file_handler_data_init_read(NMKeyfileHandlerData *handler_data, - NMKeyfileHandlerType handler_type, - KeyfileReaderInfo * info, - const char * kf_key, - const char * cur_property) -{ - _key_file_handler_data_init(handler_data, - handler_type, - info->group, - kf_key, - info->setting, - cur_property, - &info->error); -} - -static void -_key_file_handler_data_init_write(NMKeyfileHandlerData *handler_data, - NMKeyfileHandlerType handler_type, - KeyfileWriterInfo * info, - const char * kf_group, - const char * kf_key, - NMSetting * cur_setting, - const char * cur_property) -{ - _key_file_handler_data_init(handler_data, - handler_type, - kf_group, - kf_key, - cur_setting, - cur_property, - &info->error); -} - -_nm_printf(5, 6) static void _handle_warn(KeyfileReaderInfo * info, - const char * kf_key, - const char * cur_property, - NMKeyfileWarnSeverity severity, - const char * fmt, - ...) -{ - NMKeyfileHandlerData handler_data; - - _key_file_handler_data_init_read(&handler_data, - NM_KEYFILE_HANDLER_TYPE_WARN, - info, - kf_key, - cur_property); - handler_data.warn = (NMKeyfileHandlerDataWarn){ - .severity = severity, - .message = NULL, - .fmt = fmt, - }; - - va_start(handler_data.warn.ap, fmt); - - info->read_handler(info->keyfile, - info->connection, - NM_KEYFILE_HANDLER_TYPE_WARN, - &handler_data, - info->user_data); - - va_end(handler_data.warn.ap); - - g_free(handler_data.warn.message); -} - -#define handle_warn(arg_info, arg_kf_key, arg_property_name, arg_severity, ...) \ - ({ \ - KeyfileReaderInfo *_info = (arg_info); \ - \ - nm_assert(!_info->error); \ - \ - if (_info->read_handler) { \ - _handle_warn(_info, (arg_kf_key), (arg_property_name), (arg_severity), __VA_ARGS__); \ - } \ - _info->error == NULL; \ - }) - -/*****************************************************************************/ - -static gboolean -_secret_flags_persist_secret(NMSettingSecretFlags flags) -{ - return flags == NM_SETTING_SECRET_FLAG_NONE; -} - -/*****************************************************************************/ -/* Some setting properties also contain setting names, such as - * NMSettingConnection's 'type' property (which specifies the base type of the - * connection, e.g. ethernet or wifi) or 'slave-type' (specifies type of slave - * connection, e.g. bond or bridge). This function handles translating those - * properties' values to the real setting name if they are an alias. - */ -static void -setting_alias_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - const char * setting_name = nm_setting_get_name(setting); - const char * key_setting_name; - gs_free char *s = NULL; - - s = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); - if (!s) - return; - - key_setting_name = nm_keyfile_plugin_get_setting_name_for_alias(s); - g_object_set(G_OBJECT(setting), key, key_setting_name ?: s, NULL); -} - -static void -sriov_vfs_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - const char * setting_name = nm_setting_get_name(setting); - gs_unref_ptrarray GPtrArray *vfs = NULL; - gs_strfreev char ** keys = NULL; - gsize n_keys = 0; - int i; - - keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); - if (n_keys == 0) - return; - - vfs = g_ptr_array_new_with_free_func((GDestroyNotify) nm_sriov_vf_unref); - - for (i = 0; i < n_keys; i++) { - gs_free char *value = NULL; - NMSriovVF * vf; - const char * rest; - - if (!g_str_has_prefix(keys[i], "vf.")) - continue; - - rest = &keys[i][3]; - - if (!NM_STRCHAR_ALL(rest, ch, g_ascii_isdigit(ch))) - continue; - - value = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, keys[i], NULL); - - vf = _nm_utils_sriov_vf_from_strparts(rest, value, TRUE, NULL); - if (vf) - g_ptr_array_add(vfs, vf); - } - - g_object_set(G_OBJECT(setting), key, vfs, NULL); -} - -static void -read_array_of_uint(GKeyFile *file, NMSetting *setting, const char *key) -{ - gs_unref_array GArray *array = NULL; - gs_free_error GError *error = NULL; - gs_free guint *tmp = NULL; - gsize length; - - tmp = nm_keyfile_plugin_kf_get_integer_list_uint(file, - nm_setting_get_name(setting), - key, - &length, - &error); - if (error) - return; - - array = g_array_sized_new(FALSE, FALSE, sizeof(guint), length); - g_array_append_vals(array, tmp, length); - g_object_set(setting, key, array, NULL); -} - -static gboolean -get_one_int(KeyfileReaderInfo *info, - const char * kf_key, - const char * property_name, - const char * str, - guint32 max_val, - guint32 * out) -{ - gint64 tmp; - - nm_assert((!info) == (!property_name)); - nm_assert((!info) == (!kf_key)); - - if (!str || !str[0]) { - if (info) { - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring missing number")); - } - return FALSE; - } - - tmp = _nm_utils_ascii_str_to_int64(str, 10, 0, max_val, -1); - if (tmp == -1) { - if (info) { - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid number '%s'"), - str); - } - return FALSE; - } - - *out = (guint32) tmp; - return TRUE; -} - -static gpointer -build_address(KeyfileReaderInfo *info, - const char * kf_key, - const char * property_name, - int family, - const char * address_str, - guint32 plen) -{ - NMIPAddress *addr; - GError * error = NULL; - - g_return_val_if_fail(address_str, NULL); - - addr = nm_ip_address_new(family, address_str, plen, &error); - if (!addr) { - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid %s address: %s"), - family == AF_INET ? "IPv4" : "IPv6", - error->message); - g_error_free(error); - } - - return addr; -} - -static gpointer -build_route(KeyfileReaderInfo *info, - const char * kf_key, - const char * property_name, - int family, - const char * dest_str, - guint32 plen, - const char * gateway_str, - const char * metric_str) -{ - NMIPRoute *route; - guint32 u32; - gint64 metric = -1; - GError * error = NULL; - - g_return_val_if_fail(dest_str, NULL); - - /* Next hop */ - if (gateway_str && gateway_str[0]) { - if (!nm_utils_ipaddr_is_valid(family, gateway_str)) { - /* Try workaround for routes written by broken keyfile writer. - * Due to bug bgo#719851, an older version of writer would have - * written "a:b:c:d::/plen,metric" if the gateway was ::, instead - * of "a:b:c:d::/plen,,metric" or "a:b:c:d::/plen,::,metric" - * Try workaround by interpreting gateway_str as metric to accept such - * invalid routes. This broken syntax should not be not officially - * supported. - **/ - if (family == AF_INET6 && !metric_str - && get_one_int(NULL, NULL, NULL, gateway_str, G_MAXUINT32, &u32)) { - metric = u32; - gateway_str = NULL; - } else { - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid gateway '%s' for %s route"), - gateway_str, - family == AF_INET ? "IPv4" : "IPv6"); - return NULL; - } - } - } else - gateway_str = NULL; - - /* parse metric, default to -1 */ - if (metric_str) { - if (!get_one_int(info, kf_key, property_name, metric_str, G_MAXUINT32, &u32)) - return NULL; - metric = u32; - } - - route = nm_ip_route_new(family, dest_str, plen, gateway_str, metric, &error); - if (!route) { - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid %s route: %s"), - family == AF_INET ? "IPv4" : "IPv6", - error->message); - g_error_free(error); - } - - return route; -} - -/* On success, returns pointer to the zero-terminated field (original @current). - * The @current * pointer target is set to point to the rest of the input - * or %NULL if there is no more input. Sets error to %NULL for convenience. - * - * On failure, returns %NULL (unspecified). The @current pointer target is - * resets to its original value to allow skipping fields. The @error target - * is set to the character that breaks the parsing or %NULL if @current was %NULL. - * - * When @current target is %NULL, gracefully fail returning %NULL while - * leaving the @current target %NULL end setting @error to %NULL; - */ -static const char * -read_field(char **current, const char **out_err_str, const char *characters, const char *delimiters) -{ - const char *start; - - nm_assert(current); - nm_assert(out_err_str); - nm_assert(characters); - nm_assert(delimiters); - - *out_err_str = NULL; - - if (!*current) { - /* graceful failure, leave '*current' NULL */ - return NULL; - } - - /* fail on empty input */ - if (!**current) - return NULL; - - /* remember beginning of input */ - start = *current; - - while (**current && strchr(characters, **current)) - (*current)++; - if (**current) - if (strchr(delimiters, **current)) { - /* success, more data available */ - *(*current)++ = '\0'; - return start; - } else { - /* error, bad character */ - *out_err_str = *current; - *current = (char *) start; - return NULL; - } - else { - /* success, end of input */ - *current = NULL; - return start; - } -} - -/*****************************************************************************/ - -#define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect" -#define NM_OPENCONNECT_KEY_GATEWAY "gateway" -#define NM_OPENCONNECT_KEY_COOKIE "cookie" -#define NM_OPENCONNECT_KEY_GWCERT "gwcert" -#define NM_OPENCONNECT_KEY_XMLCONFIG "xmlconfig" -#define NM_OPENCONNECT_KEY_LASTHOST "lasthost" -#define NM_OPENCONNECT_KEY_AUTOCONNECT "autoconnect" -#define NM_OPENCONNECT_KEY_CERTSIGS "certsigs" - -static void -openconnect_fix_secret_flags(NMSetting *setting) -{ - NMSettingVpn * s_vpn; - NMSettingSecretFlags flags; - - /* Huge hack. There were some openconnect changes that needed to happen - * pretty late, too late to get into distros. Migration has already - * happened for many people, and their secret flags are wrong. But we - * don't want to require re-migration, so we have to fix it up here. Ugh. - */ - - if (!NM_IS_SETTING_VPN(setting)) - return; - - s_vpn = NM_SETTING_VPN(setting); - - if (!nm_streq0(nm_setting_vpn_get_service_type(s_vpn), NM_DBUS_SERVICE_OPENCONNECT)) - return; - - /* These are different for every login session, and should not be stored */ - flags = NM_SETTING_SECRET_FLAG_NOT_SAVED; - nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_GATEWAY, flags, NULL); - nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_COOKIE, flags, NULL); - nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_GWCERT, flags, NULL); - - /* These are purely internal data for the auth-dialog, and should be stored */ - flags = 0; - nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_XMLCONFIG, flags, NULL); - nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_LASTHOST, flags, NULL); - nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_AUTOCONNECT, flags, NULL); - nm_setting_set_secret_flags(NM_SETTING(s_vpn), NM_OPENCONNECT_KEY_CERTSIGS, flags, NULL); -} - -/*****************************************************************************/ - -#define IP_ADDRESS_CHARS "0123456789abcdefABCDEF:.%" -#define DIGITS "0123456789" -#define DELIMITERS "/;," - -/* The following IPv4 and IPv6 address formats are supported: - * - * address (DEPRECATED) - * address/plen - * address/gateway (DEPRECATED) - * address/plen,gateway - * - * The following IPv4 and IPv6 route formats are supported: - * - * address/plen (NETWORK dev DEVICE) - * address/plen,gateway (NETWORK via GATEWAY dev DEVICE) - * address/plen,,metric (NETWORK dev DEVICE metric METRIC) - * address/plen,gateway,metric (NETWORK via GATEWAY dev DEVICE metric METRIC) - * - * For backward, forward and sideward compatibility, slash (/), - * semicolon (;) and comma (,) are interchangeable. The choice of - * separator in the above examples is therefore not significant. - * - * Leaving out the prefix length is discouraged and DEPRECATED. The - * default value of IPv6 prefix length was 64 and has not been - * changed. The default for IPv4 is now 24, which is the closest - * IPv4 equivalent. These defaults may just as well be changed to - * match the iproute2 defaults (32 for IPv4 and 128 for IPv6). - */ -static gpointer -read_one_ip_address_or_route(KeyfileReaderInfo *info, - const char * property_name, - const char * setting_name, - const char * kf_key, - gboolean ipv6, - gboolean route, - char ** out_gateway, - NMSetting * setting) -{ - guint plen; - gpointer result; - const char * address_str; - const char * plen_str; - const char * gateway_str; - const char * metric_str; - const char * err_str = NULL; - char * current; - gs_free char *value = NULL; - gs_free char *value_orig = NULL; - -#define VALUE_ORIG() \ - (value_orig \ - ?: (value_orig = \ - nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, kf_key, NULL))) - - value = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, kf_key, NULL); - if (!value) - return NULL; - - current = value; - - /* get address field */ - address_str = read_field(¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS); - if (err_str) { - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("unexpected character '%c' for address %s: '%s' (position %td)"), - *err_str, - kf_key, - VALUE_ORIG(), - err_str - current); - return NULL; - } - /* get prefix length field (skippable) */ - plen_str = read_field(¤t, &err_str, DIGITS, DELIMITERS); - /* get gateway field */ - gateway_str = read_field(¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS); - if (err_str) { - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("unexpected character '%c' for %s: '%s' (position %td)"), - *err_str, - kf_key, - VALUE_ORIG(), - err_str - current); - return NULL; - } - /* for routes, get metric */ - if (route) { - metric_str = read_field(¤t, &err_str, DIGITS, DELIMITERS); - if (err_str) { - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("unexpected character '%c' in prefix length for %s: '%s' (position %td)"), - *err_str, - kf_key, - VALUE_ORIG(), - err_str - current); - return NULL; - } - } else - metric_str = NULL; - if (current) { - /* there is still some data */ - if (*current) { - /* another field follows */ - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("garbage at the end of value %s: '%s'"), - kf_key, - VALUE_ORIG()); - return NULL; - } else { - /* semicolon at the end of input */ - if (!handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_INFO, - _("deprecated semicolon at the end of value %s: '%s'"), - kf_key, - VALUE_ORIG())) - return NULL; - } - } - -#define DEFAULT_PREFIX(for_route, for_ipv6) \ - ((for_route) ? ((for_ipv6) ? 128 : 24) : ((for_ipv6) ? 64 : 24)) - - /* parse plen, fallback to defaults */ - if (plen_str) { - if (!get_one_int(info, kf_key, property_name, plen_str, ipv6 ? 128 : 32, &plen)) { - plen = DEFAULT_PREFIX(route, ipv6); - if (info->error - || !handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid prefix length for %s '%s', defaulting to %d"), - kf_key, - VALUE_ORIG(), - plen)) - return NULL; - } - } else { - plen = DEFAULT_PREFIX(route, ipv6); - if (!handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("missing prefix length for %s '%s', defaulting to %d"), - kf_key, - VALUE_ORIG(), - plen)) - return NULL; - } - - /* build the appropriate data structure for NetworkManager settings */ - if (route) { - result = build_route(info, - kf_key, - property_name, - ipv6 ? AF_INET6 : AF_INET, - address_str, - plen, - gateway_str, - metric_str); - } else { - result = build_address(info, - kf_key, - property_name, - ipv6 ? AF_INET6 : AF_INET, - address_str, - plen); - if (!result) - return NULL; - if (gateway_str) - NM_SET_OUT(out_gateway, g_strdup(gateway_str)); - } - -#undef VALUE_ORIG - - return result; -} - -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)); - } - } -} - -typedef struct { - const char *s_key; - gint32 key_idx; - gint8 key_type; -} BuildListData; - -typedef enum { - BUILD_LIST_TYPE_ADDRESSES, - BUILD_LIST_TYPE_ROUTES, - BUILD_LIST_TYPE_ROUTING_RULES, -} BuildListType; - -static int -_build_list_data_cmp(gconstpointer p_a, gconstpointer p_b, gpointer user_data) -{ - const BuildListData *a = p_a; - const BuildListData *b = p_b; - - NM_CMP_FIELD(a, b, key_idx); - NM_CMP_FIELD(a, b, key_type); - NM_CMP_FIELD_STR(a, b, s_key); - return 0; -} - -static gboolean -_build_list_data_is_shadowed(const BuildListData *build_list, gsize build_list_len, gsize idx) -{ - /* the keyfile contains duplicate keys, which are both returned - * by g_key_file_get_keys() (WHY??). - * - * Skip the earlier one. */ - return idx + 1 < build_list_len && build_list[idx].key_idx == build_list[idx + 1].key_idx - && build_list[idx].key_type == build_list[idx + 1].key_type - && nm_streq(build_list[idx].s_key, build_list[idx + 1].s_key); -} - -static gboolean -_build_list_match_key_w_name_impl(const char *key, - const char *base_name, - gsize base_name_l, - gint32 * out_key_idx) -{ - gint64 v; - - /* some very strict parsing. */ - - /* the key must start with base_name. */ - if (strncmp(key, base_name, base_name_l) != 0) - return FALSE; - - key += base_name_l; - if (key[0] == '\0') { - /* if key is identical to base_name, that's good. */ - NM_SET_OUT(out_key_idx, -1); - return TRUE; - } - - /* if base_name is followed by a zero, then it must be - * only a zero, nothing else. */ - if (key[0] == '0') { - if (key[1] != '\0') - return FALSE; - NM_SET_OUT(out_key_idx, 0); - return TRUE; - } - - /* otherwise, it can only be followed by a non-zero decimal. */ - if (!(key[0] >= '1' && key[0] <= '9')) - return FALSE; - /* and all remaining chars must be decimals too. */ - if (!NM_STRCHAR_ALL(&key[1], ch, g_ascii_isdigit(ch))) - return FALSE; - - /* and it must be convertible to a (positive) int. */ - v = _nm_utils_ascii_str_to_int64(key, 10, 0, G_MAXINT32, -1); - if (v < 0) - return FALSE; - - /* good */ - NM_SET_OUT(out_key_idx, v); - return TRUE; -} - -#define _build_list_match_key_w_name(key, base_name, out_key_idx) \ - _build_list_match_key_w_name_impl(key, base_name, NM_STRLEN(base_name), out_key_idx) - -static BuildListData * -_build_list_create(GKeyFile * keyfile, - const char * group_name, - BuildListType build_list_type, - gsize * out_build_list_len, - char *** out_keys_strv) -{ - gs_strfreev char **keys = NULL; - gsize i_keys, n_keys; - gs_free BuildListData *build_list = NULL; - gsize build_list_len = 0; - - nm_assert(out_build_list_len && *out_build_list_len == 0); - nm_assert(out_keys_strv && !*out_keys_strv); - - keys = nm_keyfile_plugin_kf_get_keys(keyfile, group_name, &n_keys, NULL); - if (n_keys == 0) - return NULL; - - for (i_keys = 0; i_keys < n_keys; i_keys++) { - const char *s_key = keys[i_keys]; - gint32 key_idx; - gint8 key_type = 0; - - switch (build_list_type) { - case BUILD_LIST_TYPE_ROUTES: - if (_build_list_match_key_w_name(s_key, "route", &key_idx)) - key_type = 0; - else if (_build_list_match_key_w_name(s_key, "routes", &key_idx)) - key_type = 1; - else - continue; - break; - case BUILD_LIST_TYPE_ADDRESSES: - if (_build_list_match_key_w_name(s_key, "address", &key_idx)) - key_type = 0; - else if (_build_list_match_key_w_name(s_key, "addresses", &key_idx)) - key_type = 1; - else - continue; - break; - case BUILD_LIST_TYPE_ROUTING_RULES: - if (_build_list_match_key_w_name(s_key, "routing-rule", &key_idx)) - key_type = 0; - else - continue; - break; - default: - nm_assert_not_reached(); - break; - } - - if (G_UNLIKELY(!build_list)) - build_list = g_new(BuildListData, n_keys - i_keys); - - build_list[build_list_len++] = (BuildListData){ - .s_key = s_key, - .key_idx = key_idx, - .key_type = key_type, - }; - } - - if (build_list_len == 0) - return NULL; - - if (build_list_len > 1) { - g_qsort_with_data(build_list, - build_list_len, - sizeof(BuildListData), - _build_list_data_cmp, - NULL); - } - - *out_build_list_len = build_list_len; - *out_keys_strv = g_steal_pointer(&keys); - return g_steal_pointer(&build_list); -} - -static void -ip_address_or_route_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *setting_key) -{ - const char * setting_name = nm_setting_get_name(setting); - gboolean is_ipv6 = nm_streq(setting_name, "ipv6"); - gboolean is_routes = nm_streq(setting_key, "routes"); - gs_free char * gateway = NULL; - gs_unref_ptrarray GPtrArray *list = NULL; - gs_strfreev char ** keys = NULL; - gs_free BuildListData *build_list = NULL; - gsize i_build_list, build_list_len = 0; - - build_list = _build_list_create(info->keyfile, - setting_name, - is_routes ? BUILD_LIST_TYPE_ROUTES : BUILD_LIST_TYPE_ADDRESSES, - &build_list_len, - &keys); - if (!build_list) - return; - - list = g_ptr_array_new_with_free_func(is_routes ? (GDestroyNotify) nm_ip_route_unref - : (GDestroyNotify) nm_ip_address_unref); - - for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) { - const char *s_key; - gpointer item; - - if (_build_list_data_is_shadowed(build_list, build_list_len, i_build_list)) - continue; - - s_key = build_list[i_build_list].s_key; - item = read_one_ip_address_or_route(info, - setting_key, - setting_name, - s_key, - is_ipv6, - is_routes, - gateway ? NULL : &gateway, - setting); - if (item && is_routes) { - char options_key[128]; - - nm_sprintf_buf(options_key, "%s_options", s_key); - fill_route_attributes(info->keyfile, - item, - setting_name, - options_key, - is_ipv6 ? AF_INET6 : AF_INET); - } - - if (info->error) - return; - - if (item) - g_ptr_array_add(list, item); - } - - if (list->len >= 1) - g_object_set(setting, setting_key, list, NULL); - - if (gateway) - g_object_set(setting, "gateway", gateway, NULL); -} - -static void -ip_routing_rule_parser_full(KeyfileReaderInfo * info, - const NMMetaSettingInfo * setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty * pip, - NMSetting * setting) -{ - const char * setting_name = nm_setting_get_name(setting); - gboolean is_ipv6 = nm_streq(setting_name, "ipv6"); - gs_strfreev char **keys = NULL; - gs_free BuildListData *build_list = NULL; - gsize i_build_list, build_list_len = 0; - - build_list = _build_list_create(info->keyfile, - setting_name, - BUILD_LIST_TYPE_ROUTING_RULES, - &build_list_len, - &keys); - if (!build_list) - return; - - for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) { - nm_auto_unref_ip_routing_rule NMIPRoutingRule *rule = NULL; - gs_free char * value = NULL; - gs_free_error GError *local = NULL; - - if (_build_list_data_is_shadowed(build_list, build_list_len, i_build_list)) - continue; - - value = nm_keyfile_plugin_kf_get_string(info->keyfile, - setting_name, - build_list[i_build_list].s_key, - NULL); - if (!value) - continue; - - rule = nm_ip_routing_rule_from_string( - value, - (NM_IP_ROUTING_RULE_AS_STRING_FLAGS_VALIDATE - | (is_ipv6 ? NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET6 - : NM_IP_ROUTING_RULE_AS_STRING_FLAGS_AF_INET)), - NULL, - &local); - if (!rule) { - if (!handle_warn(info, - build_list[i_build_list].s_key, - property_info->name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid value for \"%s\": %s"), - build_list[i_build_list].s_key, - local->message)) - return; - continue; - } - - nm_setting_ip_config_add_routing_rule(NM_SETTING_IP_CONFIG(setting), rule); - } -} - -static void -ip_dns_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - int addr_family; - gs_strfreev char **list = NULL; - gsize i, n, length; - - nm_assert(NM_IS_SETTING_IP4_CONFIG(setting) || NM_IS_SETTING_IP6_CONFIG(setting)); - - list = nm_keyfile_plugin_kf_get_string_list(info->keyfile, - nm_setting_get_name(setting), - key, - &length, - NULL); - nm_assert(length == NM_PTRARRAY_LEN(list)); - if (length == 0) - return; - - addr_family = NM_IS_SETTING_IP4_CONFIG(setting) ? AF_INET : AF_INET6; - - n = 0; - for (i = 0; i < length; i++) { - NMIPAddr addr; - - if (inet_pton(addr_family, list[i], &addr) <= 0) { - if (!handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid DNS server IPv%c address '%s'"), - nm_utils_addr_family_to_char(addr_family), - list[i])) { - do { - nm_clear_g_free(&list[i]); - } while (++i < length); - return; - } - nm_clear_g_free(&list[i]); - continue; - } - - if (n != i) - list[n] = g_steal_pointer(&list[i]); - n++; - } - - g_object_set(setting, key, list, NULL); -} - -static void -ip6_addr_gen_mode_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - NMSettingIP6ConfigAddrGenMode addr_gen_mode; - const char * setting_name = nm_setting_get_name(setting); - gs_free char * s = NULL; - - s = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); - if (s) { - if (!nm_utils_enum_from_str(nm_setting_ip6_config_addr_gen_mode_get_type(), - s, - (int *) &addr_gen_mode, - NULL)) { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid option '%s', use one of [%s]"), - s, - "eui64,stable-privacy"); - return; - } - } else - addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64; - - g_object_set(G_OBJECT(setting), key, (int) addr_gen_mode, NULL); -} - -static void -mac_address_parser(KeyfileReaderInfo *info, - NMSetting * setting, - const char * key, - gsize addr_len, - gboolean cloned_mac_addr) -{ - const char * setting_name = nm_setting_get_name(setting); - char addr_str[NM_UTILS_HWADDR_LEN_MAX * 3]; - guint8 addr_bin[NM_UTILS_HWADDR_LEN_MAX]; - gs_free char *tmp_string = NULL; - gs_free guint *int_list = NULL; - const char * mac_str; - gsize int_list_len; - gsize i; - - nm_assert(addr_len > 0); - nm_assert(addr_len <= NM_UTILS_HWADDR_LEN_MAX); - - tmp_string = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); - - if (cloned_mac_addr && NM_CLONED_MAC_IS_SPECIAL(tmp_string)) { - mac_str = tmp_string; - goto out; - } - - if (tmp_string && nm_utils_hwaddr_aton(tmp_string, addr_bin, addr_len)) - goto good_addr_bin; - - /* Old format; list of ints */ - int_list = nm_keyfile_plugin_kf_get_integer_list_uint(info->keyfile, - setting_name, - key, - &int_list_len, - NULL); - if (int_list_len == addr_len) { - for (i = 0; i < addr_len; i++) { - const guint val = int_list[i]; - - if (val > 255) - break; - addr_bin[i] = (guint8) val; - } - if (i == addr_len) - goto good_addr_bin; - } - - handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("ignoring invalid MAC address")); - return; - -good_addr_bin: - nm_utils_bin2hexstr_full(addr_bin, addr_len, ':', TRUE, addr_str); - mac_str = addr_str; - -out: - g_object_set(setting, key, mac_str, NULL); -} - -static void -mac_address_parser_ETHER(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - mac_address_parser(info, setting, key, ETH_ALEN, FALSE); -} - -static void -mac_address_parser_ETHER_cloned(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - mac_address_parser(info, setting, key, ETH_ALEN, TRUE); -} - -static void -mac_address_parser_INFINIBAND(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - mac_address_parser(info, setting, key, INFINIBAND_ALEN, FALSE); -} - -static void -read_hash_of_string(GKeyFile *file, NMSetting *setting, const char *key) -{ - gs_strfreev char **keys = NULL; - const char *const *iter; - const char * setting_name = nm_setting_get_name(setting); - gboolean is_vpn; - gsize n_keys; - - nm_assert((NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_DATA)) - || (NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_SECRETS)) - || (NM_IS_SETTING_BOND(setting) && nm_streq(key, NM_SETTING_BOND_OPTIONS)) - || (NM_IS_SETTING_USER(setting) && nm_streq(key, NM_SETTING_USER_DATA))); - - keys = nm_keyfile_plugin_kf_get_keys(file, setting_name, &n_keys, NULL); - if (n_keys == 0) - return; - - 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 (!nm_streq(name, "interface-name")) - nm_setting_bond_add_option(NM_SETTING_BOND(setting), name, value); - } - } - openconnect_fix_secret_flags(setting); - return; - } - - if (NM_IS_SETTING_USER(setting)) { - gs_unref_hashtable GHashTable *data = NULL; - - data = g_hash_table_new_full(nm_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_object_set(setting, NM_SETTING_USER_DATA, data, NULL); - return; - } - - nm_assert_not_reached(); -} - -static gsize -unescape_semicolons(char *str) -{ - gsize i, j; - - for (i = 0, j = 0; str[i];) { - if (str[i] == '\\' && str[i + 1] == ';') - i++; - str[j++] = str[i++]; - } - nm_explicit_bzero(&str[j], i - j); - return j; -} - -static GBytes * -get_bytes(KeyfileReaderInfo *info, - const char * setting_name, - const char * key, - gboolean zero_terminate, - gboolean unescape_semicolon) -{ - nm_auto_free_secret char *tmp_string = NULL; - gboolean may_be_int_list = TRUE; - gsize length; - GBytes * result; - - /* New format: just a string - * Old format: integer list; e.g. 11;25;38; - */ - tmp_string = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); - if (!tmp_string) - return NULL; - - /* if the string is empty, we return an empty GBytes array. - * Note that for NM_SETTING_802_1X_PASSWORD_RAW both %NULL and - * an empty GBytes are valid, and shall be destinguished. */ - if (!tmp_string[0]) { - /* note that even if @zero_terminate is TRUE, we return an empty - * byte-array. The reason is that zero_terminate is there to terminate - * *valid* strings. It's not there to terminated invalid (empty) strings. - */ - return g_bytes_new_static("", 0); - } - - for (length = 0; tmp_string[length]; length++) { - const char ch = tmp_string[length]; - - if (!g_ascii_isspace(ch) && !g_ascii_isdigit(ch) && ch != ';') { - may_be_int_list = FALSE; - length += strlen(&tmp_string[length]); - break; - } - } - - /* Try to parse the string as a integer list. */ - if (may_be_int_list && length > 0) { - nm_auto_free_secret_buf NMSecretBuf *bin = NULL; - const char *const s = tmp_string; - gsize i, d; - - bin = nm_secret_buf_new(length / 2 + 3); - -#define DIGIT(c) ((c) - '0') - i = 0; - d = 0; - while (TRUE) { - int n; - - /* leading whitespace */ - while (g_ascii_isspace(s[i])) - i++; - if (s[i] == '\0') - break; - /* then expect 1 to 3 digits */ - if (!g_ascii_isdigit(s[i])) { - d = 0; - break; - } - n = DIGIT(s[i]); - i++; - if (g_ascii_isdigit(s[i])) { - n = 10 * n + DIGIT(s[i]); - i++; - if (g_ascii_isdigit(s[i])) { - n = 10 * n + DIGIT(s[i]); - i++; - } - } - if (n > 255) { - d = 0; - break; - } - - nm_assert(d < bin->len); - bin->bin[d++] = n; - - /* allow whitespace after the digit. */ - while (g_ascii_isspace(s[i])) - i++; - /* need a semicolon as separator. */ - if (s[i] != ';') { - d = 0; - break; - } - i++; - } -#undef DIGIT - - /* Old format; list of ints. We already did a strict validation of the - * string format before. We expect that this conversion cannot fail. */ - if (d > 0) { - /* note that @zero_terminate does not add a terminating '\0' to - * binary data as an integer list. If the bytes are expressed as - * an integer list, all potential NUL characters are supposed to - * be included there explicitly. - * - * However, in the spirit of defensive programming, we do append a - * NUL character to the buffer, although this character is hidden - * and only a mitigation for bugs. */ - - if (d + 10 < bin->len) { - /* hm, too much unused memory. Copy the memory to a suitable - * sized buffer. */ - return nm_secret_copy_to_gbytes(bin->bin, d); - } - - nm_assert(d < bin->len); - bin->bin[d] = '\0'; - return nm_secret_buf_to_gbytes_take(g_steal_pointer(&bin), d); - } - } - - /* Handle as a simple string (ie, new format) */ - if (unescape_semicolon) - length = unescape_semicolons(tmp_string); - if (zero_terminate) - length++; - if (length == 0) - return NULL; - - result = - g_bytes_new_with_free_func(tmp_string, length, (GDestroyNotify) nm_free_secret, tmp_string); - tmp_string = NULL; - return result; -} - -static void -ssid_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - const char * setting_name = nm_setting_get_name(setting); - gs_unref_bytes GBytes *bytes = NULL; - - bytes = get_bytes(info, setting_name, key, FALSE, TRUE); - if (!bytes) { - handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("ignoring invalid SSID")); - return; - } - g_object_set(setting, key, bytes, NULL); -} - -static void -password_raw_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - const char * setting_name = nm_setting_get_name(setting); - gs_unref_bytes GBytes *bytes = NULL; - - bytes = get_bytes(info, setting_name, key, FALSE, TRUE); - if (!bytes) { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid raw password")); - return; - } - g_object_set(setting, key, bytes, NULL); -} - -static char * -get_cert_path(const char *base_dir, const guint8 *cert_path, gsize cert_path_len) -{ - const char *base; - char * p = NULL, *path, *tmp; - - g_return_val_if_fail(base_dir != NULL, NULL); - g_return_val_if_fail(cert_path != NULL, NULL); - - path = g_strndup((char *) cert_path, cert_path_len); - - if (path[0] == '/') - return path; - - base = path; - p = strrchr(path, '/'); - if (p) - base = p + 1; - - tmp = g_build_path("/", base_dir, base, NULL); - g_free(path); - return tmp; -} - -static const char *certext[] = {".pem", ".cert", ".crt", ".cer", ".p12", ".der", ".key"}; - -static gboolean -has_cert_ext(const char *path) -{ - int i; - - for (i = 0; i < G_N_ELEMENTS(certext); i++) { - if (g_str_has_suffix(path, certext[i])) - return TRUE; - } - return FALSE; -} - -char * -nm_keyfile_detect_unqualified_path_scheme(const char * base_dir, - gconstpointer pdata, - gsize data_len, - gboolean consider_exists, - gboolean * out_exists) -{ - const char * data = pdata; - gboolean exists = FALSE; - gsize validate_len; - gsize path_len, pathuri_len; - gs_free char *path = NULL; - gs_free char *pathuri = NULL; - - g_return_val_if_fail(base_dir && base_dir[0] == '/', NULL); - - if (!pdata) - return NULL; - if (data_len == -1) - data_len = strlen(data); - if (data_len > 500 || data_len < 1) - return NULL; - - /* If there's a trailing zero tell g_utf8_validate() to validate until the zero */ - if (data[data_len - 1] == '\0') { - /* setting it to -1, would mean we accept data to contain NUL characters before the - * end. Don't accept any NUL in [0 .. data_len-1[ . */ - validate_len = data_len - 1; - } else - validate_len = data_len; - if (validate_len == 0 || g_utf8_validate((const char *) data, validate_len, NULL) == FALSE) - return NULL; - - /* Might be a bare path without the file:// prefix; in that case - * if it's an absolute path, use that, otherwise treat it as a - * relative path to the current directory. - */ - - path = get_cert_path(base_dir, (const guint8 *) data, data_len); - - /* FIXME(keyfile-parse-in-memory): it is wrong that keyfile reader makes decisions based on - * the file systems content. The serialization/parsing should be entirely in-memory. */ - if (!memchr(data, '/', data_len) && !has_cert_ext(path)) { - if (!consider_exists) - return NULL; - exists = g_file_test(path, G_FILE_TEST_EXISTS); - if (!exists) - return NULL; - } else if (out_exists) - exists = g_file_test(path, G_FILE_TEST_EXISTS); - - /* Construct the proper value as required for the PATH scheme. - * - * When returning TRUE, we must also be sure that @data_len does not look like - * the deprecated format of list of integers. With this implementation that is the - * case, as long as @consider_exists is FALSE. */ - path_len = strlen(path); - pathuri_len = (NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) + 1) + path_len; - pathuri = g_new(char, pathuri_len); - memcpy(pathuri, - NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, - NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)); - memcpy(&pathuri[NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)], path, path_len + 1); - if (nm_setting_802_1x_check_cert_scheme(pathuri, pathuri_len, NULL) - != NM_SETTING_802_1X_CK_SCHEME_PATH) - return NULL; - - NM_SET_OUT(out_exists, exists); - return g_steal_pointer(&pathuri); -} - -#define HAS_SCHEME_PREFIX(bin, bin_len, scheme) \ - ({ \ - const char *const _bin = (bin); \ - const gsize _bin_len = (bin_len); \ - \ - nm_assert(_bin &&_bin_len > 0); \ - \ - (_bin_len > NM_STRLEN(scheme) + 1 && _bin[_bin_len - 1] == '\0' \ - && memcmp(_bin, scheme, NM_STRLEN(scheme)) == 0); \ - }) - -static void -cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - const char * setting_name = nm_setting_get_name(setting); - gs_unref_bytes GBytes *bytes = NULL; - const char * bin = NULL; - gsize bin_len = 0; - char * path; - gboolean path_exists; - - bytes = get_bytes(info, setting_name, key, TRUE, FALSE); - if (bytes) - bin = g_bytes_get_data(bytes, &bin_len); - if (bin_len == 0) { - if (!info->error) { - handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("invalid key/cert value")); - } - return; - } - - if (HAS_SCHEME_PREFIX(bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)) { - const char * path2 = &bin[NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH)]; - gs_free char *path2_free = NULL; - - if (nm_setting_802_1x_check_cert_scheme(bin, bin_len, NULL) - != NM_SETTING_802_1X_CK_SCHEME_PATH) { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key/cert value path \"%s\""), - bin); - return; - } - - g_object_set(setting, key, bytes, NULL); - - if (path2[0] != '/') { - /* we want to read absolute paths because we use keyfile as exchange - * between different processes which might not have the same cwd. */ - path2_free = get_cert_path(info->base_dir, - (const guint8 *) path2, - bin_len - NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH) - 1); - path2 = path2_free; - } - - /* FIXME(keyfile-parse-in-memory): keyfile reader must not access the file system and - * (in a first step) only operate in memory-only. If the presence of files should be checked, - * then by invoking a callback (and possibly keyfile settings plugin would - * collect the file names to be checked and check them later). */ - if (!g_file_test(path2, G_FILE_TEST_EXISTS)) { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, - _("certificate or key file '%s' does not exist"), - path2); - } - return; - } - - if (HAS_SCHEME_PREFIX(bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_PKCS11)) { - if (nm_setting_802_1x_check_cert_scheme(bin, bin_len, NULL) - != NM_SETTING_802_1X_CK_SCHEME_PKCS11) { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid PKCS#11 URI \"%s\""), - bin); - return; - } - - g_object_set(setting, key, bytes, NULL); - return; - } - - if (HAS_SCHEME_PREFIX(bin, bin_len, NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB)) { - const char *cdata = bin + NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB); - gsize cdata_len = bin_len - NM_STRLEN(NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB) - 1; - gs_free guchar *bin_decoded = NULL; - gsize bin_decoded_len = 0; - gsize i; - gboolean valid_base64; - gs_unref_bytes GBytes *val = NULL; - - /* Let's be strict here. We expect valid base64, no funny stuff!! - * We didn't write such invalid data ourselfes and refuse to read it as blob. */ - if ((valid_base64 = (cdata_len % 4 == 0))) { - for (i = 0; i < cdata_len; i++) { - char c = cdata[i]; - - if (!((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') - || (c == '+' || c == '/'))) { - if (c != '=' || i < cdata_len - 2) - valid_base64 = FALSE; - else { - for (; i < cdata_len; i++) { - if (cdata[i] != '=') - valid_base64 = FALSE; - } - } - break; - } - } - } - if (valid_base64) - bin_decoded = g_base64_decode(cdata, &bin_decoded_len); - - if (bin_decoded_len == 0) { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key/cert value data:;base64, is not base64")); - return; - } - - if (nm_setting_802_1x_check_cert_scheme(bin_decoded, bin_decoded_len, NULL) - != NM_SETTING_802_1X_CK_SCHEME_BLOB) { - /* The blob probably starts with "file://". Setting the cert data will confuse NMSetting8021x. - * In fact this is a limitation of NMSetting8021x which does not support setting blobs that start - * with file://. Just warn and return TRUE to signal that we ~handled~ the setting. */ - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key/cert value data:;base64,file://")); - return; - } - - val = g_bytes_new_take(g_steal_pointer(&bin_decoded), bin_decoded_len); - g_object_set(setting, key, val, NULL); - return; - } - - /* If not, it might be a plain path */ - path = - nm_keyfile_detect_unqualified_path_scheme(info->base_dir, bin, bin_len, TRUE, &path_exists); - if (path) { - gs_unref_bytes GBytes *val = NULL; - - /* Construct the proper value as required for the PATH scheme */ - val = g_bytes_new_take(path, strlen(path) + 1); - g_object_set(setting, key, val, NULL); - - /* Warn if the certificate didn't exist */ - if (!path_exists) { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, - _("certificate or key file '%s' does not exist"), - path); - } - return; - } - - if (nm_setting_802_1x_check_cert_scheme(bin, bin_len, NULL) - != NM_SETTING_802_1X_CK_SCHEME_BLOB) { - /* The blob probably starts with "file://" but contains invalid characters for a path. - * Setting the cert data will confuse NMSetting8021x. - * In fact, NMSetting8021x does not support setting such binary data, so just warn and - * continue. */ - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key/cert value is not a valid blob")); - return; - } - - g_object_set(setting, key, bytes, NULL); -} - -static int -_parity_from_char(int ch) -{ -#if NM_MORE_ASSERTS > 5 - { - static char check = 0; - - if (check == 0) { - nm_auto_unref_gtypeclass GEnumClass *klass = - g_type_class_ref(NM_TYPE_SETTING_SERIAL_PARITY); - guint i; - - check = 1; - - /* In older versions, parity was G_TYPE_CHAR/gint8, and the character - * value was stored as integer. - * For example parity=69 equals parity=E, meaning NM_SETTING_SERIAL_PARITY_EVEN. - * - * That means, certain values are reserved. Assert that these numbers - * are not reused when we extend NMSettingSerialParity enum. - * Actually, since NM_SETTING_SERIAL_PARITY is g_param_spec_enum(), - * we anyway cannot extend the enum without breaking API... - * - * [1] commit "a91e60902e libnm-core: make NMSettingSerial:parity an enum" - * [2] https://cgit.freedesktop.org/NetworkManager/NetworkManager/commit/?id=a91e60902eabae1de93d61323dae6ac894b5d40f - */ - g_assert(G_IS_ENUM_CLASS(klass)); - for (i = 0; i < klass->n_values; i++) { - const GEnumValue *v = &klass->values[i]; - int num = v->value; - - g_assert(_parity_from_char(num) == -1); - g_assert(!NM_IN_SET(num, 'e', 'E', 'o', 'O', 'n', 'N')); - } - } - } -#endif - - switch (ch) { - case 'E': - case 'e': - return NM_SETTING_SERIAL_PARITY_EVEN; - case 'O': - case 'o': - return NM_SETTING_SERIAL_PARITY_ODD; - case 'N': - case 'n': - return NM_SETTING_SERIAL_PARITY_NONE; - } - - return -1; -} - -static void -parity_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - const char * setting_name = nm_setting_get_name(setting); - gs_free_error GError *err = NULL; - int parity; - gs_free char * tmp_str = NULL; - gint64 i64; - - /* Keyfile traditionally stored this as the ASCII value for 'E', 'o', or 'n'. - * We now accept either that or the (case-insensitive) character itself (but - * still always write it the old way, for backward compatibility). - */ - tmp_str = nm_keyfile_plugin_kf_get_value(info->keyfile, setting_name, key, &err); - if (err) - goto out_err; - - if (tmp_str && tmp_str[0] != '\0' && tmp_str[1] == '\0') { - /* the ASCII characters like 'E' are taken directly... */ - parity = _parity_from_char(tmp_str[0]); - if (parity >= 0) - goto parity_good; - } - - i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT, G_MAXINT, G_MININT64); - if (i64 != G_MININT64 && errno == 0) { - if ((parity = _parity_from_char(i64)) >= 0) { - /* another oddity: the string is a valid number. However, if the numeric values - * is one of the supported ASCII codes, accept it (like 69 for 'E'). - */ - goto parity_good; - } - - /* Finally, take the numeric value as is. */ - parity = i64; - goto parity_good; - } - - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid parity value '%s'"), - tmp_str ?: ""); - return; - -parity_good: - nm_g_object_set_property_enum(G_OBJECT(setting), - key, - NM_TYPE_SETTING_SERIAL_PARITY, - parity, - &err); - -out_err: - if (!err) - return; - if (nm_keyfile_error_is_not_found(err)) { - /* ignore such errors. The key is not present. */ - return; - } - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid setting: %s"), - err->message); -} - -static void -team_config_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - const char * setting_name = nm_setting_get_name(setting); - gs_free char *conf = NULL; - gs_free_error GError *error = NULL; - - conf = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, key, NULL); - - g_object_set(G_OBJECT(setting), key, conf, NULL); - - if (conf && !nm_setting_verify(setting, NULL, &error)) { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid team configuration: %s"), - error->message); - g_object_set(G_OBJECT(setting), key, NULL, NULL); - } -} - -static void -bridge_vlan_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - gs_unref_ptrarray GPtrArray *vlans = NULL; - gs_free char * value = NULL; - gs_free const char ** strv = NULL; - const char *const * iter; - GError * local = NULL; - NMBridgeVlan * vlan; - - value = nm_keyfile_plugin_kf_get_string(info->keyfile, nm_setting_get_name(setting), key, NULL); - if (!value || !value[0]) - return; - - vlans = g_ptr_array_new_with_free_func((GDestroyNotify) nm_bridge_vlan_unref); - - strv = nm_utils_escaped_tokens_split(value, ","); - if (strv) { - for (iter = strv; *iter; iter++) { - vlan = nm_bridge_vlan_from_str(*iter, &local); - if (!vlan) { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - "invalid bridge VLAN: %s", - local->message); - g_clear_error(&local); - continue; - } - g_ptr_array_add(vlans, vlan); - } - } - - if (vlans->len > 0) - g_object_set(setting, key, vlans, NULL); -} - -static void -qdisc_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - const char * setting_name = nm_setting_get_name(setting); - gs_unref_ptrarray GPtrArray *qdiscs = NULL; - gs_strfreev char ** keys = NULL; - gsize n_keys = 0; - int i; - - keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); - if (n_keys == 0) - return; - - qdiscs = g_ptr_array_new_with_free_func((GDestroyNotify) nm_tc_qdisc_unref); - - for (i = 0; i < n_keys; i++) { - NMTCQdisc * qdisc; - const char * qdisc_parent; - gs_free char *qdisc_rest = NULL; - gs_free char *qdisc_str = NULL; - gs_free_error GError *err = NULL; - - if (!g_str_has_prefix(keys[i], "qdisc.")) - continue; - - qdisc_parent = keys[i] + sizeof("qdisc.") - 1; - qdisc_rest = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, keys[i], NULL); - qdisc_str = g_strdup_printf( - "%s%s %s", - _nm_utils_parse_tc_handle(qdisc_parent, NULL) != TC_H_UNSPEC ? "parent " : "", - qdisc_parent, - qdisc_rest); - - qdisc = nm_utils_tc_qdisc_from_str(qdisc_str, &err); - if (!qdisc) { - handle_warn(info, - keys[i], - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid qdisc: %s"), - err->message); - } else { - g_ptr_array_add(qdiscs, qdisc); - } - } - - if (qdiscs->len >= 1) - g_object_set(setting, key, qdiscs, NULL); -} - -static void -tfilter_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) -{ - const char * setting_name = nm_setting_get_name(setting); - gs_unref_ptrarray GPtrArray *tfilters = NULL; - gs_strfreev char ** keys = NULL; - gsize n_keys = 0; - int i; - - keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, setting_name, &n_keys, NULL); - if (n_keys == 0) - return; - - tfilters = g_ptr_array_new_with_free_func((GDestroyNotify) nm_tc_tfilter_unref); - - for (i = 0; i < n_keys; i++) { - NMTCTfilter * tfilter; - const char * tfilter_parent; - gs_free char *tfilter_rest = NULL; - gs_free char *tfilter_str = NULL; - gs_free_error GError *err = NULL; - - if (!g_str_has_prefix(keys[i], "tfilter.")) - continue; - - tfilter_parent = keys[i] + sizeof("tfilter.") - 1; - tfilter_rest = nm_keyfile_plugin_kf_get_string(info->keyfile, setting_name, keys[i], NULL); - tfilter_str = g_strdup_printf( - "%s%s %s", - _nm_utils_parse_tc_handle(tfilter_parent, NULL) != TC_H_UNSPEC ? "parent " : "", - tfilter_parent, - tfilter_rest); - - tfilter = nm_utils_tc_tfilter_from_str(tfilter_str, &err); - if (!tfilter) { - handle_warn(info, - keys[i], - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid tfilter: %s"), - err->message); - } else { - g_ptr_array_add(tfilters, tfilter); - } - } - - if (tfilters->len >= 1) - g_object_set(setting, key, tfilters, NULL); -} - -/*****************************************************************************/ - -/* Some setting properties also contain setting names, such as - * NMSettingConnection's 'type' property (which specifies the base type of the - * connection, eg ethernet or wifi) or the 802-11-wireless setting's - * 'security' property which specifies whether or not the AP requires - * encryption. This function handles translating those properties' values - * from the real setting name to the more-readable alias. - */ -static void -setting_alias_writer(KeyfileWriterInfo *info, - NMSetting * setting, - const char * key, - const GValue * value) -{ - const char *str, *alias; - - str = g_value_get_string(value); - alias = nm_keyfile_plugin_get_alias_for_setting_name(str); - nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, alias ?: str); -} - -static void -sriov_vfs_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) -{ - GPtrArray *vfs; - guint i; - - vfs = g_value_get_boxed(value); - if (!vfs) - return; - - for (i = 0; i < vfs->len; i++) { - const NMSriovVF *vf = vfs->pdata[i]; - gs_free char * kf_value = NULL; - char kf_key[32]; - - kf_value = nm_utils_sriov_vf_to_str(vf, TRUE, NULL); - if (!kf_value) - continue; - - nm_sprintf_buf(kf_key, "vf.%u", nm_sriov_vf_get_index(vf)); - - nm_keyfile_plugin_kf_set_string(info->keyfile, - nm_setting_get_name(setting), - kf_key, - kf_value); - } -} - -static void -write_array_of_uint(GKeyFile *file, NMSetting *setting, const char *key, const GValue *value) -{ - GArray *array; - - array = g_value_get_boxed(value); - - nm_assert(!array || g_array_get_element_size(array) == sizeof(guint)); - - if (!array || !array->len) - return; - - nm_keyfile_plugin_kf_set_integer_list_uint(file, - nm_setting_get_name(setting), - key, - (const guint *) array->data, - array->len); -} - -static void -dns_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) -{ - char **list; - - list = g_value_get_boxed(value); - if (list && list[0]) { - nm_keyfile_plugin_kf_set_string_list(info->keyfile, - nm_setting_get_name(setting), - key, - (const char **) list, - g_strv_length(list)); - } -} - -static void -ip6_addr_gen_mode_writer(KeyfileWriterInfo *info, - NMSetting * setting, - const char * key, - const GValue * value) -{ - NMSettingIP6ConfigAddrGenMode addr_gen_mode; - gs_free char * str = NULL; - - addr_gen_mode = (NMSettingIP6ConfigAddrGenMode) g_value_get_int(value); - str = nm_utils_enum_to_str(nm_setting_ip6_config_addr_gen_mode_get_type(), addr_gen_mode); - nm_keyfile_plugin_kf_set_string(info->keyfile, nm_setting_get_name(setting), key, str); -} - -static void -write_ip_values(GKeyFile * file, - const char *setting_name, - GPtrArray * array, - const char *gateway, - gboolean is_route) -{ - if (array->len > 0) { - nm_auto_str_buf NMStrBuf output = NM_STR_BUF_INIT(2 * INET_ADDRSTRLEN + 10, FALSE); - int addr_family; - guint i; - const char * addr; - const char * gw; - guint32 plen; - char key_name[64]; - char * key_name_idx; - - addr_family = - nm_streq(setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME) ? AF_INET : AF_INET6; - - strcpy(key_name, is_route ? "route" : "address"); - key_name_idx = key_name + strlen(key_name); - - for (i = 0; i < array->len; i++) { - gint64 metric = -1; - - if (is_route) { - NMIPRoute *route = array->pdata[i]; - - addr = nm_ip_route_get_dest(route); - plen = nm_ip_route_get_prefix(route); - gw = nm_ip_route_get_next_hop(route); - metric = nm_ip_route_get_metric(route); - } else { - NMIPAddress *address = array->pdata[i]; - - addr = nm_ip_address_get_address(address); - plen = nm_ip_address_get_prefix(address); - gw = (i == 0) ? gateway : NULL; - } - - nm_str_buf_set_size(&output, 0, FALSE, FALSE); - nm_str_buf_append_printf(&output, "%s/%u", addr, plen); - if (metric != -1 || gw) { - /* Older versions of the plugin do not support the form - * "a.b.c.d/plen,,metric", so, we always have to write the - * gateway, even if there isn't one. - * The current version supports reading of the above form. - */ - if (!gw) { - if (addr_family == AF_INET) - gw = "0.0.0.0"; - else - gw = "::"; - } - - nm_str_buf_append_c(&output, ','); - nm_str_buf_append(&output, gw); - if (is_route && metric != -1) - nm_str_buf_append_printf(&output, ",%lu", (unsigned long) metric); - } - - sprintf(key_name_idx, "%u", i + 1); - nm_keyfile_plugin_kf_set_string(file, - setting_name, - key_name, - nm_str_buf_get_str(&output)); - - if (is_route) { - gs_free char *attributes = NULL; - - attributes = - nm_utils_format_variant_attributes(_nm_ip_route_get_attributes(array->pdata[i]), - ',', - '='); - if (attributes) { - g_strlcat(key_name, "_options", sizeof(key_name)); - nm_keyfile_plugin_kf_set_string(file, setting_name, key_name, attributes); - } - } - } - } -} - -static void -addr_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) -{ - GPtrArray * array; - const char *setting_name = nm_setting_get_name(setting); - const char *gateway = nm_setting_ip_config_get_gateway(NM_SETTING_IP_CONFIG(setting)); - - array = (GPtrArray *) g_value_get_boxed(value); - if (array && array->len) - write_ip_values(info->keyfile, setting_name, array, gateway, FALSE); -} - -static void -route_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) -{ - GPtrArray * array; - const char *setting_name = nm_setting_get_name(setting); - - array = (GPtrArray *) g_value_get_boxed(value); - if (array && array->len) - write_ip_values(info->keyfile, setting_name, array, NULL, TRUE); -} - -static void -bridge_vlan_writer(KeyfileWriterInfo *info, - NMSetting * setting, - const char * key, - const GValue * value) -{ - GPtrArray *vlans; - - vlans = g_value_get_boxed(value); - if (vlans && vlans->len > 0) { - const guint string_initial_size = vlans->len * 10u; - nm_auto_str_buf NMStrBuf string = NM_STR_BUF_INIT(string_initial_size, FALSE); - guint i; - - for (i = 0; i < vlans->len; i++) { - gs_free char *vlan_str = NULL; - - vlan_str = nm_bridge_vlan_to_str(vlans->pdata[i], NULL); - if (i > 0) - nm_str_buf_append_c(&string, ','); - nm_utils_escaped_tokens_escape_strbuf_assert(vlan_str, ",", &string); - } - - nm_keyfile_plugin_kf_set_string(info->keyfile, - nm_setting_get_name(setting), - "vlans", - nm_str_buf_get_str(&string)); - } -} - -#define ETHERNET_S390_OPTIONS_GROUP_NAME "ethernet-s390-options" - -static void -wired_s390_options_parser_full(KeyfileReaderInfo * info, - const NMMetaSettingInfo * setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty * pip, - NMSetting * setting) -{ - NMSettingWired * s_wired = NM_SETTING_WIRED(setting); - gs_strfreev char **keys = NULL; - gsize n_keys; - gsize i; - - keys = nm_keyfile_plugin_kf_get_keys(info->keyfile, - ETHERNET_S390_OPTIONS_GROUP_NAME, - &n_keys, - NULL); - for (i = 0; i < n_keys; i++) { - gs_free char *value = NULL; - gs_free char *key_to_free = NULL; - - value = nm_keyfile_plugin_kf_get_string(info->keyfile, - ETHERNET_S390_OPTIONS_GROUP_NAME, - keys[i], - NULL); - if (!value) - continue; - - nm_setting_wired_add_s390_option(s_wired, - nm_keyfile_key_decode(keys[i], &key_to_free), - value); - } -} - -static void -wired_s390_options_writer_full(KeyfileWriterInfo * info, - const NMMetaSettingInfo * setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty * pip, - NMSetting * setting) -{ - NMSettingWired *s_wired = NM_SETTING_WIRED(setting); - guint i, n; - - n = nm_setting_wired_get_num_s390_options(s_wired); - for (i = 0; i < n; i++) { - gs_free char *key_to_free = NULL; - const char * opt_key; - const char * opt_val; - - nm_setting_wired_get_s390_option(s_wired, i, &opt_key, &opt_val); - nm_keyfile_plugin_kf_set_string(info->keyfile, - ETHERNET_S390_OPTIONS_GROUP_NAME, - nm_keyfile_key_encode(opt_key, &key_to_free), - opt_val); - } -} - -static void -ip_routing_rule_writer_full(KeyfileWriterInfo * info, - const NMMetaSettingInfo * setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty * pip, - NMSetting * setting) -{ - const char * setting_name = nm_setting_get_name(setting); - NMSettingIPConfig *s_ip = NM_SETTING_IP_CONFIG(setting); - guint i, j, n; - char key_name_full[100] = "routing-rule"; - char * key_name_num = &key_name_full[NM_STRLEN("routing-rule")]; - - n = nm_setting_ip_config_get_num_routing_rules(s_ip); - j = 0; - for (i = 0; i < n; i++) { - NMIPRoutingRule *rule = nm_setting_ip_config_get_routing_rule(s_ip, i); - gs_free char * str = NULL; - - str = - nm_ip_routing_rule_to_string(rule, NM_IP_ROUTING_RULE_AS_STRING_FLAGS_NONE, NULL, NULL); - if (!str) - continue; - - sprintf(key_name_num, "%u", ++j); - nm_keyfile_plugin_kf_set_string(info->keyfile, setting_name, key_name_full, str); - } -} - -static void -qdisc_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) -{ - nm_auto_free_gstring GString *key_name = NULL; - nm_auto_free_gstring GString *value_str = NULL; - GPtrArray * array; - guint i; - - array = g_value_get_boxed(value); - if (!array || !array->len) - return; - - for (i = 0; i < array->len; i++) { - NMTCQdisc *qdisc = array->pdata[i]; - - nm_gstring_prepare(&key_name); - nm_gstring_prepare(&value_str); - - g_string_append(key_name, "qdisc."); - _nm_utils_string_append_tc_parent(key_name, NULL, nm_tc_qdisc_get_parent(qdisc)); - _nm_utils_string_append_tc_qdisc_rest(value_str, qdisc); - - nm_keyfile_plugin_kf_set_string(info->keyfile, - NM_SETTING_TC_CONFIG_SETTING_NAME, - key_name->str, - value_str->str); - } -} - -static void -tfilter_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) -{ - nm_auto_free_gstring GString *key_name = NULL; - nm_auto_free_gstring GString *value_str = NULL; - GPtrArray * array; - guint i; - - array = g_value_get_boxed(value); - if (!array || !array->len) - return; - - for (i = 0; i < array->len; i++) { - NMTCTfilter *tfilter = array->pdata[i]; - - nm_gstring_prepare(&key_name); - nm_gstring_prepare(&value_str); - - g_string_append(key_name, "tfilter."); - _nm_utils_string_append_tc_parent(key_name, NULL, nm_tc_tfilter_get_parent(tfilter)); - _nm_utils_string_append_tc_tfilter_rest(value_str, tfilter, NULL); - - nm_keyfile_plugin_kf_set_string(info->keyfile, - NM_SETTING_TC_CONFIG_SETTING_NAME, - key_name->str, - value_str->str); - } -} - -static void -write_hash_of_string(GKeyFile *file, NMSetting *setting, const char *key, const GValue *value) -{ - GHashTable * hash; - const char * group_name = nm_setting_get_name(setting); - gboolean vpn_secrets = FALSE; - gs_free const char **keys = NULL; - guint i, l; - - nm_assert((NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_DATA)) - || (NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_SECRETS)) - || (NM_IS_SETTING_BOND(setting) && nm_streq(key, NM_SETTING_BOND_OPTIONS)) - || (NM_IS_SETTING_USER(setting) && nm_streq(key, NM_SETTING_USER_DATA))); - - /* Write VPN secrets out to a different group to keep them separate */ - if (NM_IS_SETTING_VPN(setting) && nm_streq(key, NM_SETTING_VPN_SECRETS)) { - group_name = NM_KEYFILE_GROUP_VPN_SECRETS; - vpn_secrets = TRUE; - } - - hash = g_value_get_boxed(value); - - keys = nm_utils_strdict_get_keys(hash, TRUE, &l); - for (i = 0; i < l; i++) { - gs_free char *to_free = NULL; - const char * property, *data; - - property = keys[i]; - - /* Handle VPN secrets specially; they are nested in the property's hash; - * we don't want to write them if the secret is not saved, not required, - * or owned by a user's secret agent. - */ - if (vpn_secrets) { - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - - if (!nm_setting_get_secret_flags(setting, property, &secret_flags, NULL)) - nm_assert_not_reached(); - if (!_secret_flags_persist_secret(secret_flags)) - continue; - } - - data = g_hash_table_lookup(hash, property); - nm_keyfile_plugin_kf_set_string(file, - group_name, - nm_keyfile_key_encode(property, &to_free), - data); - } -} - -static void -ssid_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) -{ - GBytes * bytes; - const guint8 *ssid_data; - gsize ssid_len; - const char * setting_name = nm_setting_get_name(setting); - gboolean new_format = TRUE; - gsize semicolons = 0; - gsize i; - - g_return_if_fail(G_VALUE_HOLDS(value, G_TYPE_BYTES)); - - bytes = g_value_get_boxed(value); - if (!bytes) - return; - ssid_data = g_bytes_get_data(bytes, &ssid_len); - if (!ssid_data || !ssid_len) { - nm_keyfile_plugin_kf_set_string(info->keyfile, setting_name, key, ""); - return; - } - - /* Check whether each byte is printable. If not, we have to use an - * integer list, otherwise we can just use a string. - */ - for (i = 0; i < ssid_len; i++) { - const char c = ssid_data[i]; - - if (!g_ascii_isprint(c)) { - new_format = FALSE; - break; - } - if (c == ';') - semicolons++; - } - - if (new_format) { - gs_free char *ssid = NULL; - - if (semicolons == 0) - ssid = g_strndup((char *) ssid_data, ssid_len); - else { - /* Escape semicolons with backslashes to make strings - * containing ';', such as '16;17;' unambiguous */ - gsize j = 0; - - ssid = g_malloc(ssid_len + semicolons + 1); - for (i = 0; i < ssid_len; i++) { - if (ssid_data[i] == ';') - ssid[j++] = '\\'; - ssid[j++] = ssid_data[i]; - } - ssid[j] = '\0'; - } - nm_keyfile_plugin_kf_set_string(info->keyfile, setting_name, key, ssid); - } else - nm_keyfile_plugin_kf_set_integer_list_uint8(info->keyfile, - setting_name, - key, - ssid_data, - ssid_len); -} - -static void -password_raw_writer(KeyfileWriterInfo *info, - NMSetting * setting, - const char * key, - const GValue * value) -{ - const char * setting_name = nm_setting_get_name(setting); - GBytes * array; - gsize len; - const guint8 *data; - - g_return_if_fail(G_VALUE_HOLDS(value, G_TYPE_BYTES)); - - array = (GBytes *) g_value_get_boxed(value); - if (!array) - return; - data = g_bytes_get_data(array, &len); - if (!data) - len = 0; - nm_keyfile_plugin_kf_set_integer_list_uint8(info->keyfile, setting_name, key, data, len); -} - -/*****************************************************************************/ - -static void -cert_writer_default(NMConnection * connection, - GKeyFile * file, - NMSetting8021x * setting, - const char * setting_name, - const NMSetting8021xSchemeVtable *vtable) -{ - NMSetting8021xCKScheme scheme; - - scheme = vtable->scheme_func(setting); - if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) { - gs_free char *path_free = NULL; - gs_free char *base_dir = NULL; - gs_free char *tmp = NULL; - const char * path; - - path = vtable->path_func(setting); - g_assert(path); - - /* If the path is relative, make it an absolute path. - * Relative paths make a keyfile not easily usable in another - * context. */ - if (path[0] && path[0] != '/') { - base_dir = g_get_current_dir(); - path_free = g_strconcat(base_dir, "/", path, NULL); - path = path_free; - } else - base_dir = g_path_get_dirname(path); - - /* path cannot start with "file://" or "data:;base64,", because it is an absolute path. - * Still, make sure that a prefix-less path will be recognized. This can happen - * for example if the path is longer then 500 chars. */ - tmp = nm_keyfile_detect_unqualified_path_scheme(base_dir, path, -1, FALSE, NULL); - if (tmp) - nm_clear_g_free(&tmp); - else { - tmp = g_strconcat(NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL); - path = tmp; - } - - /* 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, vtable->setting_key, path); - } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) { - GBytes * blob; - const guint8 *blob_data; - gsize blob_len; - gs_free char *blob_base64 = NULL; - gs_free char *val = NULL; - - blob = vtable->blob_func(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, vtable->setting_key, val); - } else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) { - nm_keyfile_plugin_kf_set_string(file, - setting_name, - vtable->setting_key, - vtable->uri_func(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 - * case, we don't expect the writer to be called, because the default value - * will not be serialized. - * The only other reason for the scheme to be UNKNOWN is an invalid cert. - * But our connection verifies, so that cannot happen either. */ - g_return_if_reached(); - } -} - -static void -cert_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) -{ - const NMSetting8021xSchemeVtable *vtable = NULL; - const char * setting_name; - guint i; - - for (i = 0; nm_setting_8021x_scheme_vtable[i].setting_key; i++) { - if (nm_streq0(nm_setting_8021x_scheme_vtable[i].setting_key, key)) { - vtable = &nm_setting_8021x_scheme_vtable[i]; - break; - } - } - if (!vtable) - g_return_if_reached(); - - setting_name = nm_setting_get_name(NM_SETTING(setting)); - - if (info->write_handler) { - NMKeyfileHandlerData handler_data; - - _key_file_handler_data_init_write(&handler_data, - NM_KEYFILE_HANDLER_TYPE_WRITE_CERT, - info, - setting_name, - vtable->setting_key, - setting, - key); - handler_data.write_cert = (NMKeyfileHandlerDataWriteCert){ - .vtable = vtable, - }; - - if (info->write_handler(info->connection, - info->keyfile, - NM_KEYFILE_HANDLER_TYPE_WRITE_CERT, - &handler_data, - info->user_data)) - return; - if (info->error) - return; - } - - cert_writer_default(info->connection, - info->keyfile, - NM_SETTING_802_1X(setting), - setting_name, - vtable); -} - -/*****************************************************************************/ - -struct _ParseInfoProperty { - const char *property_name; - union { - void (*parser)(KeyfileReaderInfo *info, NMSetting *setting, const char *key); - void (*parser_full)(KeyfileReaderInfo * info, - const NMMetaSettingInfo * setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty * pip, - NMSetting * setting); - }; - union { - void (*writer)(KeyfileWriterInfo *info, - NMSetting * setting, - const char * key, - const GValue * value); - void (*writer_full)(KeyfileWriterInfo * info, - const NMMetaSettingInfo * setting_info, - const NMSettInfoProperty *property_info, - const ParseInfoProperty * pip, - NMSetting * setting); - }; - bool parser_skip; - bool parser_no_check_key : 1; - bool writer_skip : 1; - bool has_writer_full : 1; - bool has_parser_full : 1; - - /* usually, we skip to write values that have their - * default value. By setting this flag to TRUE, also - * default values are written. */ - bool writer_persist_default : 1; -}; - -#define PARSE_INFO_PROPERTY(_property_name, ...) \ - (&((const ParseInfoProperty){.property_name = _property_name, __VA_ARGS__})) - -#define PARSE_INFO_PROPERTIES(...) \ - .properties = ((const ParseInfoProperty *const[]){ \ - __VA_ARGS__ NULL, \ - }) - -typedef struct { - const ParseInfoProperty *const *properties; -} ParseInfoSetting; - -#define PARSE_INFO_SETTING(setting_type, ...) \ - [setting_type] = (&((const ParseInfoSetting){__VA_ARGS__})) - -static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_WIRELESS, - PARSE_INFO_PROPERTIES( - PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_BSSID, .parser = mac_address_parser_ETHER, ), - PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS, - .parser = mac_address_parser_ETHER_cloned, ), - PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_MAC_ADDRESS, - .parser = mac_address_parser_ETHER, ), - PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_SSID, - .parser = ssid_parser, - .writer = ssid_writer, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_802_1X, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_802_1X_CA_CERT, - .parser = cert_parser, - .writer = cert_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_802_1X_CLIENT_CERT, - .parser = cert_parser, - .writer = cert_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PASSWORD_RAW, - .parser = password_raw_parser, - .writer = password_raw_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PHASE2_CA_CERT, - .parser = cert_parser, - .writer = cert_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PHASE2_CLIENT_CERT, - .parser = cert_parser, - .writer = cert_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, - .parser = cert_parser, - .writer = cert_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_802_1X_PRIVATE_KEY, - .parser = cert_parser, - .writer = cert_writer, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_WIRED, - PARSE_INFO_PROPERTIES( - PARSE_INFO_PROPERTY(NM_SETTING_WIRED_CLONED_MAC_ADDRESS, - .parser = mac_address_parser_ETHER_cloned, ), - PARSE_INFO_PROPERTY(NM_SETTING_WIRED_MAC_ADDRESS, .parser = mac_address_parser_ETHER, ), - PARSE_INFO_PROPERTY(NM_SETTING_WIRED_S390_OPTIONS, - .parser_no_check_key = TRUE, - .parser_full = wired_s390_options_parser_full, - .writer_full = wired_s390_options_writer_full, - .has_parser_full = TRUE, - .has_writer_full = TRUE, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_BLUETOOTH, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BLUETOOTH_BDADDR, - .parser = mac_address_parser_ETHER, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_BOND, - PARSE_INFO_PROPERTIES( - PARSE_INFO_PROPERTY(NM_SETTING_BOND_OPTIONS, .parser_no_check_key = TRUE, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_BRIDGE, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_MAC_ADDRESS, - .parser = mac_address_parser_ETHER, ), - PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_VLANS, - .parser_no_check_key = TRUE, - .parser = bridge_vlan_parser, - .writer = bridge_vlan_writer, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_BRIDGE_PORT, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_PORT_VLANS, - .parser_no_check_key = TRUE, - .parser = bridge_vlan_parser, - .writer = bridge_vlan_writer, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_CONNECTION, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_CONNECTION_READ_ONLY, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_CONNECTION_TYPE, - .parser = setting_alias_parser, - .writer = setting_alias_writer, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_INFINIBAND, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_INFINIBAND_MAC_ADDRESS, - .parser = mac_address_parser_INFINIBAND, ), ), ), - PARSE_INFO_SETTING(NM_META_SETTING_TYPE_IP4_CONFIG, - PARSE_INFO_PROPERTIES( - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ADDRESSES, - .parser_no_check_key = TRUE, - .parser = ip_address_or_route_parser, - .writer = addr_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS, - .parser_no_check_key = TRUE, - .parser = ip_dns_parser, - .writer = dns_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, - .parser_no_check_key = TRUE, - .parser = ip_address_or_route_parser, - .writer = route_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTING_RULES, - .parser_no_check_key = TRUE, - .parser_full = ip_routing_rule_parser_full, - .writer_full = ip_routing_rule_writer_full, - .has_parser_full = TRUE, - .has_writer_full = TRUE, ), ), ), - PARSE_INFO_SETTING(NM_META_SETTING_TYPE_IP6_CONFIG, - PARSE_INFO_PROPERTIES( - PARSE_INFO_PROPERTY(NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE, - .parser_no_check_key = TRUE, - .parser = ip6_addr_gen_mode_parser, - .writer = ip6_addr_gen_mode_writer, - .writer_persist_default = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ADDRESSES, - .parser_no_check_key = TRUE, - .parser = ip_address_or_route_parser, - .writer = addr_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_DNS, - .parser_no_check_key = TRUE, - .parser = ip_dns_parser, - .writer = dns_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_GATEWAY, .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTES, - .parser_no_check_key = TRUE, - .parser = ip_address_or_route_parser, - .writer = route_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_IP_CONFIG_ROUTING_RULES, - .parser_no_check_key = TRUE, - .parser_full = ip_routing_rule_parser_full, - .writer_full = ip_routing_rule_writer_full, - .has_parser_full = TRUE, - .has_writer_full = TRUE, ), ), ), - PARSE_INFO_SETTING(NM_META_SETTING_TYPE_SERIAL, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_SERIAL_PARITY, - .parser = parity_parser, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_SRIOV, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_SRIOV_VFS, - .parser_no_check_key = TRUE, - .parser = sriov_vfs_parser, - .writer = sriov_vfs_writer, ), ), ), - PARSE_INFO_SETTING(NM_META_SETTING_TYPE_TC_CONFIG, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_TC_CONFIG_QDISCS, - .parser_no_check_key = TRUE, - .parser = qdisc_parser, - .writer = qdisc_writer, ), - PARSE_INFO_PROPERTY(NM_SETTING_TC_CONFIG_TFILTERS, - .parser_no_check_key = TRUE, - .parser = tfilter_parser, - .writer = tfilter_writer, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_TEAM, - PARSE_INFO_PROPERTIES( - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_CONFIG, .parser = team_config_parser, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_LINK_WATCHERS, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_MCAST_REJOIN_COUNT, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER, .parser_skip = TRUE, .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_ACTIVE, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_FAST_RATE, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_MIN_PORTS, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_SYS_PRIO, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_TX_BALANCER, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_RUNNER_TX_HASH, - .parser_skip = TRUE, - .writer_skip = TRUE, ), ), ), - PARSE_INFO_SETTING(NM_META_SETTING_TYPE_TEAM_PORT, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_TEAM_CONFIG, - .parser = team_config_parser, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_LACP_KEY, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_LACP_PRIO, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_LINK_WATCHERS, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_PRIO, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_QUEUE_ID, - .parser_skip = TRUE, - .writer_skip = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_TEAM_PORT_STICKY, - .parser_skip = TRUE, - .writer_skip = TRUE, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_USER, - PARSE_INFO_PROPERTIES( - PARSE_INFO_PROPERTY(NM_SETTING_USER_DATA, .parser_no_check_key = TRUE, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_VLAN, - PARSE_INFO_PROPERTIES( - PARSE_INFO_PROPERTY(NM_SETTING_VLAN_FLAGS, .writer_persist_default = TRUE, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_VPN, - PARSE_INFO_PROPERTIES( - PARSE_INFO_PROPERTY(NM_SETTING_VPN_DATA, .parser_no_check_key = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_VPN_PERSISTENT, .parser_no_check_key = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_VPN_SECRETS, .parser_no_check_key = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_VPN_SERVICE_TYPE, .parser_no_check_key = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_VPN_TIMEOUT, .parser_no_check_key = TRUE, ), - PARSE_INFO_PROPERTY(NM_SETTING_VPN_USER_NAME, .parser_no_check_key = TRUE, ), ), ), - PARSE_INFO_SETTING( - NM_META_SETTING_TYPE_WIMAX, - PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_WIMAX_MAC_ADDRESS, - .parser = mac_address_parser_ETHER, ), ), ), -}; - -static void -_parse_info_find(NMSetting * setting, - const char * property_name, - const NMMetaSettingInfo **out_setting_info, - const ParseInfoSetting ** out_parse_info_setting, - const ParseInfoProperty **out_parse_info_property) -{ - const NMMetaSettingInfo *setting_info; - const ParseInfoSetting * pis; - const ParseInfoProperty *pip; - -#if NM_MORE_ASSERTS > 10 - { - guint i, j; - static int asserted = FALSE; - - if (!asserted) { - for (i = 0; i < G_N_ELEMENTS(parse_infos); i++) { - pis = parse_infos[i]; - - if (!pis) - continue; - if (!pis->properties) - continue; - - g_assert(pis->properties[0]); - for (j = 0; pis->properties[j]; j++) { - const ParseInfoProperty *pip0; - const ParseInfoProperty *pipj = pis->properties[j]; - - g_assert(pipj->property_name); - if (j > 0 && (pip0 = pis->properties[j - 1]) - && strcmp(pip0->property_name, pipj->property_name) >= 0) { - g_error("Wrong order at index #%d.%d: \"%s.%s\" before \"%s.%s\"", - i, - j - 1, - nm_meta_setting_infos[i].setting_name, - pip0->property_name, - nm_meta_setting_infos[i].setting_name, - pipj->property_name); - } - } - } - asserted = TRUE; - } - } -#endif - - if (!NM_IS_SETTING(setting) || !(setting_info = NM_SETTING_GET_CLASS(setting)->setting_info)) { - /* handle invalid setting objects gracefully. */ - NM_SET_OUT(out_setting_info, NULL); - NM_SET_OUT(out_parse_info_setting, NULL); - NM_SET_OUT(out_parse_info_property, NULL); - return; - } - - nm_assert(setting_info->setting_name); - nm_assert(_NM_INT_NOT_NEGATIVE(setting_info->meta_type)); - nm_assert(setting_info->meta_type < G_N_ELEMENTS(parse_infos)); - - pis = parse_infos[setting_info->meta_type]; - - pip = NULL; - if (pis && property_name) { - gssize idx; - - G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(ParseInfoProperty, property_name) == 0); - - idx = nm_utils_ptrarray_find_binary_search((gconstpointer *) pis->properties, - NM_PTRARRAY_LEN(pis->properties), - &property_name, - nm_strcmp_p_with_data, - NULL, - NULL, - NULL); - if (idx >= 0) - pip = pis->properties[idx]; - } - - NM_SET_OUT(out_setting_info, setting_info); - NM_SET_OUT(out_parse_info_setting, pis); - NM_SET_OUT(out_parse_info_property, pip); -} - -/*****************************************************************************/ - -static void -read_one_setting_value(KeyfileReaderInfo * info, - NMSetting * setting, - const NMSettInfoProperty *property_info) -{ - GKeyFile * keyfile = info->keyfile; - gs_free_error GError * err = NULL; - const NMMetaSettingInfo *setting_info; - const ParseInfoProperty *pip; - gs_free char * tmp_str = NULL; - const char * key; - GType type; - guint64 u64; - gint64 i64; - - nm_assert(!info->error); - nm_assert(!property_info->param_spec - || nm_streq(property_info->param_spec->name, property_info->name)); - - key = property_info->name; - - _parse_info_find(setting, key, &setting_info, NULL, &pip); - - nm_assert(setting_info); - - if (!pip) { - if (nm_streq(key, NM_SETTING_NAME)) - return; - if (!property_info->param_spec) - return; - if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) - != G_PARAM_WRITABLE) - return; - } else { - if (pip->parser_skip) - return; - if (pip->has_parser_full) { - pip->parser_full(info, setting_info, property_info, pip, setting); - return; - } - } - - nm_assert(property_info->param_spec); - nm_assert((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) - == G_PARAM_WRITABLE); - - /* Check for the exact key in the GKeyFile if required. Most setting - * properties map 1:1 to a key in the GKeyFile, but for those properties - * like IP addresses and routes where more than one value is actually - * encoded by the setting property, this won't be true. - */ - if ((!pip || !pip->parser_no_check_key) - && !nm_keyfile_plugin_kf_has_key(keyfile, setting_info->setting_name, key, &err)) { - /* Key doesn't exist or an error occurred, thus nothing to do. */ - if (err) { - if (!handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("error loading setting value: %s"), - err->message)) - return; - } - return; - } - - if (pip && pip->parser) { - pip->parser(info, setting, key); - return; - } - - type = G_PARAM_SPEC_VALUE_TYPE(property_info->param_spec); - - if (type == G_TYPE_STRING) { - gs_free char *str_val = NULL; - - str_val = nm_keyfile_plugin_kf_get_string(keyfile, setting_info->setting_name, key, &err); - if (!err) - nm_g_object_set_property_string_take(G_OBJECT(setting), - key, - g_steal_pointer(&str_val), - &err); - } else if (type == G_TYPE_UINT) { - tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); - if (!err) { - u64 = _nm_utils_ascii_str_to_uint64(tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64); - if (u64 == G_MAXUINT64 && errno != 0) { - g_set_error_literal(&err, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_uint(G_OBJECT(setting), key, u64, &err); - } - } else if (type == G_TYPE_INT) { - tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); - if (!err) { - i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT, G_MAXINT, G_MININT64); - if (i64 == G_MININT64 && errno != 0) { - g_set_error_literal(&err, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_int(G_OBJECT(setting), key, i64, &err); - } - } else if (type == G_TYPE_BOOLEAN) { - gboolean bool_val; - - bool_val = nm_keyfile_plugin_kf_get_boolean(keyfile, setting_info->setting_name, key, &err); - if (!err) - nm_g_object_set_property_boolean(G_OBJECT(setting), key, bool_val, &err); - } else if (type == G_TYPE_CHAR) { - tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); - if (!err) { - /* As documented by glib, G_TYPE_CHAR is really a (signed!) gint8. */ - i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT8, G_MAXINT8, G_MININT64); - if (i64 == G_MININT64 && errno != 0) { - g_set_error_literal(&err, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_char(G_OBJECT(setting), key, i64, &err); - } - } else if (type == G_TYPE_UINT64) { - tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); - if (!err) { - u64 = _nm_utils_ascii_str_to_uint64(tmp_str, 0, 0, G_MAXUINT64, G_MAXUINT64); - if (u64 == G_MAXUINT64 && errno != 0) { - g_set_error_literal(&err, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_uint64(G_OBJECT(setting), key, u64, &err); - } - } else if (type == G_TYPE_INT64) { - tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); - if (!err) { - i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT64, G_MAXINT64, G_MAXINT64); - if (i64 == G_MAXINT64 && errno != 0) { - g_set_error_literal(&err, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_int64(G_OBJECT(setting), key, i64, &err); - } - } else if (type == G_TYPE_BYTES) { - nm_auto_unref_bytearray GByteArray *array = NULL; - gs_unref_bytes GBytes *bytes = NULL; - gs_free guint *tmp = NULL; - gsize length; - int i; - gboolean already_warned = FALSE; - - tmp = nm_keyfile_plugin_kf_get_integer_list_uint(keyfile, - setting_info->setting_name, - key, - &length, - NULL); - - array = g_byte_array_sized_new(length); - for (i = 0; i < length; i++) { - const guint val = tmp[i]; - unsigned char v = (unsigned char) (val & 0xFF); - - if (val > 255u) { - if (!already_warned - && !handle_warn( - info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring invalid byte element '%u' (not between 0 and 255 inclusive)"), - val)) - return; - already_warned = TRUE; - } else - g_byte_array_append(array, (const unsigned char *) &v, sizeof(v)); - } - - bytes = g_byte_array_free_to_bytes(g_steal_pointer(&array)); - g_object_set(setting, key, bytes, NULL); - } else if (type == G_TYPE_STRV) { - gs_strfreev char **sa = NULL; - gsize length; - - sa = nm_keyfile_plugin_kf_get_string_list(keyfile, - setting_info->setting_name, - key, - &length, - NULL); - g_object_set(setting, key, sa, NULL); - } else if (type == G_TYPE_HASH_TABLE) { - read_hash_of_string(keyfile, setting, key); - } else if (type == G_TYPE_ARRAY) { - read_array_of_uint(keyfile, setting, key); - } else if (G_TYPE_IS_FLAGS(type)) { - tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); - if (!err) { - u64 = _nm_utils_ascii_str_to_uint64(tmp_str, 0, 0, G_MAXUINT, G_MAXUINT64); - if (u64 == G_MAXUINT64 && errno != 0) { - g_set_error_literal(&err, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_flags(G_OBJECT(setting), key, type, u64, &err); - } - } else if (G_TYPE_IS_ENUM(type)) { - tmp_str = nm_keyfile_plugin_kf_get_value(keyfile, setting_info->setting_name, key, &err); - if (!err) { - i64 = _nm_utils_ascii_str_to_int64(tmp_str, 0, G_MININT, G_MAXINT, G_MAXINT64); - if (i64 == G_MAXINT64 && errno != 0) { - g_set_error_literal(&err, - G_KEY_FILE_ERROR, - G_KEY_FILE_ERROR_INVALID_VALUE, - _("value cannot be interpreted as integer")); - } else - nm_g_object_set_property_enum(G_OBJECT(setting), key, type, i64, &err); - } - } else - g_return_if_reached(); - - if (err) { - if (nm_keyfile_error_is_not_found(err)) { - /* ignore such errors. The key is not present. */ - } else { - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid setting: %s"), - err->message); - } - } -} - -static void -_read_setting(KeyfileReaderInfo *info) -{ - const NMSettInfoSetting *sett_info; - gs_unref_object NMSetting *setting = NULL; - const char * alias; - GType type; - guint i; - - alias = nm_keyfile_plugin_get_setting_name_for_alias(info->group); - if (!alias) - alias = info->group; - - type = nm_setting_lookup_type(alias); - if (!type) { - handle_warn(info, - NULL, - NULL, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid setting name '%s'"), - info->group); - return; - } - - setting = g_object_new(type, NULL); - - info->setting = setting; - - sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting)); - - if (sett_info->detail.gendata_info) { - gs_free char **keys = NULL; - gsize k, n_keys; - - keys = g_key_file_get_keys(info->keyfile, info->group, &n_keys, NULL); - if (!keys) - n_keys = 0; - if (n_keys > 0) { - GHashTable *h = _nm_setting_option_hash(setting, TRUE); - - nm_utils_strv_sort(keys, n_keys); - for (k = 0; k < n_keys; k++) { - gs_free char *key = keys[k]; - gs_free_error GError *local = NULL; - const GVariantType * variant_type; - GVariant * variant; - - /* a GKeyFile can return duplicate keys, there is just no API to make sense - * of them. Skip them. */ - if (k + 1 < n_keys && nm_streq(key, keys[k + 1])) - continue; - - /* currently, the API is very simple. The setting class just returns - * the desired variant type, and keyfile reader will try to parse - * it accordingly. Note, that this does currently not allow, that - * a particular key can contain different variant types, nor is it - * very flexible in general. - * - * We add flexibility when we need it. Keep it simple for now. */ - variant_type = - sett_info->detail.gendata_info->get_variant_type(sett_info, key, &local); - if (!variant_type) { - if (!handle_warn(info, - key, - NULL, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid key '%s.%s'"), - info->group, - key)) - break; - continue; - } - - if (g_variant_type_equal(variant_type, G_VARIANT_TYPE_BOOLEAN)) { - gboolean v; - - v = g_key_file_get_boolean(info->keyfile, info->group, key, &local); - if (local) { - if (!handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not boolean"), - info->group, - key)) - break; - continue; - } - variant = g_variant_new_boolean(v); - } else if (g_variant_type_equal(variant_type, G_VARIANT_TYPE_UINT32)) { - guint64 v; - - v = g_key_file_get_uint64(info->keyfile, info->group, key, &local); - - if (local) { - if (!handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a uint32"), - info->group, - key)) - break; - continue; - } - variant = g_variant_new_uint32((guint32) v); - } else { - nm_assert_not_reached(); - continue; - } - - g_hash_table_insert(h, g_steal_pointer(&key), g_variant_take_ref(variant)); - } - for (; k < n_keys; k++) - g_free(keys[k]); - } - } - - for (i = 0; i < sett_info->property_infos_len; i++) { - read_one_setting_value(info, setting, &sett_info->property_infos[i]); - if (info->error) - goto out; - } - -out: - info->setting = NULL; - if (!info->error) - nm_connection_add_setting(info->connection, g_steal_pointer(&setting)); -} - -static void -_read_setting_wireguard_peer(KeyfileReaderInfo *info) -{ - gs_unref_object NMSettingWireGuard *s_wg_new = NULL; - nm_auto_unref_wgpeer NMWireGuardPeer *peer = NULL; - gs_free_error GError *error = NULL; - NMSettingWireGuard * s_wg; - gs_free char * str = NULL; - const char * cstr = NULL; - const char * key; - gint64 i64; - gs_strfreev char ** sa = NULL; - gsize n_sa; - - peer = nm_wireguard_peer_new(); - - nm_assert(g_str_has_prefix(info->group, NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)); - cstr = &info->group[NM_STRLEN(NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)]; - if (!nm_utils_base64secret_normalize(cstr, NM_WIREGUARD_PUBLIC_KEY_LEN, &str) - || !nm_streq0(str, cstr)) { - /* the group name must be identical to the normalized(!) key, so that it - * is uniquely identified. */ - handle_warn(info, - NULL, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid peer public key in section '%s'"), - info->group); - return; - } - nm_wireguard_peer_set_public_key(peer, cstr, TRUE); - nm_clear_g_free(&str); - - key = NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY; - str = nm_keyfile_plugin_kf_get_string(info->keyfile, info->group, key, NULL); - if (str) { - if (!nm_wireguard_peer_set_preshared_key(peer, str, FALSE)) { - if (!handle_warn(info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a valid 256 bit key in base64 encoding"), - info->group, - key)) - return; - } - nm_clear_g_free(&str); - } - - key = NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS; - i64 = nm_keyfile_plugin_kf_get_int64(info->keyfile, - info->group, - key, - 0, - 0, - NM_SETTING_SECRET_FLAG_ALL, - -1, - NULL); - if (errno != ENODATA) { - if (i64 == -1 || !_nm_setting_secret_flags_valid(i64)) { - if (!handle_warn(info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a valid secret flag"), - info->group, - key)) - return; - } else - nm_wireguard_peer_set_preshared_key_flags(peer, i64); - } - - key = NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE; - i64 = nm_keyfile_plugin_kf_get_int64(info->keyfile, - info->group, - key, - 0, - 0, - G_MAXUINT32, - -1, - NULL); - if (errno != ENODATA) { - if (i64 == -1) { - if (!handle_warn(info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a integer in range 0 to 2^32"), - info->group, - key)) - return; - } else - nm_wireguard_peer_set_persistent_keepalive(peer, i64); - } - - key = NM_WIREGUARD_PEER_ATTR_ENDPOINT; - str = nm_keyfile_plugin_kf_get_string(info->keyfile, info->group, key, NULL); - if (str && str[0]) { - if (!nm_wireguard_peer_set_endpoint(peer, str, FALSE)) { - if (!handle_warn(info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' is not a valid endpoint"), - info->group, - key)) - return; - } - } - nm_clear_g_free(&str); - - key = NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS; - sa = nm_keyfile_plugin_kf_get_string_list(info->keyfile, info->group, key, &n_sa, NULL); - if (n_sa > 0) { - gboolean has_error = FALSE; - gsize i; - - for (i = 0; i < n_sa; i++) { - if (!nm_utils_parse_inaddr_prefix_bin(AF_UNSPEC, sa[i], NULL, NULL, NULL)) { - has_error = TRUE; - continue; - } - nm_wireguard_peer_append_allowed_ip(peer, sa[i], TRUE); - } - if (has_error) { - if (!handle_warn(info, - key, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("key '%s.%s' has invalid allowed-ips"), - info->group, - key)) - return; - } - } - - if (info->error) - return; - - if (!nm_wireguard_peer_is_valid(peer, TRUE, TRUE, &error)) { - handle_warn(info, - NULL, - NM_SETTING_WIREGUARD_PEERS, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("peer '%s' is invalid: %s"), - info->group, - error->message); - return; - } - - s_wg = NM_SETTING_WIREGUARD( - nm_connection_get_setting(info->connection, NM_TYPE_SETTING_WIREGUARD)); - if (!s_wg) { - s_wg_new = NM_SETTING_WIREGUARD(nm_setting_wireguard_new()); - s_wg = s_wg_new; - } - - nm_setting_wireguard_append_peer(s_wg, peer); - - if (s_wg_new) { - nm_connection_add_setting(info->connection, NM_SETTING(g_steal_pointer(&s_wg_new))); - } -} - -static void -_read_setting_vpn_secrets(KeyfileReaderInfo *info) -{ - gs_strfreev char **keys = NULL; - gsize i, n_keys; - NMSettingVpn * s_vpn; - - s_vpn = nm_connection_get_setting_vpn(info->connection); - if (!s_vpn) { - /* if we don't also have a [vpn] section (which must be parsed earlier), - * we don't do anything. */ - nm_assert(!g_key_file_has_group(info->keyfile, "vpn")); - return; - } - - keys = - nm_keyfile_plugin_kf_get_keys(info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, &n_keys, NULL); - for (i = 0; i < n_keys; i++) { - gs_free char *secret = NULL; - - secret = nm_keyfile_plugin_kf_get_string(info->keyfile, - NM_KEYFILE_GROUP_VPN_SECRETS, - keys[i], - NULL); - if (secret) - nm_setting_vpn_add_secret(s_vpn, keys[i], secret); - } -} - -gboolean -nm_keyfile_read_ensure_id(NMConnection *connection, const char *fallback_id) -{ - NMSettingConnection *s_con; - - g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); - g_return_val_if_fail(fallback_id, FALSE); - - s_con = nm_connection_get_setting_connection(connection); - g_return_val_if_fail(NM_IS_SETTING_CONNECTION(s_con), FALSE); - - if (nm_setting_connection_get_id(s_con)) - return FALSE; - - g_object_set(s_con, NM_SETTING_CONNECTION_ID, fallback_id, NULL); - return TRUE; -} - -gboolean -nm_keyfile_read_ensure_uuid(NMConnection *connection, const char *fallback_uuid_seed) -{ - NMSettingConnection *s_con; - gs_free char * hashed_uuid = NULL; - - g_return_val_if_fail(NM_IS_CONNECTION(connection), FALSE); - g_return_val_if_fail(fallback_uuid_seed, FALSE); - - s_con = nm_connection_get_setting_connection(connection); - g_return_val_if_fail(NM_IS_SETTING_CONNECTION(s_con), FALSE); - - if (nm_setting_connection_get_uuid(s_con)) - return FALSE; - - hashed_uuid = _nm_utils_uuid_generate_from_strings("keyfile", fallback_uuid_seed, NULL); - g_object_set(s_con, NM_SETTING_CONNECTION_UUID, hashed_uuid, NULL); - return TRUE; -} - -/** - * nm_keyfile_read: - * @keyfile: the keyfile from which to create the connection - * @base_dir: when reading certificates from files with relative name, - * the relative path is made absolute using @base_dir. This must - * be an absolute path. - * @handler_flags: the #NMKeyfileHandlerFlags. - * @handler: read handler - * @user_data: user data for read handler - * @error: error - * - * Tries to create a NMConnection from a keyfile. The resulting keyfile is - * not normalized and might not even verify. - * - * Returns: (transfer full): on success, returns the created connection. - */ -NMConnection * -nm_keyfile_read(GKeyFile * keyfile, - const char * base_dir, - NMKeyfileHandlerFlags handler_flags, - NMKeyfileReadHandler handler, - void * user_data, - GError ** error) -{ - gs_unref_object NMConnection *connection = NULL; - NMSettingConnection * s_con; - gs_strfreev char ** groups = NULL; - gsize n_groups; - gsize i; - gboolean vpn_secrets = FALSE; - KeyfileReaderInfo info; - - g_return_val_if_fail(keyfile, NULL); - g_return_val_if_fail(!error || !*error, NULL); - g_return_val_if_fail(base_dir && base_dir[0] == '/', NULL); - g_return_val_if_fail(handler_flags == NM_KEYFILE_HANDLER_FLAGS_NONE, NULL); - - connection = nm_simple_connection_new(); - - info = (KeyfileReaderInfo){ - .connection = connection, - .keyfile = keyfile, - .base_dir = base_dir, - .read_handler = handler, - .user_data = user_data, - }; - - groups = g_key_file_get_groups(keyfile, &n_groups); - if (!groups) - n_groups = 0; - - for (i = 0; i < n_groups; i++) { - info.group = groups[i]; - - if (nm_streq(groups[i], NM_KEYFILE_GROUP_VPN_SECRETS)) { - /* Only read out secrets when needed */ - vpn_secrets = TRUE; - } else if (NM_STR_HAS_PREFIX(groups[i], NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER)) - _read_setting_wireguard_peer(&info); - else if (NM_IN_STRSET(groups[i], - NM_KEYFILE_GROUP_NMMETA, - ETHERNET_S390_OPTIONS_GROUP_NAME)) { - /* pass */ - } else - _read_setting(&info); - - info.group = NULL; - - if (info.error) - goto out_with_info_error; - } - - s_con = nm_connection_get_setting_connection(connection); - if (!s_con) { - s_con = NM_SETTING_CONNECTION(nm_setting_connection_new()); - nm_connection_add_setting(connection, NM_SETTING(s_con)); - } - - /* Make sure that we have 'interface-name' even if it was specified in the - * "wrong" (ie, deprecated) group. - */ - if (!nm_setting_connection_get_interface_name(s_con) - && nm_setting_connection_get_connection_type(s_con)) { - gs_free char *interface_name = NULL; - - interface_name = g_key_file_get_string(keyfile, - nm_setting_connection_get_connection_type(s_con), - "interface-name", - NULL); - if (interface_name) - g_object_set(s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL); - } - - if (vpn_secrets) { - info.group = NM_KEYFILE_GROUP_VPN_SECRETS; - _read_setting_vpn_secrets(&info); - info.group = NULL; - if (info.error) - goto out_with_info_error; - } - - return g_steal_pointer(&connection); - -out_with_info_error: - g_propagate_error(error, info.error); - return NULL; -} - -/*****************************************************************************/ - -static void -write_setting_value(KeyfileWriterInfo * info, - NMSetting * setting, - const NMSettInfoProperty *property_info) -{ - const NMMetaSettingInfo *setting_info; - const ParseInfoProperty *pip; - const char * key; - char numstr[64]; - GValue value; - GType type; - - nm_assert(!info->error); - nm_assert(!property_info->param_spec - || nm_streq(property_info->param_spec->name, property_info->name)); - - key = property_info->name; - - _parse_info_find(setting, key, &setting_info, NULL, &pip); - - if (!pip) { - if (!setting_info) { - /* the setting type is unknown. That is highly unexpected - * (and as this is currently only called from NetworkManager - * daemon, not possible). - * - * Still, handle it gracefully, because later keyfile writer will become - * public API of libnm, where @setting is (untrusted) user input. - * - * Gracefully here just means: ignore the setting. */ - return; - } - if (!property_info->param_spec) - return; - if (nm_streq(key, NM_SETTING_NAME)) - return; - } else { - if (pip->has_writer_full) { - pip->writer_full(info, setting_info, property_info, pip, setting); - return; - } - if (pip->writer_skip) - return; - } - - nm_assert(property_info->param_spec); - - /* Don't write secrets that are owned by user secret agents or aren't - * supposed to be saved. VPN secrets are handled specially though since - * the secret flags there are in a third-level hash in the 'secrets' - * property. - */ - if ((property_info->param_spec->flags & NM_SETTING_PARAM_SECRET) - && !NM_IS_SETTING_VPN(setting)) { - NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE; - - if (!nm_setting_get_secret_flags(setting, key, &secret_flags, NULL)) - g_return_if_reached(); - if (!_secret_flags_persist_secret(secret_flags)) - return; - } - - value = (GValue){0}; - - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(property_info->param_spec)); - g_object_get_property(G_OBJECT(setting), property_info->param_spec->name, &value); - - if ((!pip || !pip->writer_persist_default) - && g_param_value_defaults(property_info->param_spec, &value)) { - nm_assert(!g_key_file_has_key(info->keyfile, setting_info->setting_name, key, NULL)); - goto out_unset_value; - } - - if (pip && pip->writer) { - pip->writer(info, setting, key, &value); - goto out_unset_value; - } - - type = G_VALUE_TYPE(&value); - if (type == G_TYPE_STRING) { - const char *str; - - str = g_value_get_string(&value); - if (str) - nm_keyfile_plugin_kf_set_string(info->keyfile, setting_info->setting_name, key, str); - } else if (type == G_TYPE_UINT) { - nm_sprintf_buf(numstr, "%u", g_value_get_uint(&value)); - nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_INT) { - nm_sprintf_buf(numstr, "%d", g_value_get_int(&value)); - nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_UINT64) { - nm_sprintf_buf(numstr, "%" G_GUINT64_FORMAT, g_value_get_uint64(&value)); - nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_INT64) { - nm_sprintf_buf(numstr, "%" G_GINT64_FORMAT, g_value_get_int64(&value)); - nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_BOOLEAN) { - nm_keyfile_plugin_kf_set_value(info->keyfile, - setting_info->setting_name, - key, - g_value_get_boolean(&value) ? "true" : "false"); - } else if (type == G_TYPE_CHAR) { - nm_sprintf_buf(numstr, "%d", (int) g_value_get_schar(&value)); - nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); - } else if (type == G_TYPE_BYTES) { - GBytes * bytes; - const guint8 *data; - gsize len = 0; - - bytes = g_value_get_boxed(&value); - data = bytes ? g_bytes_get_data(bytes, &len) : NULL; - - if (data != NULL && len > 0) - nm_keyfile_plugin_kf_set_integer_list_uint8(info->keyfile, - setting_info->setting_name, - key, - data, - len); - } else if (type == G_TYPE_STRV) { - char **array; - - array = (char **) g_value_get_boxed(&value); - nm_keyfile_plugin_kf_set_string_list(info->keyfile, - setting_info->setting_name, - key, - (const char **const) array, - g_strv_length(array)); - } else if (type == G_TYPE_HASH_TABLE) { - write_hash_of_string(info->keyfile, setting, key, &value); - } else if (type == G_TYPE_ARRAY) { - write_array_of_uint(info->keyfile, setting, key, &value); - } else if (G_VALUE_HOLDS_FLAGS(&value)) { - nm_sprintf_buf(numstr, "%u", g_value_get_flags(&value)); - nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); - } else if (G_VALUE_HOLDS_ENUM(&value)) { - nm_sprintf_buf(numstr, "%d", g_value_get_enum(&value)); - nm_keyfile_plugin_kf_set_value(info->keyfile, setting_info->setting_name, key, numstr); - } else - g_return_if_reached(); - -out_unset_value: - g_value_unset(&value); -} - -static void -_write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info) -{ - NMSettingWireGuard *s_wg; - guint i_peer, n_peers; - - s_wg = NM_SETTING_WIREGUARD(setting); - - n_peers = nm_setting_wireguard_get_peers_len(s_wg); - for (i_peer = 0; i_peer < n_peers; i_peer++) { - NMWireGuardPeer * peer = nm_setting_wireguard_get_peer(s_wg, i_peer); - const char * public_key; - char group[NM_STRLEN(NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER) + 200]; - NMSettingSecretFlags secret_flags; - gboolean any_key = FALSE; - guint i_aip, n_aip; - const char * cstr; - guint32 u32; - - public_key = nm_wireguard_peer_get_public_key(peer); - if (!public_key || !public_key[0] - || !NM_STRCHAR_ALL(public_key, ch, nm_sd_utils_unbase64char(ch, TRUE) >= 0)) { - /* invalid peer. Skip it */ - continue; - } - - if (g_snprintf(group, - sizeof(group), - "%s%s", - NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER, - nm_wireguard_peer_get_public_key(peer)) - >= sizeof(group)) { - /* Too long. Not a valid public key. Skip the peer. */ - continue; - } - - cstr = nm_wireguard_peer_get_endpoint(peer); - if (cstr) { - g_key_file_set_string(info->keyfile, group, NM_WIREGUARD_PEER_ATTR_ENDPOINT, cstr); - any_key = TRUE; - } - - secret_flags = nm_wireguard_peer_get_preshared_key_flags(peer); - if (_secret_flags_persist_secret(secret_flags)) { - cstr = nm_wireguard_peer_get_preshared_key(peer); - if (cstr) { - g_key_file_set_string(info->keyfile, - group, - NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY, - cstr); - any_key = TRUE; - } - } - - /* usually, we don't persist the secret-flags 0 (because they are the default). - * For WireGuard peers, the default secret-flags for preshared-key are 4 (not-required). - * So, in this case behave differently: a missing preshared-key-flag setting means - * "not-required". */ - if (secret_flags != NM_SETTING_SECRET_FLAG_NOT_REQUIRED) { - g_key_file_set_int64(info->keyfile, - group, - NM_WIREGUARD_PEER_ATTR_PRESHARED_KEY_FLAGS, - secret_flags); - any_key = TRUE; - } - - u32 = nm_wireguard_peer_get_persistent_keepalive(peer); - if (u32) { - g_key_file_set_uint64(info->keyfile, - group, - NM_WIREGUARD_PEER_ATTR_PERSISTENT_KEEPALIVE, - u32); - any_key = TRUE; - } - - n_aip = nm_wireguard_peer_get_allowed_ips_len(peer); - if (n_aip > 0) { - gs_free const char **strv = NULL; - - strv = g_new(const char *, ((gsize) n_aip) + 1); - for (i_aip = 0; i_aip < n_aip; i_aip++) - strv[i_aip] = nm_wireguard_peer_get_allowed_ip(peer, i_aip, NULL); - strv[n_aip] = NULL; - g_key_file_set_string_list(info->keyfile, - group, - NM_WIREGUARD_PEER_ATTR_ALLOWED_IPS, - strv, - n_aip); - any_key = TRUE; - } - - if (!any_key) { - /* we cannot omit all keys. At an empty endpoint. */ - g_key_file_set_string(info->keyfile, group, NM_WIREGUARD_PEER_ATTR_ENDPOINT, ""); - } - } -} - -GKeyFile * -nm_keyfile_write(NMConnection * connection, - NMKeyfileHandlerFlags handler_flags, - NMKeyfileWriteHandler handler, - void * user_data, - GError ** error) -{ - nm_auto_unref_keyfile GKeyFile *keyfile = NULL; - KeyfileWriterInfo info; - gs_free NMSetting **settings = NULL; - guint i, j, n_settings = 0; - - g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL); - g_return_val_if_fail(!error || !*error, NULL); - g_return_val_if_fail(handler_flags == NM_KEYFILE_HANDLER_FLAGS_NONE, NULL); - - if (!nm_connection_verify(connection, error)) - return NULL; - - keyfile = g_key_file_new(); - - info = (KeyfileWriterInfo){ - .connection = connection, - .keyfile = keyfile, - .error = NULL, - .write_handler = handler, - .user_data = user_data, - }; - - settings = nm_connection_get_settings(connection, &n_settings); - for (i = 0; i < n_settings; i++) { - const NMSettInfoSetting *sett_info; - NMSetting * setting = settings[i]; - const char * setting_name; - const char * setting_alias; - - sett_info = _nm_setting_class_get_sett_info(NM_SETTING_GET_CLASS(setting)); - - setting_name = sett_info->setting_class->setting_info->setting_name; - - if (sett_info->detail.gendata_info) { - guint k, n_keys; - const char *const *keys; - - nm_assert(!nm_keyfile_plugin_get_alias_for_setting_name( - sett_info->setting_class->setting_info->setting_name)); - - n_keys = _nm_setting_option_get_all(setting, &keys, NULL); - - if (n_keys > 0) { - GHashTable *h = _nm_setting_option_hash(setting, FALSE); - - for (k = 0; k < n_keys; k++) { - const char *key = keys[k]; - GVariant * v; - - v = g_hash_table_lookup(h, key); - - if (g_variant_is_of_type(v, G_VARIANT_TYPE_BOOLEAN)) { - g_key_file_set_boolean(info.keyfile, - setting_name, - key, - g_variant_get_boolean(v)); - } else if (g_variant_is_of_type(v, G_VARIANT_TYPE_UINT32)) { - g_key_file_set_uint64(info.keyfile, - setting_name, - key, - (guint64) g_variant_get_uint32(v)); - } else { - /* BUG: The variant type is not implemented. Since the connection - * verifies, this can only mean we either wrongly didn't reject - * the connection as invalid, or we didn't properly implement the - * variant type. */ - nm_assert_not_reached(); - continue; - } - } - } - } - - for (j = 0; j < sett_info->property_infos_len; j++) { - const NMSettInfoProperty *property_info = - _nm_sett_info_property_info_get_sorted(sett_info, j); - - write_setting_value(&info, setting, property_info); - if (info.error) - goto out_with_info_error; - } - - setting_alias = nm_keyfile_plugin_get_alias_for_setting_name(setting_name); - if ((setting_alias && g_key_file_has_group(info.keyfile, setting_alias)) - || g_key_file_has_group(info.keyfile, setting_name)) { - /* we have a section for the setting. Nothing to do. */ - } else { - /* ensure the group is present. There is no API for that, so add and remove - * a dummy key. */ - g_key_file_set_value(info.keyfile, setting_alias ?: setting_name, ".X", "1"); - g_key_file_remove_key(info.keyfile, setting_alias ?: setting_name, ".X", NULL); - } - - if (NM_IS_SETTING_WIREGUARD(setting)) { - _write_setting_wireguard(setting, &info); - if (info.error) - goto out_with_info_error; - } - - nm_assert(!info.error); - } - - nm_assert(!info.error); - - return g_steal_pointer(&keyfile); - -out_with_info_error: - g_propagate_error(error, info.error); - return NULL; -} - -/*****************************************************************************/ - -static const char temp_letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - -/* - * Check '.[a-zA-Z0-9]{6}' file suffix used for temporary files by g_file_set_contents() (mkstemp()). - */ -static gboolean -check_mkstemp_suffix(const char *path) -{ - const char *ptr; - - nm_assert(path); - - /* Matches *.[a-zA-Z0-9]{6} suffix of mkstemp()'s temporary files */ - ptr = strrchr(path, '.'); - if (ptr && strspn(&ptr[1], temp_letters) == 6 && ptr[7] == '\0') - return TRUE; - return FALSE; -} - -#define SWP_TAG ".swp" -#define SWPX_TAG ".swpx" -#define PEM_TAG ".pem" -#define DER_TAG ".der" - -gboolean -nm_keyfile_utils_ignore_filename(const char *filename, gboolean require_extension) -{ - const char *base; - gsize l; - - /* ignore_filename() must mirror nm_keyfile_utils_create_filename() */ - - g_return_val_if_fail(filename, TRUE); - - base = strrchr(filename, '/'); - if (base) - base++; - else - base = filename; - - if (!base[0]) { - /* this check above with strrchr() also rejects "/some/path/with/trailing/slash/", - * but that is fine, because such a path would name a directory, and we are not - * interested in directories. */ - return TRUE; - } - - if (base[0] == '.') { - /* don't allow hidden files */ - return TRUE; - } - - if (require_extension) { - if (!NM_STR_HAS_SUFFIX_WITH_MORE(base, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)) - return TRUE; - return FALSE; - } - - l = strlen(base); - - /* Ignore backup files */ - if (base[l - 1] == '~') - return TRUE; - - /* Ignore temporary files - * - * This check is also important to ignore .nmload files (see - * %NM_KEYFILE_PATH_SUFFIX_NMMETA). */ - if (check_mkstemp_suffix(base)) - return TRUE; - - /* Ignore 802.1x certificates and keys */ - if (NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(base, PEM_TAG) - || NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(base, DER_TAG)) - return TRUE; - - return FALSE; -} - -char * -nm_keyfile_utils_create_filename(const char *name, gboolean with_extension) -{ - /* keyfile used to escape with '*', do not change that behavior. - * - * But for newly added escapings, use '_' instead. - * Also, @with_extension is new-style. */ - const char ESCAPE_CHAR = with_extension ? '_' : '*'; - const char ESCAPE_CHAR2 = '_'; - NMStrBuf str; - char * p; - gsize len; - gsize i; - - g_return_val_if_fail(name && name[0], NULL); - - nm_str_buf_init(&str, 0, FALSE); - - len = strlen(name); - - p = nm_str_buf_append_len0(&str, name, len); - - /* Convert '/' to ESCAPE_CHAR */ - for (i = 0; i < len; i++) { - if (p[i] == '/') - p[i] = ESCAPE_CHAR; - } - - /* nm_keyfile_utils_create_filename() must avoid anything that ignore_filename() would reject. - * We can escape here more aggressively then what we would read back. */ - if (p[0] == '.') - p[0] = ESCAPE_CHAR2; - if (p[str.len - 1] == '~') - p[str.len - 1] = ESCAPE_CHAR2; - - if (check_mkstemp_suffix(p) || NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(p, PEM_TAG) - || NM_STR_HAS_SUFFIX_ASCII_CASE_WITH_MORE(p, DER_TAG)) - nm_str_buf_append_c(&str, ESCAPE_CHAR2); - - if (with_extension) - nm_str_buf_append(&str, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION); - - p = nm_str_buf_finalize(&str, NULL); - - /* nm_keyfile_utils_create_filename() must mirror ignore_filename() */ - nm_assert(!strchr(p, '/')); - nm_assert(!nm_keyfile_utils_ignore_filename(p, with_extension)); - - return p; -} - -/*****************************************************************************/ - -/** - * nm_keyfile_handler_data_fail_with_error: - * @handler_data: the #NMKeyfileHandlerData - * @src: (transfer full): error to move into the return location - * - * Set the error for the handler. This lets the operation fail - * with the provided error. You may only set the error once. - * - * @src must be non-%NULL. - * - * Note that @src is no longer valid after this call. If you want - * to keep using the same GError*, you need to set it to %NULL - * after calling this function on it. - */ -void -nm_keyfile_handler_data_fail_with_error(NMKeyfileHandlerData *handler_data, GError *src) -{ - g_return_if_fail(handler_data); - g_return_if_fail(handler_data->p_error && !*handler_data->p_error); - g_return_if_fail(src); - - *handler_data->p_error = src; -} - -/** - * nm_keyfile_handler_data_get_context: - * @handler_data: the #NMKeyfileHandlerData for any event. - * @out_kf_group_name: (out) (allow-none) (transfer none): if the event is in the - * context of a keyfile group, the group name. - * @out_kf_key_name: (out) (allow-none) (transfer none): if the event is in the - * context of a keyfile value, the key name. - * @out_cur_setting: (out) (allow-none) (transfer none): if the event happens while - * handling a particular #NMSetting instance. - * @out_cur_property_name: (out) (allow-none) (transfer none): the property name if applicable. - * - * Get context information of the current event. This function can be called - * on all events, but the context information may be unset. - */ -void -nm_keyfile_handler_data_get_context(const NMKeyfileHandlerData *handler_data, - const char ** out_kf_group_name, - const char ** out_kf_key_name, - NMSetting ** out_cur_setting, - const char ** out_cur_property_name) -{ - g_return_if_fail(handler_data); - - NM_SET_OUT(out_kf_group_name, handler_data->kf_group_name); - NM_SET_OUT(out_kf_key_name, handler_data->kf_key); - NM_SET_OUT(out_cur_setting, handler_data->cur_setting); - NM_SET_OUT(out_cur_property_name, handler_data->cur_property); -} - -const char * -_nm_keyfile_handler_data_warn_get_message(const NMKeyfileHandlerData *handler_data) -{ - nm_assert(handler_data); - nm_assert(handler_data->type == NM_KEYFILE_HANDLER_TYPE_WARN); - - if (!handler_data->warn.message) { - /* we cast the const away. @handler_data is const w.r.t. visible mutations - * from POV of the user. Internally, we construct the message in - * a lazy manner. It's like a mutable field in C++. */ - NM_PRAGMA_WARNING_DISABLE("-Wformat-nonliteral") - ((NMKeyfileHandlerData *) handler_data)->warn.message = - g_strdup_vprintf(handler_data->warn.fmt, - ((NMKeyfileHandlerData *) handler_data)->warn.ap); - NM_PRAGMA_WARNING_REENABLE - } - return handler_data->warn.message; -} - -/** - * nm_keyfile_handler_data_warn_get: - * @handler_data: the #NMKeyfileHandlerData for a %NM_KEYFILE_HANDLER_TYPE_WARN - * event. - * @out_message: (out) (allow-none) (transfer none): the warning message. - * @out_severity: (out) (allow-none): the #NMKeyfileWarnSeverity warning severity. - */ -void -nm_keyfile_handler_data_warn_get(const NMKeyfileHandlerData *handler_data, - const char ** out_message, - NMKeyfileWarnSeverity * out_severity) -{ - g_return_if_fail(handler_data); - g_return_if_fail(handler_data->type == NM_KEYFILE_HANDLER_TYPE_WARN); - - NM_SET_OUT(out_message, _nm_keyfile_handler_data_warn_get_message(handler_data)); - NM_SET_OUT(out_severity, handler_data->warn.severity); -} diff --git a/libnm-core/nm-libnm-core-aux/nm-dispatcher-api.h b/libnm-core/nm-libnm-core-aux/nm-dispatcher-api.h index 80546a83..7776c84f 100644 --- a/libnm-core/nm-libnm-core-aux/nm-dispatcher-api.h +++ b/libnm-core/nm-libnm-core-aux/nm-dispatcher-api.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2008 - 2012 Red Hat, Inc. */ diff --git a/libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c b/libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c index bcc8ef4a..888dbac4 100644 --- a/libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c +++ b/libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019 Red Hat, Inc. */ -#include "nm-default.h" +#include "nm-glib-aux/nm-default-glib-i18n-lib.h" #include "nm-libnm-core-aux.h" diff --git a/libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.h b/libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.h index 9253edfd..905f2433 100644 --- a/libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.h +++ b/libnm-core/nm-libnm-core-aux/nm-libnm-core-aux.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019 Red Hat, Inc. */ diff --git a/libnm-core/nm-libnm-core-intern/nm-auth-subject.c b/libnm-core/nm-libnm-core-intern/nm-auth-subject.c index 49cd4f12..1866662c 100644 --- a/libnm-core/nm-libnm-core-intern/nm-auth-subject.c +++ b/libnm-core/nm-libnm-core-intern/nm-auth-subject.c @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2013 - 2014 Red Hat, Inc. */ @@ -11,7 +11,7 @@ * makes requests, like process identifier and user UID. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-auth-subject.h" @@ -179,10 +179,10 @@ nm_auth_subject_get_unix_session_id(NMAuthSubject *subject) NMAuthSubject * nm_auth_subject_new_internal(void) { - return NM_AUTH_SUBJECT(g_object_new(NM_TYPE_AUTH_SUBJECT, - NM_AUTH_SUBJECT_SUBJECT_TYPE, - (int) NM_AUTH_SUBJECT_TYPE_INTERNAL, - NULL)); + return g_object_new(NM_TYPE_AUTH_SUBJECT, + NM_AUTH_SUBJECT_SUBJECT_TYPE, + (int) NM_AUTH_SUBJECT_TYPE_INTERNAL, + NULL); } /** @@ -195,12 +195,12 @@ nm_auth_subject_new_internal(void) NMAuthSubject * nm_auth_subject_new_unix_session(const char *session_id) { - return NM_AUTH_SUBJECT(g_object_new(NM_TYPE_AUTH_SUBJECT, - NM_AUTH_SUBJECT_SUBJECT_TYPE, - (int) NM_AUTH_SUBJECT_TYPE_UNIX_SESSION, - NM_AUTH_SUBJECT_UNIX_SESSION_ID, - session_id, - NULL)); + return g_object_new(NM_TYPE_AUTH_SUBJECT, + NM_AUTH_SUBJECT_SUBJECT_TYPE, + (int) NM_AUTH_SUBJECT_TYPE_UNIX_SESSION, + NM_AUTH_SUBJECT_UNIX_SESSION_ID, + session_id, + NULL); } /** @@ -213,16 +213,16 @@ nm_auth_subject_new_unix_session(const char *session_id) NMAuthSubject * nm_auth_subject_new_unix_process(const char *dbus_sender, gulong pid, gulong uid) { - return NM_AUTH_SUBJECT(g_object_new(NM_TYPE_AUTH_SUBJECT, - NM_AUTH_SUBJECT_SUBJECT_TYPE, - (int) NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, - NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, - dbus_sender, - NM_AUTH_SUBJECT_UNIX_PROCESS_PID, - pid, - NM_AUTH_SUBJECT_UNIX_PROCESS_UID, - uid, - NULL)); + return g_object_new(NM_TYPE_AUTH_SUBJECT, + NM_AUTH_SUBJECT_SUBJECT_TYPE, + (int) NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, + NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, + dbus_sender, + NM_AUTH_SUBJECT_UNIX_PROCESS_PID, + pid, + NM_AUTH_SUBJECT_UNIX_PROCESS_UID, + uid, + NULL); } /** diff --git a/libnm-core/nm-libnm-core-intern/nm-auth-subject.h b/libnm-core/nm-libnm-core-intern/nm-auth-subject.h index 13d380d2..2c9c4f71 100644 --- a/libnm-core/nm-libnm-core-intern/nm-auth-subject.h +++ b/libnm-core/nm-libnm-core-intern/nm-auth-subject.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2013 Red Hat, Inc. */ diff --git a/libnm-core/nm-libnm-core-intern/nm-common-macros.h b/libnm-core/nm-libnm-core-intern/nm-common-macros.h index 9de3a8fc..c452b7d3 100644 --- a/libnm-core/nm-libnm-core-intern/nm-common-macros.h +++ b/libnm-core/nm-libnm-core-intern/nm-common-macros.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2016 Red Hat, Inc. */ diff --git a/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.c b/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.c deleted file mode 100644 index f3d34fea..00000000 --- a/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.c +++ /dev/null @@ -1,276 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-ethtool-utils.h" - -#include "nm-setting-ethtool.h" - -/*****************************************************************************/ - -#define ETHT_DATA(xname) \ - [NM_ETHTOOL_ID_##xname] = (&((const NMEthtoolData){ \ - .optname = NM_ETHTOOL_OPTNAME_##xname, \ - .id = NM_ETHTOOL_ID_##xname, \ - })) - -const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1] = { - /* indexed by NMEthtoolID */ - ETHT_DATA(COALESCE_ADAPTIVE_RX), - ETHT_DATA(COALESCE_ADAPTIVE_TX), - ETHT_DATA(COALESCE_PKT_RATE_HIGH), - ETHT_DATA(COALESCE_PKT_RATE_LOW), - ETHT_DATA(COALESCE_RX_FRAMES), - ETHT_DATA(COALESCE_RX_FRAMES_HIGH), - ETHT_DATA(COALESCE_RX_FRAMES_IRQ), - ETHT_DATA(COALESCE_RX_FRAMES_LOW), - ETHT_DATA(COALESCE_RX_USECS), - ETHT_DATA(COALESCE_RX_USECS_HIGH), - ETHT_DATA(COALESCE_RX_USECS_IRQ), - ETHT_DATA(COALESCE_RX_USECS_LOW), - ETHT_DATA(COALESCE_SAMPLE_INTERVAL), - ETHT_DATA(COALESCE_STATS_BLOCK_USECS), - ETHT_DATA(COALESCE_TX_FRAMES), - ETHT_DATA(COALESCE_TX_FRAMES_HIGH), - ETHT_DATA(COALESCE_TX_FRAMES_IRQ), - ETHT_DATA(COALESCE_TX_FRAMES_LOW), - ETHT_DATA(COALESCE_TX_USECS), - ETHT_DATA(COALESCE_TX_USECS_HIGH), - ETHT_DATA(COALESCE_TX_USECS_IRQ), - ETHT_DATA(COALESCE_TX_USECS_LOW), - ETHT_DATA(FEATURE_ESP_HW_OFFLOAD), - ETHT_DATA(FEATURE_ESP_TX_CSUM_HW_OFFLOAD), - ETHT_DATA(FEATURE_FCOE_MTU), - ETHT_DATA(FEATURE_GRO), - ETHT_DATA(FEATURE_GSO), - ETHT_DATA(FEATURE_HIGHDMA), - ETHT_DATA(FEATURE_HW_TC_OFFLOAD), - ETHT_DATA(FEATURE_L2_FWD_OFFLOAD), - ETHT_DATA(FEATURE_LOOPBACK), - ETHT_DATA(FEATURE_LRO), - ETHT_DATA(FEATURE_NTUPLE), - ETHT_DATA(FEATURE_RX), - ETHT_DATA(FEATURE_RXHASH), - ETHT_DATA(FEATURE_RXVLAN), - ETHT_DATA(FEATURE_RX_ALL), - ETHT_DATA(FEATURE_RX_FCS), - ETHT_DATA(FEATURE_RX_GRO_HW), - ETHT_DATA(FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD), - ETHT_DATA(FEATURE_RX_VLAN_FILTER), - ETHT_DATA(FEATURE_RX_VLAN_STAG_FILTER), - ETHT_DATA(FEATURE_RX_VLAN_STAG_HW_PARSE), - ETHT_DATA(FEATURE_SG), - ETHT_DATA(FEATURE_TLS_HW_RECORD), - ETHT_DATA(FEATURE_TLS_HW_TX_OFFLOAD), - ETHT_DATA(FEATURE_TSO), - ETHT_DATA(FEATURE_TX), - ETHT_DATA(FEATURE_TXVLAN), - ETHT_DATA(FEATURE_TX_CHECKSUM_FCOE_CRC), - ETHT_DATA(FEATURE_TX_CHECKSUM_IPV4), - ETHT_DATA(FEATURE_TX_CHECKSUM_IPV6), - ETHT_DATA(FEATURE_TX_CHECKSUM_IP_GENERIC), - ETHT_DATA(FEATURE_TX_CHECKSUM_SCTP), - ETHT_DATA(FEATURE_TX_ESP_SEGMENTATION), - ETHT_DATA(FEATURE_TX_FCOE_SEGMENTATION), - ETHT_DATA(FEATURE_TX_GRE_CSUM_SEGMENTATION), - ETHT_DATA(FEATURE_TX_GRE_SEGMENTATION), - ETHT_DATA(FEATURE_TX_GSO_PARTIAL), - ETHT_DATA(FEATURE_TX_GSO_ROBUST), - ETHT_DATA(FEATURE_TX_IPXIP4_SEGMENTATION), - ETHT_DATA(FEATURE_TX_IPXIP6_SEGMENTATION), - ETHT_DATA(FEATURE_TX_NOCACHE_COPY), - ETHT_DATA(FEATURE_TX_SCATTER_GATHER), - ETHT_DATA(FEATURE_TX_SCATTER_GATHER_FRAGLIST), - ETHT_DATA(FEATURE_TX_SCTP_SEGMENTATION), - ETHT_DATA(FEATURE_TX_TCP6_SEGMENTATION), - ETHT_DATA(FEATURE_TX_TCP_ECN_SEGMENTATION), - ETHT_DATA(FEATURE_TX_TCP_MANGLEID_SEGMENTATION), - ETHT_DATA(FEATURE_TX_TCP_SEGMENTATION), - ETHT_DATA(FEATURE_TX_UDP_SEGMENTATION), - ETHT_DATA(FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION), - ETHT_DATA(FEATURE_TX_UDP_TNL_SEGMENTATION), - ETHT_DATA(FEATURE_TX_VLAN_STAG_HW_INSERT), - ETHT_DATA(RING_RX), - ETHT_DATA(RING_RX_JUMBO), - ETHT_DATA(RING_RX_MINI), - ETHT_DATA(RING_TX), - [_NM_ETHTOOL_ID_NUM] = NULL, -}; - -static const guint8 _by_name[_NM_ETHTOOL_ID_NUM] = { - /* sorted by optname. */ - NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX, - NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX, - NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH, - NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW, - NM_ETHTOOL_ID_COALESCE_RX_FRAMES, - NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH, - NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ, - NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW, - NM_ETHTOOL_ID_COALESCE_RX_USECS, - NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH, - NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ, - NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW, - NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL, - NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS, - NM_ETHTOOL_ID_COALESCE_TX_FRAMES, - NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH, - NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ, - NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW, - NM_ETHTOOL_ID_COALESCE_TX_USECS, - NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH, - NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ, - NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW, - NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_FCOE_MTU, - NM_ETHTOOL_ID_FEATURE_GRO, - NM_ETHTOOL_ID_FEATURE_GSO, - NM_ETHTOOL_ID_FEATURE_HIGHDMA, - NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_LOOPBACK, - NM_ETHTOOL_ID_FEATURE_LRO, - NM_ETHTOOL_ID_FEATURE_NTUPLE, - NM_ETHTOOL_ID_FEATURE_RX, - NM_ETHTOOL_ID_FEATURE_RX_ALL, - NM_ETHTOOL_ID_FEATURE_RX_FCS, - NM_ETHTOOL_ID_FEATURE_RX_GRO_HW, - NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER, - NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER, - NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE, - NM_ETHTOOL_ID_FEATURE_RXHASH, - NM_ETHTOOL_ID_FEATURE_RXVLAN, - NM_ETHTOOL_ID_FEATURE_SG, - NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD, - NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_TSO, - NM_ETHTOOL_ID_FEATURE_TX, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP, - NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL, - NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST, - NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY, - NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER, - NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST, - NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, - NM_ETHTOOL_ID_FEATURE_TXVLAN, - NM_ETHTOOL_ID_RING_RX, - NM_ETHTOOL_ID_RING_RX_JUMBO, - NM_ETHTOOL_ID_RING_RX_MINI, - NM_ETHTOOL_ID_RING_TX, -}; - -/*****************************************************************************/ - -static void -_ASSERT_data(void) -{ - int i; - - if (!NM_MORE_ASSERT_ONCE(10)) - return; - - G_STATIC_ASSERT_EXPR(_NM_ETHTOOL_ID_FIRST == 0); - G_STATIC_ASSERT_EXPR(_NM_ETHTOOL_ID_LAST == _NM_ETHTOOL_ID_NUM - 1); - G_STATIC_ASSERT_EXPR(_NM_ETHTOOL_ID_NUM > 0); - - nm_assert(NM_PTRARRAY_LEN(nm_ethtool_data) == _NM_ETHTOOL_ID_NUM); - nm_assert(G_N_ELEMENTS(_by_name) == _NM_ETHTOOL_ID_NUM); - nm_assert(G_N_ELEMENTS(nm_ethtool_data) == _NM_ETHTOOL_ID_NUM + 1); - - for (i = 0; i < _NM_ETHTOOL_ID_NUM; i++) { - const NMEthtoolData *d = nm_ethtool_data[i]; - - nm_assert(d); - nm_assert(d->id == (NMEthtoolID) i); - nm_assert(d->optname && d->optname[0]); - } - - for (i = 0; i < _NM_ETHTOOL_ID_NUM; i++) { - NMEthtoolID id = _by_name[i]; - const NMEthtoolData *d; - - nm_assert(id >= 0); - nm_assert(id < _NM_ETHTOOL_ID_NUM); - - d = nm_ethtool_data[id]; - if (i > 0) { - /* since we assert that all optnames are sorted strictly monotonically increasing, - * it also follows that there are no duplicates in the _by_name. - * It also follows, that all names in nm_ethtool_data are unique. */ - if (strcmp(nm_ethtool_data[_by_name[i - 1]]->optname, d->optname) >= 0) { - g_error("nm_ethtool_data is not sorted asciibetically: %u/%s should be after %u/%s", - i - 1, - nm_ethtool_data[_by_name[i - 1]]->optname, - i, - d->optname); - } - } - } -} - -static int -_by_name_cmp(gconstpointer a, gconstpointer b, gpointer user_data) -{ - const guint8 *p_id = a; - const char * optname = b; - - nm_assert(p_id && p_id >= _by_name && p_id <= &_by_name[_NM_ETHTOOL_ID_NUM]); - nm_assert(*p_id < _NM_ETHTOOL_ID_NUM); - - return strcmp(nm_ethtool_data[*p_id]->optname, optname); -} - -const NMEthtoolData * -nm_ethtool_data_get_by_optname(const char *optname) -{ - gssize idx; - - if (!optname) - return NULL; - - _ASSERT_data(); - - idx = nm_utils_array_find_binary_search((gconstpointer *) _by_name, - sizeof(_by_name[0]), - _NM_ETHTOOL_ID_NUM, - optname, - _by_name_cmp, - NULL); - return (idx < 0) ? NULL : nm_ethtool_data[_by_name[idx]]; -} - -NMEthtoolType -nm_ethtool_id_to_type(NMEthtoolID id) -{ - if (nm_ethtool_id_is_coalesce(id)) - return NM_ETHTOOL_TYPE_COALESCE; - if (nm_ethtool_id_is_feature(id)) - return NM_ETHTOOL_TYPE_FEATURE; - if (nm_ethtool_id_is_ring(id)) - return NM_ETHTOOL_TYPE_RING; - - return NM_ETHTOOL_TYPE_UNKNOWN; -} diff --git a/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.h b/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.h deleted file mode 100644 index a11177e8..00000000 --- a/libnm-core/nm-libnm-core-intern/nm-ethtool-utils.h +++ /dev/null @@ -1,164 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ -/* - * Copyright (C) 2018 Red Hat, Inc. - */ - -#ifndef __NM_ETHTOOL_UTILS_H__ -#define __NM_ETHTOOL_UTILS_H__ - -/*****************************************************************************/ - -typedef enum { - NM_ETHTOOL_ID_UNKNOWN = -1, - - _NM_ETHTOOL_ID_FIRST = 0, - - _NM_ETHTOOL_ID_COALESCE_FIRST = _NM_ETHTOOL_ID_FIRST, - NM_ETHTOOL_ID_COALESCE_ADAPTIVE_RX = _NM_ETHTOOL_ID_COALESCE_FIRST, - NM_ETHTOOL_ID_COALESCE_ADAPTIVE_TX, - NM_ETHTOOL_ID_COALESCE_PKT_RATE_HIGH, - NM_ETHTOOL_ID_COALESCE_PKT_RATE_LOW, - NM_ETHTOOL_ID_COALESCE_RX_FRAMES, - NM_ETHTOOL_ID_COALESCE_RX_FRAMES_HIGH, - NM_ETHTOOL_ID_COALESCE_RX_FRAMES_IRQ, - NM_ETHTOOL_ID_COALESCE_RX_FRAMES_LOW, - NM_ETHTOOL_ID_COALESCE_RX_USECS, - NM_ETHTOOL_ID_COALESCE_RX_USECS_HIGH, - NM_ETHTOOL_ID_COALESCE_RX_USECS_IRQ, - NM_ETHTOOL_ID_COALESCE_RX_USECS_LOW, - NM_ETHTOOL_ID_COALESCE_SAMPLE_INTERVAL, - NM_ETHTOOL_ID_COALESCE_STATS_BLOCK_USECS, - NM_ETHTOOL_ID_COALESCE_TX_FRAMES, - NM_ETHTOOL_ID_COALESCE_TX_FRAMES_HIGH, - NM_ETHTOOL_ID_COALESCE_TX_FRAMES_IRQ, - NM_ETHTOOL_ID_COALESCE_TX_FRAMES_LOW, - NM_ETHTOOL_ID_COALESCE_TX_USECS, - NM_ETHTOOL_ID_COALESCE_TX_USECS_HIGH, - NM_ETHTOOL_ID_COALESCE_TX_USECS_IRQ, - NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW, - _NM_ETHTOOL_ID_COALESCE_LAST = NM_ETHTOOL_ID_COALESCE_TX_USECS_LOW, - - _NM_ETHTOOL_ID_FEATURE_FIRST = _NM_ETHTOOL_ID_COALESCE_LAST + 1, - NM_ETHTOOL_ID_FEATURE_ESP_HW_OFFLOAD = _NM_ETHTOOL_ID_FEATURE_FIRST, - NM_ETHTOOL_ID_FEATURE_ESP_TX_CSUM_HW_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_FCOE_MTU, - NM_ETHTOOL_ID_FEATURE_GRO, - NM_ETHTOOL_ID_FEATURE_GSO, - NM_ETHTOOL_ID_FEATURE_HIGHDMA, - NM_ETHTOOL_ID_FEATURE_HW_TC_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_L2_FWD_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_LOOPBACK, - NM_ETHTOOL_ID_FEATURE_LRO, - NM_ETHTOOL_ID_FEATURE_NTUPLE, - NM_ETHTOOL_ID_FEATURE_RX, - NM_ETHTOOL_ID_FEATURE_RXHASH, - NM_ETHTOOL_ID_FEATURE_RXVLAN, - NM_ETHTOOL_ID_FEATURE_RX_ALL, - NM_ETHTOOL_ID_FEATURE_RX_FCS, - NM_ETHTOOL_ID_FEATURE_RX_GRO_HW, - NM_ETHTOOL_ID_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_RX_VLAN_FILTER, - NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_FILTER, - NM_ETHTOOL_ID_FEATURE_RX_VLAN_STAG_HW_PARSE, - NM_ETHTOOL_ID_FEATURE_SG, - NM_ETHTOOL_ID_FEATURE_TLS_HW_RECORD, - NM_ETHTOOL_ID_FEATURE_TLS_HW_TX_OFFLOAD, - NM_ETHTOOL_ID_FEATURE_TSO, - NM_ETHTOOL_ID_FEATURE_TX, - NM_ETHTOOL_ID_FEATURE_TXVLAN, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_FCOE_CRC, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV4, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IPV6, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_IP_GENERIC, - NM_ETHTOOL_ID_FEATURE_TX_CHECKSUM_SCTP, - NM_ETHTOOL_ID_FEATURE_TX_ESP_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_FCOE_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_GRE_CSUM_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_GRE_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_GSO_PARTIAL, - NM_ETHTOOL_ID_FEATURE_TX_GSO_ROBUST, - NM_ETHTOOL_ID_FEATURE_TX_IPXIP4_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_IPXIP6_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_NOCACHE_COPY, - NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER, - NM_ETHTOOL_ID_FEATURE_TX_SCATTER_GATHER_FRAGLIST, - NM_ETHTOOL_ID_FEATURE_TX_SCTP_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_TCP6_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_TCP_ECN_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_TCP_MANGLEID_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_TCP_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_UDP_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_UDP_TNL_SEGMENTATION, - NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, - _NM_ETHTOOL_ID_FEATURE_LAST = NM_ETHTOOL_ID_FEATURE_TX_VLAN_STAG_HW_INSERT, - - _NM_ETHTOOL_ID_RING_FIRST = _NM_ETHTOOL_ID_FEATURE_LAST + 1, - NM_ETHTOOL_ID_RING_RX = _NM_ETHTOOL_ID_RING_FIRST, - NM_ETHTOOL_ID_RING_RX_JUMBO, - NM_ETHTOOL_ID_RING_RX_MINI, - NM_ETHTOOL_ID_RING_TX, - _NM_ETHTOOL_ID_RING_LAST = NM_ETHTOOL_ID_RING_TX, - - _NM_ETHTOOL_ID_LAST = _NM_ETHTOOL_ID_RING_LAST, - - _NM_ETHTOOL_ID_COALESCE_NUM = - (_NM_ETHTOOL_ID_COALESCE_LAST - _NM_ETHTOOL_ID_COALESCE_FIRST + 1), - _NM_ETHTOOL_ID_FEATURE_NUM = (_NM_ETHTOOL_ID_FEATURE_LAST - _NM_ETHTOOL_ID_FEATURE_FIRST + 1), - _NM_ETHTOOL_ID_RING_NUM = (_NM_ETHTOOL_ID_RING_LAST - _NM_ETHTOOL_ID_RING_FIRST + 1), - _NM_ETHTOOL_ID_NUM = (_NM_ETHTOOL_ID_LAST - _NM_ETHTOOL_ID_FIRST + 1), -} NMEthtoolID; - -#define _NM_ETHTOOL_ID_FEATURE_AS_IDX(ethtool_id) ((ethtool_id) -_NM_ETHTOOL_ID_FEATURE_FIRST) -#define _NM_ETHTOOL_ID_COALESCE_AS_IDX(ethtool_id) ((ethtool_id) -_NM_ETHTOOL_ID_COALESCE_FIRST) - -typedef enum { - NM_ETHTOOL_TYPE_UNKNOWN, - NM_ETHTOOL_TYPE_COALESCE, - NM_ETHTOOL_TYPE_FEATURE, - NM_ETHTOOL_TYPE_RING, -} NMEthtoolType; - -typedef struct { - const char *optname; - NMEthtoolID id; -} NMEthtoolData; - -extern const NMEthtoolData *const nm_ethtool_data[_NM_ETHTOOL_ID_NUM + 1]; - -const NMEthtoolData *nm_ethtool_data_get_by_optname(const char *optname); - -NMEthtoolType nm_ethtool_id_to_type(NMEthtoolID id); - -/****************************************************************************/ - -static inline NMEthtoolID -nm_ethtool_id_get_by_name(const char *optname) -{ - const NMEthtoolData *d; - - d = nm_ethtool_data_get_by_optname(optname); - return d ? d->id : NM_ETHTOOL_ID_UNKNOWN; -} - -static inline gboolean -nm_ethtool_id_is_feature(NMEthtoolID id) -{ - return id >= _NM_ETHTOOL_ID_FEATURE_FIRST && id <= _NM_ETHTOOL_ID_FEATURE_LAST; -} - -static inline gboolean -nm_ethtool_id_is_coalesce(NMEthtoolID id) -{ - return id >= _NM_ETHTOOL_ID_COALESCE_FIRST && id <= _NM_ETHTOOL_ID_COALESCE_LAST; -} - -static inline gboolean -nm_ethtool_id_is_ring(NMEthtoolID id) -{ - return id >= _NM_ETHTOOL_ID_RING_FIRST && id <= _NM_ETHTOOL_ID_RING_LAST; -} - -/****************************************************************************/ - -#endif /* __NM_ETHTOOL_UTILS_H__ */ diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c index 65cd8ba5..1ab0fcf2 100644 --- a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c +++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.c @@ -1,6 +1,6 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-libnm-core-utils.h" @@ -36,18 +36,19 @@ _nm_setting_bond_remove_options_arp_interval(NMSettingBond *s_bond) nm_setting_bond_remove_option(s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET); } +/*****************************************************************************/ + NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( _nm_setting_bond_mode_from_string, NMBondMode, - { g_return_val_if_fail(name, NM_BOND_MODE_UNKNOWN); }, + { + G_STATIC_ASSERT_EXPR(_NM_BOND_MODE_NUM <= 9); + + if (name && name[0] < '0' + _NM_BOND_MODE_NUM && name[0] >= '0' && name[1] == '\0') { + return name[0] - '0'; + } + }, { return NM_BOND_MODE_UNKNOWN; }, - {"0", NM_BOND_MODE_ROUNDROBIN}, - {"1", NM_BOND_MODE_ACTIVEBACKUP}, - {"2", NM_BOND_MODE_XOR}, - {"3", NM_BOND_MODE_BROADCAST}, - {"4", NM_BOND_MODE_8023AD}, - {"5", NM_BOND_MODE_TLB}, - {"6", NM_BOND_MODE_ALB}, {"802.3ad", NM_BOND_MODE_8023AD}, {"active-backup", NM_BOND_MODE_ACTIVEBACKUP}, {"balance-alb", NM_BOND_MODE_ALB}, @@ -56,6 +57,47 @@ NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( {"balance-xor", NM_BOND_MODE_XOR}, {"broadcast", NM_BOND_MODE_BROADCAST}, ); +const char * +_nm_setting_bond_mode_to_string(int mode) +{ + static const char *const modes[] = { + [NM_BOND_MODE_8023AD] = "802.3ad", + [NM_BOND_MODE_ACTIVEBACKUP] = "active-backup", + [NM_BOND_MODE_ALB] = "balance-alb", + [NM_BOND_MODE_BROADCAST] = "broadcast", + [NM_BOND_MODE_ROUNDROBIN] = "balance-rr", + [NM_BOND_MODE_TLB] = "balance-tlb", + [NM_BOND_MODE_XOR] = "balance-xor", + }; + + G_STATIC_ASSERT(G_N_ELEMENTS(modes) == _NM_BOND_MODE_NUM); + + if (NM_MORE_ASSERT_ONCE(5)) { + char sbuf[100]; + int i; + NMBondMode m; + + for (i = 0; i < (int) G_N_ELEMENTS(modes); i++) { + nm_assert(modes[i]); + nm_assert(i == _nm_setting_bond_mode_from_string(modes[i])); + nm_assert(i == _nm_setting_bond_mode_from_string(nm_sprintf_buf(sbuf, "%d", i))); + } + nm_assert(NM_BOND_MODE_UNKNOWN == _nm_setting_bond_mode_from_string(NULL)); + nm_assert(NM_BOND_MODE_UNKNOWN == _nm_setting_bond_mode_from_string("")); + for (i = -2; i < ((int) G_N_ELEMENTS(modes)) + 20; i++) { + if (i < 0 || i >= G_N_ELEMENTS(modes)) + m = NM_BOND_MODE_UNKNOWN; + else + m = i; + nm_assert(m == _nm_setting_bond_mode_from_string(nm_sprintf_buf(sbuf, "%d", i))); + } + } + + if (mode >= 0 && mode < (int) G_N_ELEMENTS(modes)) + return modes[mode]; + return NULL; +} + /*****************************************************************************/ gboolean diff --git a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h index 5d672fed..946c7a2c 100644 --- a/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h +++ b/libnm-core/nm-libnm-core-intern/nm-libnm-core-utils.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef __NM_LIBNM_SHARED_UTILS_H__ #define __NM_LIBNM_SHARED_UTILS_H__ @@ -65,11 +65,16 @@ typedef enum { NM_BOND_MODE_8023AD = 4, NM_BOND_MODE_TLB = 5, NM_BOND_MODE_ALB = 6, + _NM_BOND_MODE_NUM, } NMBondMode; NMBondMode _nm_setting_bond_mode_from_string(const char *str); +const char *_nm_setting_bond_mode_to_string(int mode); + +gboolean _nm_setting_bond_validate_option(const char *name, const char *value, GError **error); + /*****************************************************************************/ static inline guint32 @@ -93,6 +98,11 @@ gboolean nm_utils_vlan_priority_map_parse_str(NMVlanPriorityMap map_type, /*****************************************************************************/ +#define NM_OVS_EXTERNAL_ID_NM_PREFIX "NM." +#define NM_OVS_EXTERNAL_ID_NM_CONNECTION_UUID "NM.connection.uuid" + +/*****************************************************************************/ + static inline int nm_setting_ip_config_get_addr_family(NMSettingIPConfig *s_ip) { diff --git a/libnm-core/nm-meta-setting-base-impl.c b/libnm-core/nm-meta-setting-base-impl.c new file mode 100644 index 00000000..523c0d5d --- /dev/null +++ b/libnm-core/nm-meta-setting-base-impl.c @@ -0,0 +1,641 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2017 - 2018 Red Hat, Inc. + */ + +#include "nm-glib-aux/nm-default-glib-i18n-lib.h" + +#include "nm-meta-setting-base.h" + +#include "nm-setting-6lowpan.h" +#include "nm-setting-8021x.h" +#include "nm-setting-adsl.h" +#include "nm-setting-bluetooth.h" +#include "nm-setting-bond.h" +#include "nm-setting-bridge-port.h" +#include "nm-setting-bridge.h" +#include "nm-setting-cdma.h" +#include "nm-setting-connection.h" +#include "nm-setting-dcb.h" +#include "nm-setting-dummy.h" +#include "nm-setting-ethtool.h" +#include "nm-setting-generic.h" +#include "nm-setting-gsm.h" +#include "nm-setting-hostname.h" +#include "nm-setting-infiniband.h" +#include "nm-setting-ip-config.h" +#include "nm-setting-ip-tunnel.h" +#include "nm-setting-ip4-config.h" +#include "nm-setting-ip6-config.h" +#include "nm-setting-macsec.h" +#include "nm-setting-macvlan.h" +#include "nm-setting-match.h" +#include "nm-setting-olpc-mesh.h" +#include "nm-setting-ovs-bridge.h" +#include "nm-setting-ovs-interface.h" +#include "nm-setting-ovs-dpdk.h" +#include "nm-setting-ovs-external-ids.h" +#include "nm-setting-ovs-patch.h" +#include "nm-setting-ovs-port.h" +#include "nm-setting-ppp.h" +#include "nm-setting-pppoe.h" +#include "nm-setting-proxy.h" +#include "nm-setting-serial.h" +#include "nm-setting-tc-config.h" +#include "nm-setting-team-port.h" +#include "nm-setting-team.h" +#include "nm-setting-tun.h" +#include "nm-setting-user.h" +#include "nm-setting-veth.h" +#include "nm-setting-vlan.h" +#include "nm-setting-vpn.h" +#include "nm-setting-vrf.h" +#include "nm-setting-vxlan.h" +#include "nm-setting-wifi-p2p.h" +#include "nm-setting-wimax.h" +#include "nm-setting-wired.h" +#include "nm-setting-wireguard.h" +#include "nm-setting-wireless-security.h" +#include "nm-setting-wireless.h" +#include "nm-setting-wpan.h" + +/*****************************************************************************/ + +const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { + +#define _D(_scheme_type, ...) [(_scheme_type)] = {.scheme_type = (_scheme_type), __VA_ARGS__} + + _D(NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT, + .setting_key = NM_SETTING_802_1X_CA_CERT, + .scheme_func = nm_setting_802_1x_get_ca_cert_scheme, + .format_func = NULL, + .path_func = nm_setting_802_1x_get_ca_cert_path, + .blob_func = nm_setting_802_1x_get_ca_cert_blob, + .uri_func = nm_setting_802_1x_get_ca_cert_uri, + .passwd_func = nm_setting_802_1x_get_ca_cert_password, + .pwflag_func = nm_setting_802_1x_get_ca_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_ca_cert, + .file_suffix = "ca-cert", ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT, + .setting_key = NM_SETTING_802_1X_PHASE2_CA_CERT, + .scheme_func = nm_setting_802_1x_get_phase2_ca_cert_scheme, + .format_func = NULL, + .path_func = nm_setting_802_1x_get_phase2_ca_cert_path, + .blob_func = nm_setting_802_1x_get_phase2_ca_cert_blob, + .uri_func = nm_setting_802_1x_get_phase2_ca_cert_uri, + .passwd_func = nm_setting_802_1x_get_phase2_ca_cert_password, + .pwflag_func = nm_setting_802_1x_get_phase2_ca_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_phase2_ca_cert, + .file_suffix = "inner-ca-cert", ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT, + .setting_key = NM_SETTING_802_1X_CLIENT_CERT, + .scheme_func = nm_setting_802_1x_get_client_cert_scheme, + .format_func = NULL, + .path_func = nm_setting_802_1x_get_client_cert_path, + .blob_func = nm_setting_802_1x_get_client_cert_blob, + .uri_func = nm_setting_802_1x_get_client_cert_uri, + .passwd_func = nm_setting_802_1x_get_client_cert_password, + .pwflag_func = nm_setting_802_1x_get_client_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_client_cert, + .file_suffix = "client-cert", ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT, + .setting_key = NM_SETTING_802_1X_PHASE2_CLIENT_CERT, + .scheme_func = nm_setting_802_1x_get_phase2_client_cert_scheme, + .format_func = NULL, + .path_func = nm_setting_802_1x_get_phase2_client_cert_path, + .blob_func = nm_setting_802_1x_get_phase2_client_cert_blob, + .uri_func = nm_setting_802_1x_get_phase2_client_cert_uri, + .passwd_func = nm_setting_802_1x_get_phase2_client_cert_password, + .pwflag_func = nm_setting_802_1x_get_phase2_client_cert_password_flags, + .set_cert_func = nm_setting_802_1x_set_phase2_client_cert, + .file_suffix = "inner-client-cert", ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY, + .setting_key = NM_SETTING_802_1X_PRIVATE_KEY, + .scheme_func = nm_setting_802_1x_get_private_key_scheme, + .format_func = nm_setting_802_1x_get_private_key_format, + .path_func = nm_setting_802_1x_get_private_key_path, + .blob_func = nm_setting_802_1x_get_private_key_blob, + .uri_func = nm_setting_802_1x_get_private_key_uri, + .passwd_func = nm_setting_802_1x_get_private_key_password, + .pwflag_func = nm_setting_802_1x_get_private_key_password_flags, + .set_private_key_func = nm_setting_802_1x_set_private_key, + .file_suffix = "private-key", + .is_secret = TRUE, ), + + _D(NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY, + .setting_key = NM_SETTING_802_1X_PHASE2_PRIVATE_KEY, + .scheme_func = nm_setting_802_1x_get_phase2_private_key_scheme, + .format_func = nm_setting_802_1x_get_phase2_private_key_format, + .path_func = nm_setting_802_1x_get_phase2_private_key_path, + .blob_func = nm_setting_802_1x_get_phase2_private_key_blob, + .uri_func = nm_setting_802_1x_get_phase2_private_key_uri, + .passwd_func = nm_setting_802_1x_get_phase2_private_key_password, + .pwflag_func = nm_setting_802_1x_get_phase2_private_key_password_flags, + .set_private_key_func = nm_setting_802_1x_set_phase2_private_key, + .file_suffix = "inner-private-key", + .is_secret = TRUE, ), + +#undef _D +}; + +/*****************************************************************************/ + +const NMMetaSettingInfo nm_meta_setting_infos[] = { + [NM_META_SETTING_TYPE_6LOWPAN] = + { + .meta_type = NM_META_SETTING_TYPE_6LOWPAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_6LOWPAN_SETTING_NAME, + .get_setting_gtype = nm_setting_6lowpan_get_type, + }, + [NM_META_SETTING_TYPE_802_1X] = + { + .meta_type = NM_META_SETTING_TYPE_802_1X, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_802_1X_SETTING_NAME, + .get_setting_gtype = nm_setting_802_1x_get_type, + }, + [NM_META_SETTING_TYPE_ADSL] = + { + .meta_type = NM_META_SETTING_TYPE_ADSL, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_ADSL_SETTING_NAME, + .get_setting_gtype = nm_setting_adsl_get_type, + }, + [NM_META_SETTING_TYPE_BLUETOOTH] = + { + .meta_type = NM_META_SETTING_TYPE_BLUETOOTH, + .setting_priority = NM_SETTING_PRIORITY_HW_NON_BASE, + .setting_name = NM_SETTING_BLUETOOTH_SETTING_NAME, + .get_setting_gtype = nm_setting_bluetooth_get_type, + }, + [NM_META_SETTING_TYPE_BOND] = + { + .meta_type = NM_META_SETTING_TYPE_BOND, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_BOND_SETTING_NAME, + .get_setting_gtype = nm_setting_bond_get_type, + }, + [NM_META_SETTING_TYPE_BRIDGE] = + { + .meta_type = NM_META_SETTING_TYPE_BRIDGE, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_BRIDGE_SETTING_NAME, + .get_setting_gtype = nm_setting_bridge_get_type, + }, + [NM_META_SETTING_TYPE_BRIDGE_PORT] = + { + .meta_type = NM_META_SETTING_TYPE_BRIDGE_PORT, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_BRIDGE_PORT_SETTING_NAME, + .get_setting_gtype = nm_setting_bridge_port_get_type, + }, + [NM_META_SETTING_TYPE_CDMA] = + { + .meta_type = NM_META_SETTING_TYPE_CDMA, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_CDMA_SETTING_NAME, + .get_setting_gtype = nm_setting_cdma_get_type, + }, + [NM_META_SETTING_TYPE_CONNECTION] = + { + .meta_type = NM_META_SETTING_TYPE_CONNECTION, + .setting_priority = NM_SETTING_PRIORITY_CONNECTION, + .setting_name = NM_SETTING_CONNECTION_SETTING_NAME, + .get_setting_gtype = nm_setting_connection_get_type, + }, + [NM_META_SETTING_TYPE_DCB] = + { + .meta_type = NM_META_SETTING_TYPE_DCB, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_DCB_SETTING_NAME, + .get_setting_gtype = nm_setting_dcb_get_type, + }, + [NM_META_SETTING_TYPE_DUMMY] = + { + .meta_type = NM_META_SETTING_TYPE_DUMMY, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_DUMMY_SETTING_NAME, + .get_setting_gtype = nm_setting_dummy_get_type, + }, + [NM_META_SETTING_TYPE_ETHTOOL] = + { + .meta_type = NM_META_SETTING_TYPE_ETHTOOL, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_ETHTOOL_SETTING_NAME, + .get_setting_gtype = nm_setting_ethtool_get_type, + }, + [NM_META_SETTING_TYPE_GENERIC] = + { + .meta_type = NM_META_SETTING_TYPE_GENERIC, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_GENERIC_SETTING_NAME, + .get_setting_gtype = nm_setting_generic_get_type, + }, + [NM_META_SETTING_TYPE_GSM] = + { + .meta_type = NM_META_SETTING_TYPE_GSM, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_GSM_SETTING_NAME, + .get_setting_gtype = nm_setting_gsm_get_type, + }, + [NM_META_SETTING_TYPE_HOSTNAME] = + { + .meta_type = NM_META_SETTING_TYPE_HOSTNAME, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_HOSTNAME_SETTING_NAME, + .get_setting_gtype = nm_setting_hostname_get_type, + }, + [NM_META_SETTING_TYPE_INFINIBAND] = + { + .meta_type = NM_META_SETTING_TYPE_INFINIBAND, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_INFINIBAND_SETTING_NAME, + .get_setting_gtype = nm_setting_infiniband_get_type, + }, + [NM_META_SETTING_TYPE_IP4_CONFIG] = + { + .meta_type = NM_META_SETTING_TYPE_IP4_CONFIG, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_IP4_CONFIG_SETTING_NAME, + .get_setting_gtype = nm_setting_ip4_config_get_type, + }, + [NM_META_SETTING_TYPE_IP6_CONFIG] = + { + .meta_type = NM_META_SETTING_TYPE_IP6_CONFIG, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_IP6_CONFIG_SETTING_NAME, + .get_setting_gtype = nm_setting_ip6_config_get_type, + }, + [NM_META_SETTING_TYPE_IP_TUNNEL] = + { + .meta_type = NM_META_SETTING_TYPE_IP_TUNNEL, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_IP_TUNNEL_SETTING_NAME, + .get_setting_gtype = nm_setting_ip_tunnel_get_type, + }, + [NM_META_SETTING_TYPE_MACSEC] = + { + .meta_type = NM_META_SETTING_TYPE_MACSEC, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_MACSEC_SETTING_NAME, + .get_setting_gtype = nm_setting_macsec_get_type, + }, + [NM_META_SETTING_TYPE_MACVLAN] = + { + .meta_type = NM_META_SETTING_TYPE_MACVLAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_MACVLAN_SETTING_NAME, + .get_setting_gtype = nm_setting_macvlan_get_type, + }, + [NM_META_SETTING_TYPE_MATCH] = + { + .meta_type = NM_META_SETTING_TYPE_MATCH, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_MATCH_SETTING_NAME, + .get_setting_gtype = nm_setting_match_get_type, + }, + [NM_META_SETTING_TYPE_OLPC_MESH] = + { + .meta_type = NM_META_SETTING_TYPE_OLPC_MESH, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OLPC_MESH_SETTING_NAME, + .get_setting_gtype = nm_setting_olpc_mesh_get_type, + }, + [NM_META_SETTING_TYPE_OVS_BRIDGE] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_BRIDGE, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_BRIDGE_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_bridge_get_type, + }, + [NM_META_SETTING_TYPE_OVS_DPDK] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_DPDK, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_DPDK_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_dpdk_get_type, + }, + [NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_external_ids_get_type, + }, + [NM_META_SETTING_TYPE_OVS_INTERFACE] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_INTERFACE, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_INTERFACE_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_interface_get_type, + }, + [NM_META_SETTING_TYPE_OVS_PATCH] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_PATCH, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_PATCH_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_patch_get_type, + }, + [NM_META_SETTING_TYPE_OVS_PORT] = + { + .meta_type = NM_META_SETTING_TYPE_OVS_PORT, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_OVS_PORT_SETTING_NAME, + .get_setting_gtype = nm_setting_ovs_port_get_type, + }, + [NM_META_SETTING_TYPE_PPPOE] = + { + .meta_type = NM_META_SETTING_TYPE_PPPOE, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_PPPOE_SETTING_NAME, + .get_setting_gtype = nm_setting_pppoe_get_type, + }, + [NM_META_SETTING_TYPE_PPP] = + { + .meta_type = NM_META_SETTING_TYPE_PPP, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_PPP_SETTING_NAME, + .get_setting_gtype = nm_setting_ppp_get_type, + }, + [NM_META_SETTING_TYPE_PROXY] = + { + .meta_type = NM_META_SETTING_TYPE_PROXY, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_PROXY_SETTING_NAME, + .get_setting_gtype = nm_setting_proxy_get_type, + }, + [NM_META_SETTING_TYPE_SERIAL] = + { + .meta_type = NM_META_SETTING_TYPE_SERIAL, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_SERIAL_SETTING_NAME, + .get_setting_gtype = nm_setting_serial_get_type, + }, + [NM_META_SETTING_TYPE_SRIOV] = + { + .meta_type = NM_META_SETTING_TYPE_SRIOV, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_SRIOV_SETTING_NAME, + .get_setting_gtype = nm_setting_sriov_get_type, + }, + [NM_META_SETTING_TYPE_TC_CONFIG] = + { + .meta_type = NM_META_SETTING_TYPE_TC_CONFIG, + .setting_priority = NM_SETTING_PRIORITY_IP, + .setting_name = NM_SETTING_TC_CONFIG_SETTING_NAME, + .get_setting_gtype = nm_setting_tc_config_get_type, + }, + [NM_META_SETTING_TYPE_TEAM] = + { + .meta_type = NM_META_SETTING_TYPE_TEAM, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_TEAM_SETTING_NAME, + .get_setting_gtype = nm_setting_team_get_type, + }, + [NM_META_SETTING_TYPE_TEAM_PORT] = + { + .meta_type = NM_META_SETTING_TYPE_TEAM_PORT, + .setting_priority = NM_SETTING_PRIORITY_AUX, + .setting_name = NM_SETTING_TEAM_PORT_SETTING_NAME, + .get_setting_gtype = nm_setting_team_port_get_type, + }, + [NM_META_SETTING_TYPE_TUN] = + { + .meta_type = NM_META_SETTING_TYPE_TUN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_TUN_SETTING_NAME, + .get_setting_gtype = nm_setting_tun_get_type, + }, + [NM_META_SETTING_TYPE_USER] = + { + .meta_type = NM_META_SETTING_TYPE_USER, + .setting_priority = NM_SETTING_PRIORITY_USER, + .setting_name = NM_SETTING_USER_SETTING_NAME, + .get_setting_gtype = nm_setting_user_get_type, + }, + [NM_META_SETTING_TYPE_VETH] = + { + .meta_type = NM_META_SETTING_TYPE_VETH, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VETH_SETTING_NAME, + .get_setting_gtype = nm_setting_veth_get_type, + }, + [NM_META_SETTING_TYPE_VLAN] = + { + .meta_type = NM_META_SETTING_TYPE_VLAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VLAN_SETTING_NAME, + .get_setting_gtype = nm_setting_vlan_get_type, + }, + [NM_META_SETTING_TYPE_VPN] = + { + .meta_type = NM_META_SETTING_TYPE_VPN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VPN_SETTING_NAME, + .get_setting_gtype = nm_setting_vpn_get_type, + }, + [NM_META_SETTING_TYPE_VRF] = + { + .meta_type = NM_META_SETTING_TYPE_VRF, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VRF_SETTING_NAME, + .get_setting_gtype = nm_setting_vrf_get_type, + }, + [NM_META_SETTING_TYPE_VXLAN] = + { + .meta_type = NM_META_SETTING_TYPE_VXLAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_VXLAN_SETTING_NAME, + .get_setting_gtype = nm_setting_vxlan_get_type, + }, + [NM_META_SETTING_TYPE_WIFI_P2P] = + { + .meta_type = NM_META_SETTING_TYPE_WIFI_P2P, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIFI_P2P_SETTING_NAME, + .get_setting_gtype = nm_setting_wifi_p2p_get_type, + }, + [NM_META_SETTING_TYPE_WIMAX] = + { + .meta_type = NM_META_SETTING_TYPE_WIMAX, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIMAX_SETTING_NAME, + .get_setting_gtype = nm_setting_wimax_get_type, + }, + [NM_META_SETTING_TYPE_WIRED] = + { + .meta_type = NM_META_SETTING_TYPE_WIRED, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIRED_SETTING_NAME, + .get_setting_gtype = nm_setting_wired_get_type, + }, + [NM_META_SETTING_TYPE_WIREGUARD] = + { + .meta_type = NM_META_SETTING_TYPE_WIREGUARD, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIREGUARD_SETTING_NAME, + .get_setting_gtype = nm_setting_wireguard_get_type, + }, + [NM_META_SETTING_TYPE_WIRELESS] = + { + .meta_type = NM_META_SETTING_TYPE_WIRELESS, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WIRELESS_SETTING_NAME, + .get_setting_gtype = nm_setting_wireless_get_type, + }, + [NM_META_SETTING_TYPE_WIRELESS_SECURITY] = + { + .meta_type = NM_META_SETTING_TYPE_WIRELESS_SECURITY, + .setting_priority = NM_SETTING_PRIORITY_HW_AUX, + .setting_name = NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, + .get_setting_gtype = nm_setting_wireless_security_get_type, + }, + [NM_META_SETTING_TYPE_WPAN] = + { + .meta_type = NM_META_SETTING_TYPE_WPAN, + .setting_priority = NM_SETTING_PRIORITY_HW_BASE, + .setting_name = NM_SETTING_WPAN_SETTING_NAME, + .get_setting_gtype = nm_setting_wpan_get_type, + }, + + [NM_META_SETTING_TYPE_UNKNOWN] = + { + .meta_type = NM_META_SETTING_TYPE_UNKNOWN, + }, +}; + +const NMMetaSettingInfo * +nm_meta_setting_infos_by_name(const char *name) +{ + gssize idx; + + if (NM_MORE_ASSERTS > 10) { + guint i, j; + + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + const NMMetaSettingInfo *setting_info = &nm_meta_setting_infos[i]; + + nm_assert(setting_info->meta_type == (NMMetaSettingType) i); + nm_assert(setting_info->setting_name); + nm_assert(setting_info->setting_name[0]); + nm_assert(setting_info->get_setting_gtype); + nm_assert(setting_info->setting_priority != NM_SETTING_PRIORITY_INVALID); + if (i > 0 + && strcmp(nm_meta_setting_infos[i - 1].setting_name, setting_info->setting_name) + >= 0) { + g_error("nm_meta_setting_infos[%u, \"%s\"] is wrongly sorted before " + "nm_meta_setting_infos[%u, \"%s\"]. Rearange NMMetaSettingType enum", + i - 1, + nm_meta_setting_infos[i - 1].setting_name, + i, + setting_info->setting_name); + } + for (j = 0; j < i; j++) { + const NMMetaSettingInfo *s = &nm_meta_setting_infos[j]; + + nm_assert(setting_info->get_setting_gtype != s->get_setting_gtype); + } + } + } + + G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(NMMetaSettingInfo, setting_name) == 0); + idx = nm_utils_array_find_binary_search(nm_meta_setting_infos, + sizeof(NMMetaSettingInfo), + _NM_META_SETTING_TYPE_NUM, + &name, + nm_strcmp_p_with_data, + NULL); + + return idx >= 0 ? &nm_meta_setting_infos[idx] : NULL; +} + +const NMMetaSettingInfo * +nm_meta_setting_infos_by_gtype(GType gtype) +{ +#if _NM_META_SETTING_BASE_IMPL_LIBNM + nm_auto_unref_gtypeclass GTypeClass *gtypeclass_unref = NULL; + GTypeClass * gtypeclass; + NMSettingClass * klass; + + if (!g_type_is_a(gtype, NM_TYPE_SETTING)) + goto out_none; + + gtypeclass = g_type_class_peek(gtype); + if (!gtypeclass) + gtypeclass = gtypeclass_unref = g_type_class_ref(gtype); + + nm_assert(NM_IS_SETTING_CLASS(gtypeclass)); + + klass = (NMSettingClass *) gtypeclass; + + if (!klass->setting_info) + goto out_none; + + nm_assert(klass->setting_info->get_setting_gtype); + nm_assert(klass->setting_info->get_setting_gtype() == gtype); + + return klass->setting_info; + +out_none: + + if (NM_MORE_ASSERTS > 10) { + int i; + + /* this might hint to a bug, but it would be expected for NM_TYPE_SETTING + * and NM_TYPE_SETTING_IP_CONFIG. + * + * Assert that we didn't lookup for a gtype, which we would expect to find. + * An assertion failure here, hints to a bug in nm_setting_*_class_init(). + */ + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) + nm_assert(nm_meta_setting_infos[i].get_setting_gtype() != gtype); + } + + return NULL; +#else + guint i; + + for (i = 0; i < _NM_META_SETTING_TYPE_NUM; i++) { + if (nm_meta_setting_infos[i].get_setting_gtype() == gtype) + return &nm_meta_setting_infos[i]; + } + return NULL; +#endif +} + +/*****************************************************************************/ + +NMSettingPriority +nm_meta_setting_info_get_base_type_priority(const NMMetaSettingInfo *setting_info, GType gtype) +{ + /* Historical oddity: PPPoE is a base-type even though it's not + * priority 1. It needs to be sorted *after* lower-level stuff like + * Wi-Fi security or 802.1x for secrets, but it's still allowed as a + * base type. + */ + + if (setting_info) { + if (NM_IN_SET(setting_info->setting_priority, + NM_SETTING_PRIORITY_HW_BASE, + NM_SETTING_PRIORITY_HW_NON_BASE) + || gtype == NM_TYPE_SETTING_PPPOE) + return setting_info->setting_priority; + } + + return NM_SETTING_PRIORITY_INVALID; +} + +NMSettingPriority +_nm_setting_type_get_base_type_priority(GType type) +{ + return nm_meta_setting_info_get_base_type_priority(nm_meta_setting_infos_by_gtype(type), type); +} + +/*****************************************************************************/ diff --git a/libnm-core/nm-meta-setting-base-impl.h b/libnm-core/nm-meta-setting-base-impl.h new file mode 100644 index 00000000..94b14e84 --- /dev/null +++ b/libnm-core/nm-meta-setting-base-impl.h @@ -0,0 +1,187 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2017 - 2018 Red Hat, Inc. + */ + +#ifndef __NM_META_SETTING_BASE_IMPL_H__ +#define __NM_META_SETTING_BASE_IMPL_H__ + +#include "nm-setting-8021x.h" + +/*****************************************************************************/ + +/* + * A setting's priority should roughly follow the OSI layer model, but it also + * controls which settings get asked for secrets first. Thus settings which + * relate to things that must be working first, like hardware, should get a + * higher priority than things which layer on top of the hardware. For example, + * the GSM/CDMA settings should provide secrets before the PPP setting does, + * because a PIN is required to unlock the device before PPP can even start. + * Even settings without secrets should be assigned the right priority. + * + * 0: reserved for invalid + * + * 1: reserved for the Connection setting + * + * 2,3: hardware-related settings like Ethernet, Wi-Fi, InfiniBand, Bridge, etc. + * These priority 1 settings are also "base types", which means that at least + * one of them is required for the connection to be valid, and their name is + * valid in the 'type' property of the Connection setting. + * + * 4: hardware-related auxiliary settings that require a base setting to be + * successful first, like Wi-Fi security, 802.1x, etc. + * + * 5: hardware-independent settings that are required before IP connectivity + * can be established, like PPP, PPPoE, etc. + * + * 6: IP-level stuff + * + * 10: NMSettingUser + */ +typedef enum { /*< skip >*/ + NM_SETTING_PRIORITY_INVALID = 0, + NM_SETTING_PRIORITY_CONNECTION = 1, + NM_SETTING_PRIORITY_HW_BASE = 2, + NM_SETTING_PRIORITY_HW_NON_BASE = 3, + NM_SETTING_PRIORITY_HW_AUX = 4, + NM_SETTING_PRIORITY_AUX = 5, + NM_SETTING_PRIORITY_IP = 6, + NM_SETTING_PRIORITY_USER = 10, +} NMSettingPriority; + +/*****************************************************************************/ + +typedef enum { + NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY, + + NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN, + + _NM_SETTING_802_1X_SCHEME_TYPE_NUM = NM_SETTING_802_1X_SCHEME_TYPE_UNKNOWN, +} NMSetting8021xSchemeType; + +typedef struct { + const char *setting_key; + 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); + const char *(*passwd_func)(NMSetting8021x *setting); + NMSettingSecretFlags (*pwflag_func)(NMSetting8021x *setting); + gboolean (*set_cert_func)(NMSetting8021x * setting, + const char * value, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError ** error); + gboolean (*set_private_key_func)(NMSetting8021x * setting, + const char * value, + const char * password, + NMSetting8021xCKScheme scheme, + NMSetting8021xCKFormat *out_format, + GError ** error); + const char * file_suffix; + NMSetting8021xSchemeType scheme_type; + bool is_secret : 1; +} NMSetting8021xSchemeVtable; + +extern const NMSetting8021xSchemeVtable + nm_setting_8021x_scheme_vtable[_NM_SETTING_802_1X_SCHEME_TYPE_NUM + 1]; + +/*****************************************************************************/ + +typedef enum { + /* the enum (and their numeric values) are internal API. Do not assign + * any meaning the numeric values, because they already have one: + * + * they are sorted in a way, that corresponds to the asciibetical sort + * order of the corresponding setting-name. */ + + NM_META_SETTING_TYPE_6LOWPAN, + NM_META_SETTING_TYPE_OLPC_MESH, + NM_META_SETTING_TYPE_WIRELESS, + NM_META_SETTING_TYPE_WIRELESS_SECURITY, + NM_META_SETTING_TYPE_802_1X, + NM_META_SETTING_TYPE_WIRED, + NM_META_SETTING_TYPE_ADSL, + NM_META_SETTING_TYPE_BLUETOOTH, + NM_META_SETTING_TYPE_BOND, + NM_META_SETTING_TYPE_BRIDGE, + NM_META_SETTING_TYPE_BRIDGE_PORT, + NM_META_SETTING_TYPE_CDMA, + NM_META_SETTING_TYPE_CONNECTION, + NM_META_SETTING_TYPE_DCB, + NM_META_SETTING_TYPE_DUMMY, + NM_META_SETTING_TYPE_ETHTOOL, + NM_META_SETTING_TYPE_GENERIC, + NM_META_SETTING_TYPE_GSM, + NM_META_SETTING_TYPE_HOSTNAME, + NM_META_SETTING_TYPE_INFINIBAND, + NM_META_SETTING_TYPE_IP_TUNNEL, + NM_META_SETTING_TYPE_IP4_CONFIG, + NM_META_SETTING_TYPE_IP6_CONFIG, + NM_META_SETTING_TYPE_MACSEC, + NM_META_SETTING_TYPE_MACVLAN, + NM_META_SETTING_TYPE_MATCH, + NM_META_SETTING_TYPE_OVS_BRIDGE, + NM_META_SETTING_TYPE_OVS_DPDK, + NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, + NM_META_SETTING_TYPE_OVS_INTERFACE, + NM_META_SETTING_TYPE_OVS_PATCH, + NM_META_SETTING_TYPE_OVS_PORT, + NM_META_SETTING_TYPE_PPP, + NM_META_SETTING_TYPE_PPPOE, + NM_META_SETTING_TYPE_PROXY, + NM_META_SETTING_TYPE_SERIAL, + NM_META_SETTING_TYPE_SRIOV, + NM_META_SETTING_TYPE_TC_CONFIG, + NM_META_SETTING_TYPE_TEAM, + NM_META_SETTING_TYPE_TEAM_PORT, + NM_META_SETTING_TYPE_TUN, + NM_META_SETTING_TYPE_USER, + NM_META_SETTING_TYPE_VETH, + NM_META_SETTING_TYPE_VLAN, + NM_META_SETTING_TYPE_VPN, + NM_META_SETTING_TYPE_VRF, + NM_META_SETTING_TYPE_VXLAN, + NM_META_SETTING_TYPE_WIFI_P2P, + NM_META_SETTING_TYPE_WIMAX, + NM_META_SETTING_TYPE_WIREGUARD, + NM_META_SETTING_TYPE_WPAN, + + NM_META_SETTING_TYPE_UNKNOWN, + + _NM_META_SETTING_TYPE_NUM = NM_META_SETTING_TYPE_UNKNOWN, +} NMMetaSettingType; + +#if _NM_META_SETTING_BASE_IMPL_LIBNM + #define _NMMetaSettingInfo_Alias _NMMetaSettingInfo +#else + #define _NMMetaSettingInfo_Alias _NMMetaSettingInfoCli +#endif + +struct _NMMetaSettingInfo_Alias { + const char *setting_name; + GType (*get_setting_gtype)(void); + NMMetaSettingType meta_type; + NMSettingPriority setting_priority; +}; + +typedef struct _NMMetaSettingInfo_Alias NMMetaSettingInfo; + +extern const NMMetaSettingInfo nm_meta_setting_infos[_NM_META_SETTING_TYPE_NUM + 1]; + +const NMMetaSettingInfo *nm_meta_setting_infos_by_name(const char *name); +const NMMetaSettingInfo *nm_meta_setting_infos_by_gtype(GType gtype); + +/*****************************************************************************/ + +NMSettingPriority nm_meta_setting_info_get_base_type_priority(const NMMetaSettingInfo *setting_info, + GType gtype); +NMSettingPriority _nm_setting_type_get_base_type_priority(GType type); + +#endif /* __NM_META_SETTING_BASE_IMPL_H__ */ diff --git a/libnm-core/nm-meta-setting-base.h b/libnm-core/nm-meta-setting-base.h new file mode 100644 index 00000000..72fa8e66 --- /dev/null +++ b/libnm-core/nm-meta-setting-base.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#ifndef __NM_META_SETTING_BASE_H__ +#define __NM_META_SETTING_BASE_H__ + +#define _NM_META_SETTING_BASE_IMPL_LIBNM 1 + +#include "nm-meta-setting-base-impl.h" + +#endif /* __NM_META_SETTING_BASE_H__ */ diff --git a/libnm-core/nm-property-compare.c b/libnm-core/nm-property-compare.c index 0de81bb3..c7cf10a2 100644 --- a/libnm-core/nm-property-compare.c +++ b/libnm-core/nm-property-compare.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-property-compare.h" diff --git a/libnm-core/nm-property-compare.h b/libnm-core/nm-property-compare.h index 0ae21790..d422b1c8 100644 --- a/libnm-core/nm-property-compare.h +++ b/libnm-core/nm-property-compare.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-6lowpan.c b/libnm-core/nm-setting-6lowpan.c index 630c3126..f71daf32 100644 --- a/libnm-core/nm-setting-6lowpan.c +++ b/libnm-core/nm-setting-6lowpan.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-6lowpan.h" @@ -179,7 +179,7 @@ nm_setting_6lowpan_init(NMSetting6Lowpan *setting) NMSetting * nm_setting_6lowpan_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_6LOWPAN, NULL); + return g_object_new(NM_TYPE_SETTING_6LOWPAN, NULL); } static void diff --git a/libnm-core/nm-setting-6lowpan.h b/libnm-core/nm-setting-6lowpan.h index 4dcb8619..5a7c3986 100644 --- a/libnm-core/nm-setting-6lowpan.h +++ b/libnm-core/nm-setting-6lowpan.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-8021x.c b/libnm-core/nm-setting-8021x.c index d3dc251a..1b38aa14 100644 --- a/libnm-core/nm-setting-8021x.c +++ b/libnm-core/nm-setting-8021x.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-8021x.h" @@ -3498,7 +3498,7 @@ nm_setting_802_1x_init(NMSetting8021x *setting) NMSetting * nm_setting_802_1x_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_802_1X, NULL); + return g_object_new(NM_TYPE_SETTING_802_1X, NULL); } static void @@ -3998,19 +3998,24 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass) /** * NMSetting8021x:phase2-auth: * - * Specifies the allowed "phase 2" inner non-EAP authentication method when - * an EAP method that uses an inner TLS tunnel is specified in the - * #NMSetting8021x:eap property. Recognized non-EAP "phase 2" methods are - * "pap", "chap", "mschap", "mschapv2", "gtc", "otp", "md5", and "tls". + * Specifies the allowed "phase 2" inner authentication method when an EAP + * method that uses an inner TLS tunnel is specified in the #NMSetting8021x:eap + * property. For TTLS this property selects one of the supported non-EAP + * inner methods: "pap", "chap", "mschap", "mschapv2" while + * #NMSetting8021x:phase2-autheap selects an EAP inner method. For PEAP + * this selects an inner EAP method, one of: "gtc", "otp", "md5" and "tls". * Each "phase 2" inner method requires specific parameters for successful * authentication; see the wpa_supplicant documentation for more details. + * Both #NMSetting8021x:phase2-auth and #NMSetting8021x:phase2-autheap cannot + * be specified. **/ /* ---ifcfg-rh--- * property: phase2-auth * variable: IEEE_8021X_INNER_AUTH_METHODS(+) * values: "PAP", "CHAP", "MSCHAP", "MSCHAPV2", "GTC", "OTP", "MD5" and "TLS" - * description: Inner non-EAP authentication methods. IEEE_8021X_INNER_AUTH_METHODS - * can contain values both for 'phase2-auth' and 'phase2-autheap' properties. + * description: Inner non-EAP authentication methods for TTLS or the inner EAP + * authentication method for PEAP. IEEE_8021X_INNER_AUTH_METHODS can contain + * values both for 'phase2-auth' and 'phase2-autheap' properties. * example: IEEE_8021X_INNER_AUTH_METHODS=PAP * ---end--- */ @@ -4025,11 +4030,11 @@ nm_setting_802_1x_class_init(NMSetting8021xClass *klass) * NMSetting8021x:phase2-autheap: * * Specifies the allowed "phase 2" inner EAP-based authentication method - * when an EAP method that uses an inner TLS tunnel is specified in the - * #NMSetting8021x:eap property. Recognized EAP-based "phase 2" methods are - * "md5", "mschapv2", "otp", "gtc", and "tls". Each "phase 2" inner method - * requires specific parameters for successful authentication; see the - * wpa_supplicant documentation for more details. + * when TTLS is specified in the #NMSetting8021x:eap property. Recognized + * EAP-based "phase 2" methods are "md5", "mschapv2", "otp", "gtc", and + * "tls". Each "phase 2" inner method requires specific parameters for + * successful authentication; see the wpa_supplicant documentation for + * more details. **/ /* ---ifcfg-rh--- * property: phase2-autheap diff --git a/libnm-core/nm-setting-8021x.h b/libnm-core/nm-setting-8021x.h index c784a748..30b725be 100644 --- a/libnm-core/nm-setting-8021x.h +++ b/libnm-core/nm-setting-8021x.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-adsl.c b/libnm-core/nm-setting-adsl.c index f84baf1f..f26698b6 100644 --- a/libnm-core/nm-setting-adsl.c +++ b/libnm-core/nm-setting-adsl.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 - 2013 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-adsl.h" @@ -316,7 +316,7 @@ nm_setting_adsl_init(NMSettingAdsl *setting) NMSetting * nm_setting_adsl_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_ADSL, NULL); + return g_object_new(NM_TYPE_SETTING_ADSL, NULL); } static void diff --git a/libnm-core/nm-setting-adsl.h b/libnm-core/nm-setting-adsl.h index b4aa0f8c..3d8e99c9 100644 --- a/libnm-core/nm-setting-adsl.h +++ b/libnm-core/nm-setting-adsl.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2008 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-bluetooth.c b/libnm-core/nm-setting-bluetooth.c index f836cea9..eb0e5930 100644 --- a/libnm-core/nm-setting-bluetooth.c +++ b/libnm-core/nm-setting-bluetooth.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-bluetooth.h" @@ -266,7 +266,7 @@ nm_setting_bluetooth_init(NMSettingBluetooth *setting) NMSetting * nm_setting_bluetooth_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_BLUETOOTH, NULL); + return g_object_new(NM_TYPE_SETTING_BLUETOOTH, NULL); } static void diff --git a/libnm-core/nm-setting-bluetooth.h b/libnm-core/nm-setting-bluetooth.h index afd4f102..4f001ef7 100644 --- a/libnm-core/nm-setting-bluetooth.h +++ b/libnm-core/nm-setting-bluetooth.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2009 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-bond.c b/libnm-core/nm-setting-bond.c index 1428ab63..2d64ef02 100644 --- a/libnm-core/nm-setting-bond.c +++ b/libnm-core/nm-setting-bond.c @@ -1,15 +1,16 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 - 2013 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-bond.h" #include #include #include +#include #include "nm-libnm-core-intern/nm-libnm-core-utils.h" #include "nm-utils.h" @@ -146,7 +147,7 @@ static char const *const _option_default_strv_mode[] = NM_MAKE_STRV("balanc static char const *const _option_default_strv_primary_reselect[] = NM_MAKE_STRV("always", "better", "failure"); static char const *const _option_default_strv_xmit_hash_policy[] = - NM_MAKE_STRV("layer2", "layer3+4", "layer2+3", "encap2+3", "encap3+4"); + NM_MAKE_STRV("layer2", "layer3+4", "layer2+3", "encap2+3", "encap3+4", "vlan+srcmac"); static NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE( _get_option_meta, @@ -198,7 +199,7 @@ static NM_UTILS_STRING_TABLE_LOOKUP_STRUCT_DEFINE( {NM_SETTING_BOND_OPTION_UPDELAY, {"0", NM_BOND_OPTION_TYPE_INT, 0, G_MAXINT}}, {NM_SETTING_BOND_OPTION_USE_CARRIER, {"1", NM_BOND_OPTION_TYPE_INT, 0, 1}}, {NM_SETTING_BOND_OPTION_XMIT_HASH_POLICY, - {"layer2", NM_BOND_OPTION_TYPE_BOTH, 0, 4, _option_default_strv_xmit_hash_policy}}, ); + {"layer2", NM_BOND_OPTION_TYPE_BOTH, 0, 5, _option_default_strv_xmit_hash_policy}}, ); /*****************************************************************************/ @@ -224,9 +225,10 @@ static NM_UTILS_STRING_TABLE_LOOKUP_DEFINE( {NM_SETTING_BOND_OPTION_PACKETS_PER_SLAVE, ~(BIT(NM_BOND_MODE_ROUNDROBIN))}, {NM_SETTING_BOND_OPTION_PRIMARY, ~(BIT(NM_BOND_MODE_ACTIVEBACKUP) | BIT(NM_BOND_MODE_TLB) | BIT(NM_BOND_MODE_ALB))}, - {NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, ~(BIT(NM_BOND_MODE_TLB))}, ) + {NM_SETTING_BOND_OPTION_TLB_DYNAMIC_LB, ~(BIT(NM_BOND_MODE_TLB))}, ); - gboolean _nm_setting_bond_option_supported(const char *option, NMBondMode mode) +gboolean +_nm_setting_bond_option_supported(const char *option, NMBondMode mode) { nm_assert(option); nm_assert(mode != NM_BOND_MODE_UNKNOWN); @@ -514,8 +516,8 @@ validate_ifname(const char *name, const char *value) return nm_utils_ifname_valid_kernel(value, NULL); } -static gboolean -_setting_bond_validate_option(const char *name, const char *value, GError **error) +gboolean +_nm_setting_bond_validate_option(const char *name, const char *value, GError **error) { const OptionMeta *option_meta; gboolean success; @@ -577,7 +579,7 @@ handle_error: /** * nm_setting_bond_validate_option: * @name: the name of the option to validate - * @value: the value of the option to validate + * @value (allow-none): the value of the option to validate. * * Checks whether @name is a valid bond option and @value is a valid value for * the @name. If @value is %NULL, the function only validates the option name. @@ -588,7 +590,7 @@ handle_error: gboolean nm_setting_bond_validate_option(const char *name, const char *value) { - return _setting_bond_validate_option(name, value, NULL); + return _nm_setting_bond_validate_option(name, value, NULL); } /** @@ -607,9 +609,6 @@ nm_setting_bond_get_option_by_name(NMSettingBond *setting, const char *name) { g_return_val_if_fail(NM_IS_SETTING_BOND(setting), NULL); - if (!nm_setting_bond_validate_option(name, NULL)) - return NULL; - return _bond_get_option(setting, name); } @@ -619,16 +618,18 @@ nm_setting_bond_get_option_by_name(NMSettingBond *setting, const char *name) * @name: name for the option * @value: value for the option * - * Add an option to the table. The option is compared to an internal list - * of allowed options. Option names may contain only alphanumeric characters - * (ie [a-zA-Z0-9]). Adding a new name replaces any existing name/value pair + * Add an option to the table. Adding a new name replaces any existing name/value pair * that may already exist. * - * The order of how to set several options is relevant because there are options - * that conflict with each other. + * Returns: returns %FALSE if either @name or @value is %NULL, in that case + * the option is not set. Otherwise, the function does not fail and does not validate + * the arguments. All validation happens via nm_connection_verify() or do basic validation + * yourself with nm_setting_bond_validate_option(). * - * Returns: %TRUE if the option was valid and was added to the internal option - * list, %FALSE if it was not. + * Note: Before 1.30, libnm would perform basic validation of the name and the value + * via nm_setting_bond_validate_option() and reject the request by returning FALSE. + * Since 1.30, libnm no longer rejects any values as the setter is not supposed + * to perform validation. **/ gboolean nm_setting_bond_add_option(NMSettingBond *setting, const char *name, const char *value) @@ -637,16 +638,16 @@ nm_setting_bond_add_option(NMSettingBond *setting, const char *name, const char g_return_val_if_fail(NM_IS_SETTING_BOND(setting), FALSE); - if (!value || !nm_setting_bond_validate_option(name, value)) + if (!name) + return FALSE; + if (!value) return FALSE; priv = NM_SETTING_BOND_GET_PRIVATE(setting); nm_clear_g_free(&priv->options_idx_cache); g_hash_table_insert(priv->options, g_strdup(name), g_strdup(value)); - _notify(setting, PROP_OPTIONS); - return TRUE; } @@ -665,20 +666,17 @@ gboolean nm_setting_bond_remove_option(NMSettingBond *setting, const char *name) { NMSettingBondPrivate *priv; - gboolean found; g_return_val_if_fail(NM_IS_SETTING_BOND(setting), FALSE); - if (!nm_setting_bond_validate_option(name, NULL)) - return FALSE; - priv = NM_SETTING_BOND_GET_PRIVATE(setting); + if (!g_hash_table_remove(priv->options, name)) + return FALSE; + nm_clear_g_free(&priv->options_idx_cache); - found = g_hash_table_remove(priv->options, name); - if (found) - _notify(setting, PROP_OPTIONS); - return found; + _notify(setting, PROP_OPTIONS); + return TRUE; } /** @@ -782,7 +780,7 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) for (i = 0; priv->options_idx_cache[i].name; i++) { n = &priv->options_idx_cache[i]; - if (!n->value_str || !_setting_bond_validate_option(n->name, n->value_str, error)) { + if (!n->value_str || !_nm_setting_bond_validate_option(n->name, n->value_str, error)) { g_prefix_error(error, "%s.%s: ", NM_SETTING_BOND_SETTING_NAME, @@ -1112,7 +1110,7 @@ nm_setting_bond_init(NMSettingBond *setting) NMSetting * nm_setting_bond_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_BOND, NULL); + return g_object_new(NM_TYPE_SETTING_BOND, NULL); } static void diff --git a/libnm-core/nm-setting-bond.h b/libnm-core/nm-setting-bond.h index b6d6b6a6..25ae8c36 100644 --- a/libnm-core/nm-setting-bond.h +++ b/libnm-core/nm-setting-bond.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 - 2013 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-bridge-port.c b/libnm-core/nm-setting-bridge-port.c index 1d9b6538..74c63847 100644 --- a/libnm-core/nm-setting-bridge-port.c +++ b/libnm-core/nm-setting-bridge-port.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2012 - 2013 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-bridge-port.h" @@ -452,7 +452,7 @@ nm_setting_bridge_port_init(NMSettingBridgePort *setting) NMSetting * nm_setting_bridge_port_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_BRIDGE_PORT, NULL); + return g_object_new(NM_TYPE_SETTING_BRIDGE_PORT, NULL); } static void diff --git a/libnm-core/nm-setting-bridge-port.h b/libnm-core/nm-setting-bridge-port.h index 0d218160..679131d2 100644 --- a/libnm-core/nm-setting-bridge-port.h +++ b/libnm-core/nm-setting-bridge-port.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2012 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-bridge.c b/libnm-core/nm-setting-bridge.c index 7356d568..15d663db 100644 --- a/libnm-core/nm-setting-bridge.c +++ b/libnm-core/nm-setting-bridge.c @@ -1,14 +1,15 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 - 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-bridge.h" #include #include +#include #include "nm-glib-aux/nm-str-buf.h" #include "nm-connection-private.h" @@ -1578,7 +1579,7 @@ nm_setting_bridge_init(NMSettingBridge *setting) NMSetting * nm_setting_bridge_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_BRIDGE, NULL); + return g_object_new(NM_TYPE_SETTING_BRIDGE, NULL); } static void diff --git a/libnm-core/nm-setting-bridge.h b/libnm-core/nm-setting-bridge.h index 4ab9af92..cda18612 100644 --- a/libnm-core/nm-setting-bridge.h +++ b/libnm-core/nm-setting-bridge.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 - 2015 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-cdma.c b/libnm-core/nm-setting-cdma.c index d2103b62..42e77c61 100644 --- a/libnm-core/nm-setting-cdma.c +++ b/libnm-core/nm-setting-cdma.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-cdma.h" @@ -251,7 +251,7 @@ nm_setting_cdma_init(NMSettingCdma *setting) NMSetting * nm_setting_cdma_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_CDMA, NULL); + return g_object_new(NM_TYPE_SETTING_CDMA, NULL); } static void diff --git a/libnm-core/nm-setting-cdma.h b/libnm-core/nm-setting-cdma.h index e98c8784..67784e89 100644 --- a/libnm-core/nm-setting-cdma.h +++ b/libnm-core/nm-setting-cdma.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2011 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-connection.c b/libnm-core/nm-setting-connection.c index a21e2c25..d6626a4d 100644 --- a/libnm-core/nm-setting-connection.c +++ b/libnm-core/nm-setting-connection.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-connection.h" @@ -969,12 +969,95 @@ _set_error_missing_base_setting(GError **error, const char *type) g_prefix_error(error, "%s: ", type); } -static gboolean -verify(NMSetting *setting, NMConnection *connection, GError **error) +gboolean +_nm_connection_detect_slave_type_full(NMSettingConnection *s_con, + NMConnection * connection, + const char ** out_slave_type, + const char ** out_normerr_slave_setting_type, + const char ** out_normerr_missing_slave_type, + const char ** out_normerr_missing_slave_type_port, + GError ** error) { - NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE(setting); + NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE(s_con); gboolean is_slave; const char * slave_setting_type; + const char * slave_type; + const char * normerr_slave_setting_type = NULL; + const char * normerr_missing_slave_type = NULL; + const char * normerr_missing_slave_type_port = NULL; + + is_slave = FALSE; + slave_setting_type = NULL; + slave_type = priv->slave_type; + if (slave_type) { + is_slave = _nm_setting_slave_type_is_valid(slave_type, &slave_setting_type); + if (!is_slave) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("Unknown slave type '%s'"), + slave_type); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_SLAVE_TYPE); + return FALSE; + } + } + + if (is_slave) { + if (!priv->master) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("Slave connections need a valid '%s' property"), + NM_SETTING_CONNECTION_MASTER); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_MASTER); + return FALSE; + } + if (slave_setting_type && connection + && !nm_connection_get_setting_by_name(connection, slave_setting_type)) + normerr_slave_setting_type = slave_setting_type; + } else { + nm_assert(!slave_type); + if (priv->master) { + NMSetting *s_port; + + if (connection + && (slave_type = _nm_connection_detect_slave_type(connection, &s_port))) { + normerr_missing_slave_type = slave_type; + normerr_missing_slave_type_port = nm_setting_get_name(s_port); + } else { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("Cannot set '%s' without '%s'"), + NM_SETTING_CONNECTION_MASTER, + NM_SETTING_CONNECTION_SLAVE_TYPE); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_CONNECTION_SETTING_NAME, + NM_SETTING_CONNECTION_SLAVE_TYPE); + return FALSE; + } + } + } + + NM_SET_OUT(out_slave_type, slave_type); + NM_SET_OUT(out_normerr_slave_setting_type, normerr_slave_setting_type); + NM_SET_OUT(out_normerr_missing_slave_type, normerr_missing_slave_type); + NM_SET_OUT(out_normerr_missing_slave_type_port, normerr_missing_slave_type_port); + return TRUE; +} + +static gboolean +verify(NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingConnection * self = NM_SETTING_CONNECTION(setting); + NMSettingConnectionPrivate *priv = NM_SETTING_CONNECTION_GET_PRIVATE(self); NMSetting * normerr_base_type = NULL; const char * type; const char * slave_type; @@ -1146,68 +1229,17 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) } after_interface_name: - is_slave = FALSE; - slave_setting_type = NULL; - slave_type = priv->slave_type; - if (slave_type) { - is_slave = _nm_setting_slave_type_is_valid(slave_type, &slave_setting_type); - if (!is_slave) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("Unknown slave type '%s'"), - slave_type); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_SLAVE_TYPE); - return FALSE; - } - } - - if (is_slave) { - if (!priv->master) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_MISSING_PROPERTY, - _("Slave connections need a valid '%s' property"), - NM_SETTING_CONNECTION_MASTER); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_MASTER); - return FALSE; - } - if (slave_setting_type && connection - && !nm_connection_get_setting_by_name(connection, slave_setting_type)) - normerr_slave_setting_type = slave_setting_type; - } else { - nm_assert(!slave_type); - if (priv->master) { - NMSetting *s_port; - - if (connection - && (slave_type = _nm_connection_detect_slave_type(connection, &s_port))) { - normerr_missing_slave_type = slave_type; - normerr_missing_slave_type_port = nm_setting_get_name(s_port); - } else { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_MISSING_PROPERTY, - _("Cannot set '%s' without '%s'"), - NM_SETTING_CONNECTION_MASTER, - NM_SETTING_CONNECTION_SLAVE_TYPE); - g_prefix_error(error, - "%s.%s: ", - NM_SETTING_CONNECTION_SETTING_NAME, - NM_SETTING_CONNECTION_SLAVE_TYPE); - return FALSE; - } - } - } + if (!_nm_connection_detect_slave_type_full(self, + connection, + &slave_type, + &normerr_slave_setting_type, + &normerr_missing_slave_type, + &normerr_missing_slave_type_port, + error)) + return FALSE; - if (strcmp(type, NM_SETTING_OVS_PORT_SETTING_NAME) == 0 && slave_type - && strcmp(slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME) != 0) { + if (nm_streq(type, NM_SETTING_OVS_PORT_SETTING_NAME) && slave_type + && !nm_streq(slave_type, NM_SETTING_OVS_BRIDGE_SETTING_NAME)) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_MISSING_PROPERTY, @@ -1750,7 +1782,7 @@ nm_setting_connection_init(NMSettingConnection *setting) NMSetting * nm_setting_connection_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_CONNECTION, NULL); + return g_object_new(NM_TYPE_SETTING_CONNECTION, NULL); } static void diff --git a/libnm-core/nm-setting-connection.h b/libnm-core/nm-setting-connection.h index 6ade3c1a..34b40a4f 100644 --- a/libnm-core/nm-setting-connection.h +++ b/libnm-core/nm-setting-connection.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-dcb.c b/libnm-core/nm-setting-dcb.c index 1b07af39..839d9146 100644 --- a/libnm-core/nm-setting-dcb.c +++ b/libnm-core/nm-setting-dcb.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2013 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-dcb.h" @@ -893,7 +893,7 @@ nm_setting_dcb_init(NMSettingDcb *self) NMSetting * nm_setting_dcb_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_DCB, NULL); + return g_object_new(NM_TYPE_SETTING_DCB, NULL); } static void diff --git a/libnm-core/nm-setting-dcb.h b/libnm-core/nm-setting-dcb.h index da14bcd4..a33c13ad 100644 --- a/libnm-core/nm-setting-dcb.h +++ b/libnm-core/nm-setting-dcb.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2013 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-dummy.c b/libnm-core/nm-setting-dummy.c index 3f5922f6..9ba626dc 100644 --- a/libnm-core/nm-setting-dummy.c +++ b/libnm-core/nm-setting-dummy.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-dummy.h" @@ -52,7 +52,7 @@ nm_setting_dummy_init(NMSettingDummy *setting) NMSetting * nm_setting_dummy_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_DUMMY, NULL); + return g_object_new(NM_TYPE_SETTING_DUMMY, NULL); } static void diff --git a/libnm-core/nm-setting-dummy.h b/libnm-core/nm-setting-dummy.h index ea2c4321..504428e7 100644 --- a/libnm-core/nm-setting-dummy.h +++ b/libnm-core/nm-setting-dummy.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-ethtool.c b/libnm-core/nm-setting-ethtool.c index 1c7fde65..f2c6d15e 100644 --- a/libnm-core/nm-setting-ethtool.c +++ b/libnm-core/nm-setting-ethtool.c @@ -1,14 +1,14 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ethtool.h" #include "nm-setting-private.h" -#include "nm-libnm-core-intern/nm-ethtool-utils.h" +#include "nm-base/nm-ethtool-base.h" /*****************************************************************************/ @@ -195,7 +195,7 @@ nm_setting_ethtool_clear_features(NMSettingEthtool *setting) guint nm_setting_ethtool_init_features( NMSettingEthtool *setting, - NMTernary * requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */) + NMOptionBool * requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */) { GHashTable * hash; GHashTableIter iter; @@ -208,7 +208,7 @@ nm_setting_ethtool_init_features( nm_assert(requested); for (i = 0; i < _NM_ETHTOOL_ID_FEATURE_NUM; i++) - requested[i] = NM_TERNARY_DEFAULT; + requested[i] = NM_OPTION_BOOL_DEFAULT; hash = _nm_setting_option_hash(NM_SETTING(setting), FALSE); if (!hash) @@ -224,7 +224,7 @@ nm_setting_ethtool_init_features( continue; requested[_NM_ETHTOOL_ID_FEATURE_AS_IDX(ethtool_id)] = - g_variant_get_boolean(variant) ? NM_TERNARY_TRUE : NM_TERNARY_FALSE; + g_variant_get_boolean(variant) ? NM_OPTION_BOOL_TRUE : NM_OPTION_BOOL_FALSE; n_req++; } @@ -254,7 +254,7 @@ const char ** nm_setting_ethtool_get_optnames(NMSettingEthtool *setting, guint *out_length) { const char *const *names; - guint len; + guint len = 0; g_return_val_if_fail(NM_IS_SETTING_ETHTOOL(setting), NULL); diff --git a/libnm-core/nm-setting-ethtool.h b/libnm-core/nm-setting-ethtool.h index 1a022bed..d2310b40 100644 --- a/libnm-core/nm-setting-ethtool.h +++ b/libnm-core/nm-setting-ethtool.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Red Hat, Inc. */ @@ -14,91 +14,6 @@ G_BEGIN_DECLS -/*****************************************************************************/ - -#define NM_ETHTOOL_OPTNAME_FEATURE_ESP_HW_OFFLOAD "feature-esp-hw-offload" -#define NM_ETHTOOL_OPTNAME_FEATURE_ESP_TX_CSUM_HW_OFFLOAD "feature-esp-tx-csum-hw-offload" -#define NM_ETHTOOL_OPTNAME_FEATURE_FCOE_MTU "feature-fcoe-mtu" -#define NM_ETHTOOL_OPTNAME_FEATURE_GRO "feature-gro" -#define NM_ETHTOOL_OPTNAME_FEATURE_GSO "feature-gso" -#define NM_ETHTOOL_OPTNAME_FEATURE_HIGHDMA "feature-highdma" -#define NM_ETHTOOL_OPTNAME_FEATURE_HW_TC_OFFLOAD "feature-hw-tc-offload" -#define NM_ETHTOOL_OPTNAME_FEATURE_L2_FWD_OFFLOAD "feature-l2-fwd-offload" -#define NM_ETHTOOL_OPTNAME_FEATURE_LOOPBACK "feature-loopback" -#define NM_ETHTOOL_OPTNAME_FEATURE_LRO "feature-lro" -#define NM_ETHTOOL_OPTNAME_FEATURE_NTUPLE "feature-ntuple" -#define NM_ETHTOOL_OPTNAME_FEATURE_RX "feature-rx" -#define NM_ETHTOOL_OPTNAME_FEATURE_RXHASH "feature-rxhash" -#define NM_ETHTOOL_OPTNAME_FEATURE_RXVLAN "feature-rxvlan" -#define NM_ETHTOOL_OPTNAME_FEATURE_RX_ALL "feature-rx-all" -#define NM_ETHTOOL_OPTNAME_FEATURE_RX_FCS "feature-rx-fcs" -#define NM_ETHTOOL_OPTNAME_FEATURE_RX_GRO_HW "feature-rx-gro-hw" -#define NM_ETHTOOL_OPTNAME_FEATURE_RX_UDP_TUNNEL_PORT_OFFLOAD "feature-rx-udp_tunnel-port-offload" -#define NM_ETHTOOL_OPTNAME_FEATURE_RX_VLAN_FILTER "feature-rx-vlan-filter" -#define NM_ETHTOOL_OPTNAME_FEATURE_RX_VLAN_STAG_FILTER "feature-rx-vlan-stag-filter" -#define NM_ETHTOOL_OPTNAME_FEATURE_RX_VLAN_STAG_HW_PARSE "feature-rx-vlan-stag-hw-parse" -#define NM_ETHTOOL_OPTNAME_FEATURE_SG "feature-sg" -#define NM_ETHTOOL_OPTNAME_FEATURE_TLS_HW_RECORD "feature-tls-hw-record" -#define NM_ETHTOOL_OPTNAME_FEATURE_TLS_HW_TX_OFFLOAD "feature-tls-hw-tx-offload" -#define NM_ETHTOOL_OPTNAME_FEATURE_TSO "feature-tso" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX "feature-tx" -#define NM_ETHTOOL_OPTNAME_FEATURE_TXVLAN "feature-txvlan" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_FCOE_CRC "feature-tx-checksum-fcoe-crc" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_IPV4 "feature-tx-checksum-ipv4" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_IPV6 "feature-tx-checksum-ipv6" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_IP_GENERIC "feature-tx-checksum-ip-generic" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_CHECKSUM_SCTP "feature-tx-checksum-sctp" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_ESP_SEGMENTATION "feature-tx-esp-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_FCOE_SEGMENTATION "feature-tx-fcoe-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_GRE_CSUM_SEGMENTATION "feature-tx-gre-csum-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_GRE_SEGMENTATION "feature-tx-gre-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_GSO_PARTIAL "feature-tx-gso-partial" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_GSO_ROBUST "feature-tx-gso-robust" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_IPXIP4_SEGMENTATION "feature-tx-ipxip4-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_IPXIP6_SEGMENTATION "feature-tx-ipxip6-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_NOCACHE_COPY "feature-tx-nocache-copy" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_SCATTER_GATHER "feature-tx-scatter-gather" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_SCATTER_GATHER_FRAGLIST "feature-tx-scatter-gather-fraglist" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_SCTP_SEGMENTATION "feature-tx-sctp-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_TCP6_SEGMENTATION "feature-tx-tcp6-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_TCP_ECN_SEGMENTATION "feature-tx-tcp-ecn-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_TCP_MANGLEID_SEGMENTATION \ - "feature-tx-tcp-mangleid-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_TCP_SEGMENTATION "feature-tx-tcp-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_UDP_SEGMENTATION "feature-tx-udp-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_UDP_TNL_CSUM_SEGMENTATION \ - "feature-tx-udp_tnl-csum-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_UDP_TNL_SEGMENTATION "feature-tx-udp_tnl-segmentation" -#define NM_ETHTOOL_OPTNAME_FEATURE_TX_VLAN_STAG_HW_INSERT "feature-tx-vlan-stag-hw-insert" - -#define NM_ETHTOOL_OPTNAME_COALESCE_ADAPTIVE_RX "coalesce-adaptive-rx" -#define NM_ETHTOOL_OPTNAME_COALESCE_ADAPTIVE_TX "coalesce-adaptive-tx" -#define NM_ETHTOOL_OPTNAME_COALESCE_PKT_RATE_HIGH "coalesce-pkt-rate-high" -#define NM_ETHTOOL_OPTNAME_COALESCE_PKT_RATE_LOW "coalesce-pkt-rate-low" -#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES "coalesce-rx-frames" -#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES_HIGH "coalesce-rx-frames-high" -#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES_IRQ "coalesce-rx-frames-irq" -#define NM_ETHTOOL_OPTNAME_COALESCE_RX_FRAMES_LOW "coalesce-rx-frames-low" -#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS "coalesce-rx-usecs" -#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS_HIGH "coalesce-rx-usecs-high" -#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS_IRQ "coalesce-rx-usecs-irq" -#define NM_ETHTOOL_OPTNAME_COALESCE_RX_USECS_LOW "coalesce-rx-usecs-low" -#define NM_ETHTOOL_OPTNAME_COALESCE_SAMPLE_INTERVAL "coalesce-sample-interval" -#define NM_ETHTOOL_OPTNAME_COALESCE_STATS_BLOCK_USECS "coalesce-stats-block-usecs" -#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES "coalesce-tx-frames" -#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES_HIGH "coalesce-tx-frames-high" -#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES_IRQ "coalesce-tx-frames-irq" -#define NM_ETHTOOL_OPTNAME_COALESCE_TX_FRAMES_LOW "coalesce-tx-frames-low" -#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS "coalesce-tx-usecs" -#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS_HIGH "coalesce-tx-usecs-high" -#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS_IRQ "coalesce-tx-usecs-irq" -#define NM_ETHTOOL_OPTNAME_COALESCE_TX_USECS_LOW "coalesce-tx-usecs-low" - -#define NM_ETHTOOL_OPTNAME_RING_RX "ring-rx" -#define NM_ETHTOOL_OPTNAME_RING_RX_JUMBO "ring-rx-jumbo" -#define NM_ETHTOOL_OPTNAME_RING_RX_MINI "ring-rx-mini" -#define NM_ETHTOOL_OPTNAME_RING_TX "ring-tx" - NM_AVAILABLE_IN_1_20 gboolean nm_ethtool_optname_is_feature(const char *optname); diff --git a/libnm-core/nm-setting-generic.c b/libnm-core/nm-setting-generic.c index 50269a19..07dbd9b8 100644 --- a/libnm-core/nm-setting-generic.c +++ b/libnm-core/nm-setting-generic.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2013 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-generic.h" @@ -48,7 +48,7 @@ nm_setting_generic_init(NMSettingGeneric *setting) NMSetting * nm_setting_generic_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_GENERIC, NULL); + return g_object_new(NM_TYPE_SETTING_GENERIC, NULL); } static void diff --git a/libnm-core/nm-setting-generic.h b/libnm-core/nm-setting-generic.h index a5cf55c9..5c0195f2 100644 --- a/libnm-core/nm-setting-generic.h +++ b/libnm-core/nm-setting-generic.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2013 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-gsm.c b/libnm-core/nm-setting-gsm.c index 1c31217c..c4eda969 100644 --- a/libnm-core/nm-setting-gsm.c +++ b/libnm-core/nm-setting-gsm.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-gsm.h" @@ -604,7 +604,7 @@ nm_setting_gsm_init(NMSettingGsm *setting) NMSetting * nm_setting_gsm_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_GSM, NULL); + return g_object_new(NM_TYPE_SETTING_GSM, NULL); } static void diff --git a/libnm-core/nm-setting-gsm.h b/libnm-core/nm-setting-gsm.h index 18f50b48..ed939e7c 100644 --- a/libnm-core/nm-setting-gsm.h +++ b/libnm-core/nm-setting-gsm.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2011 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-hostname.c b/libnm-core/nm-setting-hostname.c new file mode 100644 index 00000000..2396b7bd --- /dev/null +++ b/libnm-core/nm-setting-hostname.c @@ -0,0 +1,339 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020 Red Hat, Inc. + */ + +#include "libnm-core/nm-default-libnm-core.h" + +#include "nm-setting-hostname.h" + +#include "nm-setting-private.h" +#include "nm-utils-private.h" + +/** + * SECTION:nm-setting-hostname + * @short_description: Contains properties related to the hostname + * @include: nm-setting-hostname.h + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMSettingHostname, + PROP_PRIORITY, + PROP_FROM_DHCP, + PROP_FROM_DNS_LOOKUP, + PROP_ONLY_FROM_DEFAULT, ); + +/** + * NMSettingHostname: + * + * Hostname settings + * + * Since: 1.30 + */ +struct _NMSettingHostname { + NMSetting parent; + int priority; + NMTernary from_dhcp; + NMTernary from_dns_lookup; + NMTernary only_from_default; +}; + +struct _NMSettingHostnameClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingHostname, nm_setting_hostname, NM_TYPE_SETTING) + +/** + * nm_setting_hostname_get_priority: + * @setting: the #NMSettingHostname + * + * Returns the value contained in the #NMSettingHostname:priority + * property. + * + * Returns: the 'priority' property value + * + * Since: 1.30 + **/ +int +nm_setting_hostname_get_priority(NMSettingHostname *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HOSTNAME(setting), 0); + + return setting->priority; +} + +/** + * nm_setting_hostname_get_from_dhcp: + * @setting: the #NMSettingHostname + * + * Returns the value contained in the #NMSettingHostname:from-dhcp + * property. + * + * Returns: the 'from-dhcp' property value + * + * Since: 1.30 + **/ +NMTernary +nm_setting_hostname_get_from_dhcp(NMSettingHostname *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HOSTNAME(setting), NM_TERNARY_DEFAULT); + + return setting->from_dhcp; +} + +/** + * nm_setting_hostname_get_from_dns_lookup: + * @setting: the #NMSettingHostname + * + * Returns the value contained in the #NMSettingHostname:from-dns-lookup + * property. + * + * Returns: the 'from-dns-lookup' property value + * + * Since: 1.30 + **/ +NMTernary +nm_setting_hostname_get_from_dns_lookup(NMSettingHostname *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HOSTNAME(setting), NM_TERNARY_DEFAULT); + + return setting->from_dns_lookup; +} + +/** + * nm_setting_hostname_get_only_from_default: + * @setting: the #NMSettingHostname + * + * Returns the value contained in the #NMSettingHostname:only-from-default + * property. + * + * Returns: the 'only-from-default' property value + * + * Since: 1.30 + **/ +NMTernary +nm_setting_hostname_get_only_from_default(NMSettingHostname *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_HOSTNAME(setting), NM_TERNARY_DEFAULT); + + return setting->only_from_default; +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMSettingHostname *self = NM_SETTING_HOSTNAME(object); + + switch (prop_id) { + case PROP_PRIORITY: + g_value_set_int(value, self->priority); + break; + case PROP_FROM_DHCP: + g_value_set_enum(value, self->from_dhcp); + break; + case PROP_FROM_DNS_LOOKUP: + g_value_set_enum(value, self->from_dns_lookup); + break; + case PROP_ONLY_FROM_DEFAULT: + g_value_set_enum(value, self->only_from_default); + 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) +{ + NMSettingHostname *self = NM_SETTING_HOSTNAME(object); + + switch (prop_id) { + case PROP_PRIORITY: + self->priority = g_value_get_int(value); + break; + case PROP_FROM_DHCP: + self->from_dhcp = g_value_get_enum(value); + break; + case PROP_FROM_DNS_LOOKUP: + self->from_dns_lookup = g_value_get_enum(value); + break; + case PROP_ONLY_FROM_DEFAULT: + self->only_from_default = g_value_get_enum(value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_hostname_init(NMSettingHostname *setting) +{ + setting->from_dhcp = NM_TERNARY_DEFAULT; + setting->from_dns_lookup = NM_TERNARY_DEFAULT; + setting->only_from_default = NM_TERNARY_DEFAULT; +} + +/** + * nm_setting_hostname_new: + * + * Creates a new #NMSettingHostname object with default values. + * + * Returns: (transfer full): the new empty #NMSettingHostname object + * + * Since: 1.30 + **/ +NMSetting * +nm_setting_hostname_new(void) +{ + return g_object_new(NM_TYPE_SETTING_HOSTNAME, NULL); +} + +static void +nm_setting_hostname_class_init(NMSettingHostnameClass *klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMSettingClass *setting_class = NM_SETTING_CLASS(klass); + + object_class->get_property = get_property; + object_class->set_property = set_property; + + /** + * NMSettingHostname:priority + * + * The relative priority of this connection to determine the + * system hostname. A lower numerical value is better (higher + * priority). A connection with higher priority is considered + * before connections with lower priority. + * + * If the value is zero, it can be overridden by a global value + * from NetworkManager configuration. If the property doesn't have + * a value in the global configuration, the value is assumed to be + * 100. + * + * Negative values have the special effect of excluding other + * connections with a greater numerical priority value; so in + * presence of at least one negative priority, only connections + * with the lowest priority value will be used to determine the + * hostname. + * + * Since: 1.30 + **/ + /* ---ifcfg-rh--- + * property: priority + * variable: HOSTNAME_PRIORITY(+) + * default: missing variable means global value or 100 + * description: hostname priority + * example: HOSTNAME_PRIORITY=50 + * ---end--- + */ + obj_properties[PROP_PRIORITY] = g_param_spec_int(NM_SETTING_HOSTNAME_PRIORITY, + "", + "", + G_MININT32, + G_MAXINT32, + 0, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingHostname:from-dhcp + * + * Whether the system hostname can be determined from DHCP on + * this connection. + * + * When set to %NM_TERNARY_DEFAULT, the value from global configuration + * is used. If the property doesn't have a value in the global + * configuration, NetworkManager assumes the value to be %NM_TERNARY_TRUE. + * + * Since: 1.30 + **/ + /* ---ifcfg-rh--- + * property: from-dhcp + * variable: HOSTNAME_FROM_DHCP(+) + * default: missing variable means global default or 1 + * description: whether the system hostname can be determined from DHCP + * example: HOSTNAME_FROM_DHCP=0,1 + * ---end--- + */ + obj_properties[PROP_FROM_DHCP] = g_param_spec_enum( + NM_SETTING_HOSTNAME_FROM_DHCP, + "", + "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingHostname:from-dns-lookup + * + * Whether the system hostname can be determined from reverse + * DNS lookup of addresses on this device. + * + * When set to %NM_TERNARY_DEFAULT, the value from global configuration + * is used. If the property doesn't have a value in the global + * configuration, NetworkManager assumes the value to be %NM_TERNARY_TRUE. + * + * Since: 1.30 + **/ + /* ---ifcfg-rh--- + * property: from-dhcp + * variable: HOSTNAME_FROM_DNS_LOOKUP(+) + * default: missing variable means global default or 1 + * description: whether the system hostname can be determined from reverse + * DNS lookup + * example: HOSTNAME_FROM_DNS_LOOKUP=0,1 + * ---end--- + */ + obj_properties[PROP_FROM_DNS_LOOKUP] = g_param_spec_enum( + NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP, + "", + "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingHostname:only-from-default + * + * If set to %NM_TERNARY_TRUE, NetworkManager attempts to get + * the hostname via DHCPv4/DHCPv6 or reverse DNS lookup on this + * device only when the device has the default route for the given + * address family (IPv4/IPv6). + * + * If set to %NM_TERNARY_FALSE, the hostname can be set from this + * device even if it doesn't have the default route. + * + * When set to %NM_TERNARY_DEFAULT, the value from global configuration + * is used. If the property doesn't have a value in the global + * configuration, NetworkManager assumes the value to be %NM_TERNARY_FALSE. + * + * Since: 1.30 + **/ + /* ---ifcfg-rh--- + * property: only-best-device + * variable: HOSTNAME_ONLY_FROM_DEFAULT(+) + * default: missing variable means global default or 1 + * description: whether the hostname can be determined only from + * devices with the default route + * example: HOSTNAME_ONLY_FROM_DEFAULT=0,1 + * ---end--- + */ + obj_properties[PROP_ONLY_FROM_DEFAULT] = g_param_spec_enum( + NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT, + "", + "", + NM_TYPE_TERNARY, + NM_TERNARY_DEFAULT, + NM_SETTING_PARAM_FUZZY_IGNORE | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit(setting_class, NM_META_SETTING_TYPE_HOSTNAME); +} diff --git a/libnm-core/nm-setting-hostname.h b/libnm-core/nm-setting-hostname.h new file mode 100644 index 00000000..02b4e373 --- /dev/null +++ b/libnm-core/nm-setting-hostname.h @@ -0,0 +1,53 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020 Red Hat, Inc. + */ + +#ifndef NM_SETTING_HOSTNAME_H +#define NM_SETTING_HOSTNAME_H + +#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION) + #error "Only can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_HOSTNAME (nm_setting_hostname_get_type()) +#define NM_SETTING_HOSTNAME(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_HOSTNAME, NMSettingHostname)) +#define NM_SETTING_HOSTNAME_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), NM_TYPE_SETTING_HOSTNAME, NMSettingHostnameClass)) +#define NM_IS_SETTING_HOSTNAME(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_HOSTNAME)) +#define NM_IS_SETTING_HOSTNAME_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_HOSTNAME)) +#define NM_SETTING_HOSTNAME_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_SETTING_HOSTNAME, NMSettingHostnameClass)) + +#define NM_SETTING_HOSTNAME_SETTING_NAME "hostname" + +#define NM_SETTING_HOSTNAME_PRIORITY "priority" +#define NM_SETTING_HOSTNAME_FROM_DHCP "from-dhcp" +#define NM_SETTING_HOSTNAME_FROM_DNS_LOOKUP "from-dns-lookup" +#define NM_SETTING_HOSTNAME_ONLY_FROM_DEFAULT "only-from-default" + +typedef struct _NMSettingHostnameClass NMSettingHostnameClass; + +NM_AVAILABLE_IN_1_30 +GType nm_setting_hostname_get_type(void); +NM_AVAILABLE_IN_1_30 +NMSetting *nm_setting_hostname_new(void); + +NM_AVAILABLE_IN_1_30 +int nm_setting_hostname_get_priority(NMSettingHostname *setting); +NM_AVAILABLE_IN_1_30 +NMTernary nm_setting_hostname_get_from_dhcp(NMSettingHostname *setting); +NM_AVAILABLE_IN_1_30 +NMTernary nm_setting_hostname_get_from_dns_lookup(NMSettingHostname *setting); +NM_AVAILABLE_IN_1_30 +NMTernary nm_setting_hostname_get_only_from_default(NMSettingHostname *setting); + +G_END_DECLS + +#endif /* NM_SETTING_HOSTNAME_H */ diff --git a/libnm-core/nm-setting-infiniband.c b/libnm-core/nm-setting-infiniband.c index 7469f437..c315843c 100644 --- a/libnm-core/nm-setting-infiniband.c +++ b/libnm-core/nm-setting-infiniband.c @@ -1,13 +1,14 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 - 2013 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-infiniband.h" #include +#include #include "nm-utils.h" #include "nm-utils-private.h" @@ -353,7 +354,7 @@ nm_setting_infiniband_init(NMSettingInfiniband *self) NMSetting * nm_setting_infiniband_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_INFINIBAND, NULL); + return g_object_new(NM_TYPE_SETTING_INFINIBAND, NULL); } static void diff --git a/libnm-core/nm-setting-infiniband.h b/libnm-core/nm-setting-infiniband.h index c169f46d..4a771aef 100644 --- a/libnm-core/nm-setting-infiniband.h +++ b/libnm-core/nm-setting-infiniband.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-ip-config.c b/libnm-core/nm-setting-ip-config.c index 7b6624d8..45ecbd88 100644 --- a/libnm-core/nm-setting-ip-config.c +++ b/libnm-core/nm-setting-ip-config.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2017 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ip-config.h" @@ -5889,6 +5889,10 @@ nm_setting_ip_config_class_init(NMSettingIPConfigClass *klass) * name servers to resolv.conf, and if all contributing profiles have * "trust-ad" enabled. * + * When using a caching DNS plugin (dnsmasq or systemd-resolved in + * NetworkManager.conf) then "edns0" and "trust-ad" are automatically + * added. + * * Since: 1.2 **/ obj_properties[PROP_DNS_OPTIONS] = diff --git a/libnm-core/nm-setting-ip-config.h b/libnm-core/nm-setting-ip-config.h index b6d2e184..1cb16717 100644 --- a/libnm-core/nm-setting-ip-config.h +++ b/libnm-core/nm-setting-ip-config.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-ip-tunnel.c b/libnm-core/nm-setting-ip-tunnel.c index e2f0b0ca..998b816b 100644 --- a/libnm-core/nm-setting-ip-tunnel.c +++ b/libnm-core/nm-setting-ip-tunnel.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ip-tunnel.h" @@ -617,7 +617,7 @@ nm_setting_ip_tunnel_init(NMSettingIPTunnel *self) NMSetting * nm_setting_ip_tunnel_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_IP_TUNNEL, NULL); + return g_object_new(NM_TYPE_SETTING_IP_TUNNEL, NULL); } static void diff --git a/libnm-core/nm-setting-ip-tunnel.h b/libnm-core/nm-setting-ip-tunnel.h index 8a493400..802f81e1 100644 --- a/libnm-core/nm-setting-ip-tunnel.h +++ b/libnm-core/nm-setting-ip-tunnel.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-ip4-config.c b/libnm-core/nm-setting-ip4-config.c index 46579ba9..20fbc017 100644 --- a/libnm-core/nm-setting-ip4-config.c +++ b/libnm-core/nm-setting-ip4-config.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2014 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ip4-config.h" @@ -594,7 +594,7 @@ nm_setting_ip4_config_init(NMSettingIP4Config *setting) NMSetting * nm_setting_ip4_config_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_IP4_CONFIG, NULL); + return g_object_new(NM_TYPE_SETTING_IP4_CONFIG, NULL); } static void @@ -667,7 +667,7 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) * ---end--- * ---ifcfg-rh--- * property: addresses - * variable: IPADDR, PREFIX, IPADDR1, PREFIX1, ... + * variable: IPADDR, PREFIX (NETMASK), IPADDR1, PREFIX1 (NETMASK1), ... * description: List of static IP addresses. * example: IPADDR=10.5.5.23 PREFIX=24 IPADDR1=1.1.1.2 PREFIX1=16 * ---end--- @@ -808,8 +808,12 @@ nm_setting_ip4_config_class_init(NMSettingIP4ConfigClass *klass) * with type ethernet (01). Currently, these options only work for ethernet * type of links. * + * The special value "ipv6-duid" uses the DUID from "ipv6.dhcp-duid" property as + * an RFC4361-compliant client identifier. As IAID it uses "ipv4.dhcp-iaid" + * and falls back to "ipv6.dhcp-iaid" if unset. + * * The special value "duid" generates a RFC4361-compliant client identifier based - * on a hash of the interface name as IAID and /etc/machine-id. + * on "ipv4.dhcp-iaid" and uses a DUID generated by hashing /etc/machine-id. * * The special value "stable" is supported to generate a type 0 client identifier based * on the stable-id (see connection.stable-id) and a per-host key. If you set the diff --git a/libnm-core/nm-setting-ip4-config.h b/libnm-core/nm-setting-ip4-config.h index 8102b9f4..b1c63a4f 100644 --- a/libnm-core/nm-setting-ip4-config.h +++ b/libnm-core/nm-setting-ip4-config.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-ip6-config.c b/libnm-core/nm-setting-ip6-config.c index c22e3588..06463f82 100644 --- a/libnm-core/nm-setting-ip6-config.c +++ b/libnm-core/nm-setting-ip6-config.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ip6-config.h" @@ -592,7 +592,7 @@ nm_setting_ip6_config_init(NMSettingIP6Config *setting) NMSetting * nm_setting_ip6_config_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_IP6_CONFIG, NULL); + return g_object_new(NM_TYPE_SETTING_IP6_CONFIG, NULL); } static void diff --git a/libnm-core/nm-setting-ip6-config.h b/libnm-core/nm-setting-ip6-config.h index 51714316..fca6961b 100644 --- a/libnm-core/nm-setting-ip6-config.h +++ b/libnm-core/nm-setting-ip6-config.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-macsec.c b/libnm-core/nm-setting-macsec.c index 6f185a9a..d70696d9 100644 --- a/libnm-core/nm-setting-macsec.c +++ b/libnm-core/nm-setting-macsec.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-macsec.h" @@ -495,7 +495,7 @@ nm_setting_macsec_init(NMSettingMacsec *self) NMSetting * nm_setting_macsec_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_MACSEC, NULL); + return g_object_new(NM_TYPE_SETTING_MACSEC, NULL); } static void diff --git a/libnm-core/nm-setting-macsec.h b/libnm-core/nm-setting-macsec.h index 4d955743..bc33dd9d 100644 --- a/libnm-core/nm-setting-macsec.h +++ b/libnm-core/nm-setting-macsec.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-macvlan.c b/libnm-core/nm-setting-macvlan.c index eed137c3..8c8c6279 100644 --- a/libnm-core/nm-setting-macvlan.c +++ b/libnm-core/nm-setting-macvlan.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-macvlan.h" @@ -236,7 +236,7 @@ nm_setting_macvlan_init(NMSettingMacvlan *self) NMSetting * nm_setting_macvlan_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_MACVLAN, NULL); + return g_object_new(NM_TYPE_SETTING_MACVLAN, NULL); } static void diff --git a/libnm-core/nm-setting-macvlan.h b/libnm-core/nm-setting-macvlan.h index 0e79a4ff..05c0b365 100644 --- a/libnm-core/nm-setting-macvlan.h +++ b/libnm-core/nm-setting-macvlan.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-match.c b/libnm-core/nm-setting-match.c index 5709a403..108aba95 100644 --- a/libnm-core/nm-setting-match.c +++ b/libnm-core/nm-setting-match.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-match.h" @@ -683,7 +683,7 @@ nm_setting_match_init(NMSettingMatch *setting) NMSetting * nm_setting_match_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_MATCH, NULL); + return g_object_new(NM_TYPE_SETTING_MATCH, NULL); } static gboolean diff --git a/libnm-core/nm-setting-match.h b/libnm-core/nm-setting-match.h index 9731854a..9b3e29e7 100644 --- a/libnm-core/nm-setting-match.h +++ b/libnm-core/nm-setting-match.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-olpc-mesh.c b/libnm-core/nm-setting-olpc-mesh.c index e9efbe1e..ef0b5d60 100644 --- a/libnm-core/nm-setting-olpc-mesh.c +++ b/libnm-core/nm-setting-olpc-mesh.c @@ -1,14 +1,16 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. * Copyright (C) 2009 One Laptop per Child */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-olpc-mesh.h" +#include + #include "nm-utils.h" #include "nm-utils-private.h" #include "nm-setting-private.h" @@ -190,7 +192,7 @@ nm_setting_olpc_mesh_init(NMSettingOlpcMesh *setting) NMSetting * nm_setting_olpc_mesh_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_OLPC_MESH, NULL); + return g_object_new(NM_TYPE_SETTING_OLPC_MESH, NULL); } static void diff --git a/libnm-core/nm-setting-olpc-mesh.h b/libnm-core/nm-setting-olpc-mesh.h index fce8ddfa..fdba4a4b 100644 --- a/libnm-core/nm-setting-olpc-mesh.h +++ b/libnm-core/nm-setting-olpc-mesh.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2008 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-ovs-bridge.c b/libnm-core/nm-setting-ovs-bridge.c index 15eed030..07d24d7b 100644 --- a/libnm-core/nm-setting-ovs-bridge.c +++ b/libnm-core/nm-setting-ovs-bridge.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ovs-bridge.h" @@ -272,7 +272,7 @@ nm_setting_ovs_bridge_init(NMSettingOvsBridge *self) NMSetting * nm_setting_ovs_bridge_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_OVS_BRIDGE, NULL); + return g_object_new(NM_TYPE_SETTING_OVS_BRIDGE, NULL); } static void diff --git a/libnm-core/nm-setting-ovs-bridge.h b/libnm-core/nm-setting-ovs-bridge.h index 58ed9bd8..b3078715 100644 --- a/libnm-core/nm-setting-ovs-bridge.h +++ b/libnm-core/nm-setting-ovs-bridge.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-ovs-dpdk.c b/libnm-core/nm-setting-ovs-dpdk.c index d6bd8804..6d27d78c 100644 --- a/libnm-core/nm-setting-ovs-dpdk.c +++ b/libnm-core/nm-setting-ovs-dpdk.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ovs-dpdk.h" @@ -109,7 +109,7 @@ nm_setting_ovs_dpdk_init(NMSettingOvsDpdk *self) NMSetting * nm_setting_ovs_dpdk_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_OVS_DPDK, NULL); + return g_object_new(NM_TYPE_SETTING_OVS_DPDK, NULL); } static void diff --git a/libnm-core/nm-setting-ovs-dpdk.h b/libnm-core/nm-setting-ovs-dpdk.h index f32b9685..72de2243 100644 --- a/libnm-core/nm-setting-ovs-dpdk.h +++ b/libnm-core/nm-setting-ovs-dpdk.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-ovs-external-ids.c b/libnm-core/nm-setting-ovs-external-ids.c new file mode 100644 index 00000000..16becb72 --- /dev/null +++ b/libnm-core/nm-setting-ovs-external-ids.c @@ -0,0 +1,551 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2017 - 2020 Red Hat, Inc. + */ + +#include "libnm-core/nm-default-libnm-core.h" + +#include "nm-setting-ovs-external-ids.h" + +#include "nm-setting-private.h" +#include "nm-utils-private.h" +#include "nm-connection-private.h" + +#define MAX_NUM_KEYS 256 + +/*****************************************************************************/ + +/** + * SECTION:nm-setting-ovs-external-ids + * @short_description: External-IDs for OVS database + * + * The #NMSettingOvsExternalIDs object is a #NMSetting subclass that allow to + * configure external ids for OVS. + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMSettingOvsExternalIDs, PROP_DATA, ); + +typedef struct { + GHashTable * data; + const char **data_keys; +} NMSettingOvsExternalIDsPrivate; + +/** + * NMSettingOvsExternalIDs: + * + * OVS External IDs Settings + */ +struct _NMSettingOvsExternalIDs { + NMSetting parent; + NMSettingOvsExternalIDsPrivate _priv; +}; + +struct _NMSettingOvsExternalIDsClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingOvsExternalIDs, nm_setting_ovs_external_ids, NM_TYPE_SETTING) + +#define NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMSettingOvsExternalIDs, NM_IS_SETTING_OVS_EXTERNAL_IDS) + +/*****************************************************************************/ + +static gboolean +_exid_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_ovs_external_ids_check_key: + * @key: (allow-none): the key to check + * @error: a #GError, %NULL to ignore. + * + * Checks whether @key is a valid key for OVS' external-ids. + * This means, the key cannot be %NULL, not too large and valid ASCII. + * Also, only digits and numbers are allowed with a few special + * characters. They key must also not start with "NM.". + * + * Since: 1.30 + * + * Returns: %TRUE if @key is a valid user data key. + */ +gboolean +nm_setting_ovs_external_ids_check_key(const char *key, GError **error) +{ + gsize len; + + 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 > 255u) { + 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; + } + if (!NM_STRCHAR_ALL(key, ch, _exid_key_char_is_regular(ch))) { + /* Probably OVS is more forgiving about what makes a valid key for + * an external-id. However, we are strict (at least, for now). */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key contains invalid characters")); + return FALSE; + } + + if (NM_STR_HAS_PREFIX(key, NM_OVS_EXTERNAL_ID_NM_PREFIX)) { + /* these keys are reserved. */ + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("key cannot start with \"NM.\"")); + return FALSE; + } + + return TRUE; +} + +/** + * nm_setting_ovs_external_ids_check_val: + * @val: (allow-none): 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.30 + * + * Returns: %TRUE if @val is a valid user data value. + */ +gboolean +nm_setting_ovs_external_ids_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 > (8u * 1024u)) { + 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(nm_str_hash, g_str_equal, g_free, g_free); +} + +GHashTable * +_nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *self) +{ + return NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self)->data; +} + +/** + * nm_setting_ovs_external_ids_get_data_keys: + * @setting: the #NMSettingOvsExternalIDs + * @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_ovs_external_ids_get_data_keys(NMSettingOvsExternalIDs *setting, guint *out_len) +{ + NMSettingOvsExternalIDs * self = setting; + NMSettingOvsExternalIDsPrivate *priv; + + g_return_val_if_fail(NM_IS_SETTING_OVS_EXTERNAL_IDS(self), NULL); + + priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self); + + if (priv->data_keys) { + NM_SET_OUT(out_len, g_hash_table_size(priv->data)); + return priv->data_keys; + } + + priv->data_keys = nm_utils_strdict_get_keys(priv->data, TRUE, out_len); + + /* don't return %NULL, but hijack the @data_keys fields as a pseudo + * empty strv array. */ + return priv->data_keys ?: ((const char **) &priv->data_keys); +} + +/*****************************************************************************/ + +/** + * nm_setting_ovs_external_ids_get_data: + * @setting: the #NMSettingOvsExternalIDs instance + * @key: the external-id to lookup + * + * Since: 1.30 + * + * Returns: (transfer none): the value associated with @key or %NULL if no such + * value exists. + */ +const char * +nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *setting, const char *key) +{ + NMSettingOvsExternalIDs * self = setting; + NMSettingOvsExternalIDsPrivate *priv; + + g_return_val_if_fail(NM_IS_SETTING_OVS_EXTERNAL_IDS(self), NULL); + g_return_val_if_fail(key, NULL); + + priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self); + + if (!priv->data) + return NULL; + + return g_hash_table_lookup(priv->data, key); +} + +/** + * nm_setting_ovs_external_ids_set_data: + * @setting: the #NMSettingOvsExternalIDs instance + * @key: the key to set + * @val: (allow-none): the value to set or %NULL to clear a key. + * + * Since: 1.30 + */ +void +nm_setting_ovs_external_ids_set_data(NMSettingOvsExternalIDs *setting, + const char * key, + const char * val) +{ + NMSettingOvsExternalIDs * self = setting; + NMSettingOvsExternalIDsPrivate *priv; + + g_return_if_fail(NM_IS_SETTING_OVS_EXTERNAL_IDS(self)); + + priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self); + + if (!val) { + if (priv->data && g_hash_table_remove(priv->data, key)) + goto out_changed; + return; + } + + if (priv->data) { + const char *val2; + + if (g_hash_table_lookup_extended(priv->data, key, NULL, (gpointer *) &val2)) { + if (nm_streq(val, val2)) + return; + } + } else + priv->data = _create_data_hash(); + + g_hash_table_insert(priv->data, g_strdup(key), g_strdup(val)); + +out_changed: + nm_clear_g_free(&priv->data_keys); + _notify(self, PROP_DATA); +} + +/*****************************************************************************/ + +static gboolean +verify(NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingOvsExternalIDs * self = NM_SETTING_OVS_EXTERNAL_IDS(setting); + NMSettingOvsExternalIDsPrivate *priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self); + + if (priv->data) { + gs_free_error GError *local = NULL; + GHashTableIter iter; + const char * key; + const char * val; + + g_hash_table_iter_init(&iter, priv->data); + while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) { + if (!nm_setting_ovs_external_ids_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_ovs_external_ids_check_val(val, &local)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + _("invalid value for \"%s\": %s"), + key, + local->message); + } else + continue; + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME, + NM_SETTING_OVS_EXTERNAL_IDS_DATA); + return FALSE; + } + } + + 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_OVS_EXTERNAL_IDS_SETTING_NAME, + NM_SETTING_OVS_EXTERNAL_IDS_DATA); + return FALSE; + } + + if (connection) { + NMSettingConnection *s_con; + const char * type; + const char * slave_type; + + type = nm_connection_get_connection_type(connection); + if (!type) { + NMSetting *s_base; + + s_base = _nm_connection_find_base_type_setting(connection); + if (s_base) + type = nm_setting_get_name(s_base); + } + if (NM_IN_STRSET(type, + NM_SETTING_OVS_BRIDGE_SETTING_NAME, + NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_OVS_INTERFACE_SETTING_NAME)) + goto connection_type_is_good; + + if ((s_con = nm_connection_get_setting_connection(connection)) + && _nm_connection_detect_slave_type_full(s_con, + connection, + &slave_type, + NULL, + NULL, + NULL, + NULL) + && nm_streq0(slave_type, NM_SETTING_OVS_PORT_SETTING_NAME)) + goto connection_type_is_good; + + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("OVS external IDs can only be added to a profile of type OVS " + "bridge/port/interface or to OVS system interface")); + return FALSE; + } +connection_type_is_good: + + return TRUE; +} + +static NMTernary +compare_property(const NMSettInfoSetting *sett_info, + guint property_idx, + NMConnection * con_a, + NMSetting * set_a, + NMConnection * con_b, + NMSetting * set_b, + NMSettingCompareFlags flags) +{ + NMSettingOvsExternalIDsPrivate *priv; + NMSettingOvsExternalIDsPrivate *pri2; + + if (nm_streq(sett_info->property_infos[property_idx].name, NM_SETTING_OVS_EXTERNAL_IDS_DATA)) { + if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_INFERRABLE)) + return NM_TERNARY_DEFAULT; + + if (!set_b) + return TRUE; + + priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(NM_SETTING_OVS_EXTERNAL_IDS(set_a)); + pri2 = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(NM_SETTING_OVS_EXTERNAL_IDS(set_b)); + return nm_utils_hashtable_equal(priv->data, pri2->data, TRUE, g_str_equal); + } + + return NM_SETTING_CLASS(nm_setting_ovs_external_ids_parent_class) + ->compare_property(sett_info, property_idx, con_a, set_a, con_b, set_b, flags); +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMSettingOvsExternalIDs * self = NM_SETTING_OVS_EXTERNAL_IDS(object); + NMSettingOvsExternalIDsPrivate *priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self); + GHashTableIter iter; + GHashTable * data; + const char * key; + const char * 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)); + } + 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) +{ + NMSettingOvsExternalIDs * self = NM_SETTING_OVS_EXTERNAL_IDS(object); + NMSettingOvsExternalIDsPrivate *priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self); + + switch (prop_id) { + case PROP_DATA: + { + gs_unref_hashtable GHashTable *old = NULL; + GHashTableIter iter; + GHashTable * data; + const char * key; + const char * val; + + nm_clear_g_free(&priv->data_keys); + + old = g_steal_pointer(&priv->data); + + data = g_value_get_boxed(value); + if (nm_g_hash_table_size(data) <= 0) + return; + + priv->data = _create_data_hash(); + g_hash_table_iter_init(&iter, data); + while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) + g_hash_table_insert(priv->data, g_strdup(key), g_strdup(val)); + break; + } + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_ovs_external_ids_init(NMSettingOvsExternalIDs *self) +{} + +/** + * nm_setting_ovs_external_ids_new: + * + * Creates a new #NMSettingOvsExternalIDs object with default values. + * + * Returns: (transfer full) (type NMSettingOvsExternalIDs): the new empty + * #NMSettingOvsExternalIDs object + * + * Since: 1.30 + */ +NMSetting * +nm_setting_ovs_external_ids_new(void) +{ + return g_object_new(NM_TYPE_SETTING_OVS_EXTERNAL_IDS, NULL); +} + +static void +finalize(GObject *object) +{ + NMSettingOvsExternalIDs * self = NM_SETTING_OVS_EXTERNAL_IDS(object); + NMSettingOvsExternalIDsPrivate *priv = NM_SETTING_OVS_EXTERNAL_IDS_GET_PRIVATE(self); + + g_free(priv->data_keys); + if (priv->data) + g_hash_table_unref(priv->data); + + G_OBJECT_CLASS(nm_setting_ovs_external_ids_parent_class)->finalize(object); +} + +static void +nm_setting_ovs_external_ids_class_init(NMSettingOvsExternalIDsClass *klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMSettingClass *setting_class = NM_SETTING_CLASS(klass); + GArray * properties_override = _nm_sett_info_property_override_create_array(); + + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->finalize = finalize; + + setting_class->compare_property = compare_property; + setting_class->verify = verify; + + /** + * NMSettingOvsExternalIDs:data: (type GHashTable(utf8,utf8)) + * + * A dictionary of key/value pairs with exernal-ids for OVS. + * + * Since: 1.30 + **/ + obj_properties[PROP_DATA] = g_param_spec_boxed(NM_SETTING_OVS_EXTERNAL_IDS_DATA, + "", + "", + G_TYPE_HASH_TABLE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); + _nm_properties_override_gobj(properties_override, + obj_properties[PROP_DATA], + &nm_sett_info_propert_type_strdict); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit_full(setting_class, + NM_META_SETTING_TYPE_OVS_EXTERNAL_IDS, + NULL, + properties_override); +} diff --git a/libnm-core/nm-setting-ovs-external-ids.h b/libnm-core/nm-setting-ovs-external-ids.h new file mode 100644 index 00000000..906db392 --- /dev/null +++ b/libnm-core/nm-setting-ovs-external-ids.h @@ -0,0 +1,68 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2017 - 2020 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_OVS_EXTERNAL_IDS_H__ +#define __NM_SETTING_OVS_EXTERNAL_IDS_H__ + +#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION) + #error "Only can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_OVS_EXTERNAL_IDS (nm_setting_ovs_external_ids_get_type()) +#define NM_SETTING_OVS_EXTERNAL_IDS(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_OVS_EXTERNAL_IDS, NMSettingOvsExternalIDs)) +#define NM_SETTING_OVS_EXTERNAL_IDS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST((klass), \ + NM_TYPE_SETTING_OVS_EXTERNAL_IDS, \ + NMSettingOvsExternalIDsClass)) +#define NM_IS_SETTING_OVS_EXTERNAL_IDS(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_OVS_EXTERNAL_IDS)) +#define NM_IS_SETTING_OVS_EXTERNAL_IDS_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_OVS_EXTERNAL_IDS)) +#define NM_SETTING_OVS_EXTERNAL_IDS_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), \ + NM_TYPE_SETTING_OVS_EXTERNAL_IDS, \ + NMSettingOvsExternalIDsClass)) + +#define NM_SETTING_OVS_EXTERNAL_IDS_SETTING_NAME "ovs-external-ids" + +#define NM_SETTING_OVS_EXTERNAL_IDS_DATA "data" + +typedef struct _NMSettingOvsExternalIDsClass NMSettingOvsExternalIDsClass; + +NM_AVAILABLE_IN_1_30 +GType nm_setting_ovs_external_ids_get_type(void); + +NM_AVAILABLE_IN_1_30 +NMSetting *nm_setting_ovs_external_ids_new(void); + +/*****************************************************************************/ + +NM_AVAILABLE_IN_1_30 +const char *const *nm_setting_ovs_external_ids_get_data_keys(NMSettingOvsExternalIDs *setting, + guint * out_len); + +NM_AVAILABLE_IN_1_30 +const char *nm_setting_ovs_external_ids_get_data(NMSettingOvsExternalIDs *setting, const char *key); + +NM_AVAILABLE_IN_1_30 +void nm_setting_ovs_external_ids_set_data(NMSettingOvsExternalIDs *setting, + const char * key, + const char * val); + +/*****************************************************************************/ + +NM_AVAILABLE_IN_1_30 +gboolean nm_setting_ovs_external_ids_check_key(const char *key, GError **error); +NM_AVAILABLE_IN_1_30 +gboolean nm_setting_ovs_external_ids_check_val(const char *val, GError **error); + +G_END_DECLS + +#endif /* __NM_SETTING_OVS_EXTERNAL_IDS_H__ */ diff --git a/libnm-core/nm-setting-ovs-interface.c b/libnm-core/nm-setting-ovs-interface.c index 21607889..0c04a66c 100644 --- a/libnm-core/nm-setting-ovs-interface.c +++ b/libnm-core/nm-setting-ovs-interface.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ovs-interface.h" @@ -382,7 +382,7 @@ nm_setting_ovs_interface_init(NMSettingOvsInterface *self) NMSetting * nm_setting_ovs_interface_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_OVS_INTERFACE, NULL); + return g_object_new(NM_TYPE_SETTING_OVS_INTERFACE, NULL); } static void diff --git a/libnm-core/nm-setting-ovs-interface.h b/libnm-core/nm-setting-ovs-interface.h index 40f616bd..47ad5817 100644 --- a/libnm-core/nm-setting-ovs-interface.h +++ b/libnm-core/nm-setting-ovs-interface.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-ovs-patch.c b/libnm-core/nm-setting-ovs-patch.c index 8ea4bbb2..18a62d2e 100644 --- a/libnm-core/nm-setting-ovs-patch.c +++ b/libnm-core/nm-setting-ovs-patch.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ovs-patch.h" @@ -142,7 +142,7 @@ nm_setting_ovs_patch_init(NMSettingOvsPatch *self) NMSetting * nm_setting_ovs_patch_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_OVS_PATCH, NULL); + return g_object_new(NM_TYPE_SETTING_OVS_PATCH, NULL); } static void diff --git a/libnm-core/nm-setting-ovs-patch.h b/libnm-core/nm-setting-ovs-patch.h index a749deac..fd80d45a 100644 --- a/libnm-core/nm-setting-ovs-patch.h +++ b/libnm-core/nm-setting-ovs-patch.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-ovs-port.c b/libnm-core/nm-setting-ovs-port.c index beae8c85..63da66fc 100644 --- a/libnm-core/nm-setting-ovs-port.c +++ b/libnm-core/nm-setting-ovs-port.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ovs-port.h" @@ -343,7 +343,7 @@ nm_setting_ovs_port_init(NMSettingOvsPort *self) NMSetting * nm_setting_ovs_port_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_OVS_PORT, NULL); + return g_object_new(NM_TYPE_SETTING_OVS_PORT, NULL); } static void diff --git a/libnm-core/nm-setting-ovs-port.h b/libnm-core/nm-setting-ovs-port.h index 9d33c3f2..06d3a2aa 100644 --- a/libnm-core/nm-setting-ovs-port.h +++ b/libnm-core/nm-setting-ovs-port.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-ppp.c b/libnm-core/nm-setting-ppp.c index 6c7fa278..36fe84c3 100644 --- a/libnm-core/nm-setting-ppp.c +++ b/libnm-core/nm-setting-ppp.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-ppp.h" @@ -512,7 +512,7 @@ nm_setting_ppp_init(NMSettingPpp *self) NMSetting * nm_setting_ppp_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_PPP, NULL); + return g_object_new(NM_TYPE_SETTING_PPP, NULL); } static void diff --git a/libnm-core/nm-setting-ppp.h b/libnm-core/nm-setting-ppp.h index edaf6009..91c5347f 100644 --- a/libnm-core/nm-setting-ppp.h +++ b/libnm-core/nm-setting-ppp.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2008 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-pppoe.c b/libnm-core/nm-setting-pppoe.c index b86adcc1..ef1d9ba1 100644 --- a/libnm-core/nm-setting-pppoe.c +++ b/libnm-core/nm-setting-pppoe.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-pppoe.h" @@ -254,7 +254,7 @@ nm_setting_pppoe_init(NMSettingPppoe *setting) NMSetting * nm_setting_pppoe_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_PPPOE, NULL); + return g_object_new(NM_TYPE_SETTING_PPPOE, NULL); } static void diff --git a/libnm-core/nm-setting-pppoe.h b/libnm-core/nm-setting-pppoe.h index 4c49db49..0a30f5a1 100644 --- a/libnm-core/nm-setting-pppoe.h +++ b/libnm-core/nm-setting-pppoe.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2011 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-private.h b/libnm-core/nm-setting-private.h index efbfc274..7edb5cb2 100644 --- a/libnm-core/nm-setting-private.h +++ b/libnm-core/nm-setting-private.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 Red Hat, Inc. */ @@ -20,7 +20,6 @@ /*****************************************************************************/ NMSettingPriority _nm_setting_get_base_type_priority(NMSetting *setting); -NMSettingPriority _nm_setting_type_get_base_type_priority(GType type); int _nm_setting_compare_priority(gconstpointer a, gconstpointer b); /*****************************************************************************/ diff --git a/libnm-core/nm-setting-proxy.c b/libnm-core/nm-setting-proxy.c index df91fdd0..10cebc73 100644 --- a/libnm-core/nm-setting-proxy.c +++ b/libnm-core/nm-setting-proxy.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2016 Atul Anand . */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-proxy.h" @@ -262,7 +262,7 @@ nm_setting_proxy_init(NMSettingProxy *self) NMSetting * nm_setting_proxy_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_PROXY, NULL); + return g_object_new(NM_TYPE_SETTING_PROXY, NULL); } static void diff --git a/libnm-core/nm-setting-proxy.h b/libnm-core/nm-setting-proxy.h index 7af13be5..70227df1 100644 --- a/libnm-core/nm-setting-proxy.h +++ b/libnm-core/nm-setting-proxy.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2016 Atul Anand . */ diff --git a/libnm-core/nm-setting-serial.c b/libnm-core/nm-setting-serial.c index 6a0c7792..1e5418a1 100644 --- a/libnm-core/nm-setting-serial.c +++ b/libnm-core/nm-setting-serial.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2018 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-serial.h" @@ -223,7 +223,7 @@ nm_setting_serial_init(NMSettingSerial *self) NMSetting * nm_setting_serial_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_SERIAL, NULL); + return g_object_new(NM_TYPE_SETTING_SERIAL, NULL); } static void diff --git a/libnm-core/nm-setting-serial.h b/libnm-core/nm-setting-serial.h index 0d63afbb..abd232e8 100644 --- a/libnm-core/nm-setting-serial.h +++ b/libnm-core/nm-setting-serial.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2008 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-sriov.c b/libnm-core/nm-setting-sriov.c index 942ef6d4..47625a41 100644 --- a/libnm-core/nm-setting-sriov.c +++ b/libnm-core/nm-setting-sriov.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-sriov.h" @@ -1222,7 +1222,7 @@ nm_setting_sriov_init(NMSettingSriov *setting) NMSetting * nm_setting_sriov_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_SRIOV, NULL); + return g_object_new(NM_TYPE_SETTING_SRIOV, NULL); } static void diff --git a/libnm-core/nm-setting-sriov.h b/libnm-core/nm-setting-sriov.h index 35209513..fe5fc376 100644 --- a/libnm-core/nm-setting-sriov.h +++ b/libnm-core/nm-setting-sriov.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-tc-config.c b/libnm-core/nm-setting-tc-config.c index 0a7c9dae..33df6d34 100644 --- a/libnm-core/nm-setting-tc-config.c +++ b/libnm-core/nm-setting-tc-config.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-tc-config.h" @@ -1778,7 +1778,7 @@ nm_setting_tc_config_init(NMSettingTCConfig *self) NMSetting * nm_setting_tc_config_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_TC_CONFIG, NULL); + return g_object_new(NM_TYPE_SETTING_TC_CONFIG, NULL); } static void diff --git a/libnm-core/nm-setting-tc-config.h b/libnm-core/nm-setting-tc-config.h index 9fe87895..a2bc9a0d 100644 --- a/libnm-core/nm-setting-tc-config.h +++ b/libnm-core/nm-setting-tc-config.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-team-port.c b/libnm-core/nm-setting-team-port.c index 8fff5bdc..ea8115a7 100644 --- a/libnm-core/nm-setting-team-port.c +++ b/libnm-core/nm-setting-team-port.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. * Copyright (C) 2013 Jiri Pirko */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-team-port.h" @@ -503,7 +503,7 @@ nm_setting_team_port_init(NMSettingTeamPort *setting) NMSetting * nm_setting_team_port_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_TEAM_PORT, NULL); + return g_object_new(NM_TYPE_SETTING_TEAM_PORT, NULL); } static void diff --git a/libnm-core/nm-setting-team-port.h b/libnm-core/nm-setting-team-port.h index 34188af9..4d4d9bdc 100644 --- a/libnm-core/nm-setting-team-port.h +++ b/libnm-core/nm-setting-team-port.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2013 Jiri Pirko */ diff --git a/libnm-core/nm-setting-team.c b/libnm-core/nm-setting-team.c index 15776369..f89a3031 100644 --- a/libnm-core/nm-setting-team.c +++ b/libnm-core/nm-setting-team.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. * Copyright (C) 2013 Jiri Pirko */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-team.h" @@ -122,6 +122,8 @@ nm_team_link_watcher_new_ethtool(int delay_up, int delay_down, GError **error) return NULL; } + NM_PRAGMA_WARNING_DISABLE("-Warray-bounds") + watcher = g_malloc(nm_offsetofend(NMTeamLinkWatcher, ethtool)); watcher->ref_count = 1; @@ -129,6 +131,8 @@ nm_team_link_watcher_new_ethtool(int delay_up, int delay_down, GError **error) watcher->ethtool.delay_up = delay_up; watcher->ethtool.delay_down = delay_down; + NM_PRAGMA_WARNING_REENABLE + return watcher; } @@ -1459,7 +1463,7 @@ nm_setting_team_init(NMSettingTeam *setting) NMSetting * nm_setting_team_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_TEAM, NULL); + return g_object_new(NM_TYPE_SETTING_TEAM, NULL); } static void diff --git a/libnm-core/nm-setting-team.h b/libnm-core/nm-setting-team.h index fc10cf25..3f40c8cb 100644 --- a/libnm-core/nm-setting-team.h +++ b/libnm-core/nm-setting-team.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2013 Jiri Pirko */ diff --git a/libnm-core/nm-setting-tun.c b/libnm-core/nm-setting-tun.c index bfe3f9be..1208a62b 100644 --- a/libnm-core/nm-setting-tun.c +++ b/libnm-core/nm-setting-tun.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-tun.h" @@ -266,7 +266,7 @@ nm_setting_tun_init(NMSettingTun *self) NMSetting * nm_setting_tun_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_TUN, NULL); + return g_object_new(NM_TYPE_SETTING_TUN, NULL); } static void diff --git a/libnm-core/nm-setting-tun.h b/libnm-core/nm-setting-tun.h index 2e8544a5..3fbbf082 100644 --- a/libnm-core/nm-setting-tun.h +++ b/libnm-core/nm-setting-tun.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-user.c b/libnm-core/nm-setting-user.c index 3f0e03fb..f62b8bab 100644 --- a/libnm-core/nm-setting-user.c +++ b/libnm-core/nm-setting-user.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-user.h" @@ -288,7 +288,7 @@ nm_setting_user_set_data(NMSettingUser *setting, const char *key, const char *va NMSettingUserPrivate *priv; gboolean changed = FALSE; - g_return_val_if_fail(NM_IS_SETTING(self), FALSE); + g_return_val_if_fail(NM_IS_SETTING_USER(self), FALSE); g_return_val_if_fail(!error || !*error, FALSE); if (!nm_setting_user_check_key(key, error)) @@ -416,11 +416,11 @@ compare_property(const NMSettInfoSetting *sett_info, priv = NM_SETTING_USER_GET_PRIVATE(NM_SETTING_USER(set_a)); pri2 = NM_SETTING_USER_GET_PRIVATE(NM_SETTING_USER(set_b)); - return nm_utils_hash_table_equal(priv->data, pri2->data, TRUE, g_str_equal) - && nm_utils_hash_table_equal(priv->data_invalid, - pri2->data_invalid, - TRUE, - g_str_equal); + return nm_utils_hashtable_equal(priv->data, pri2->data, TRUE, g_str_equal) + && nm_utils_hashtable_equal(priv->data_invalid, + pri2->data_invalid, + TRUE, + g_str_equal); } return NM_SETTING_CLASS(nm_setting_user_parent_class) @@ -523,7 +523,7 @@ nm_setting_user_init(NMSettingUser *self) NMSetting * nm_setting_user_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_USER, NULL); + return g_object_new(NM_TYPE_SETTING_USER, NULL); } static void diff --git a/libnm-core/nm-setting-user.h b/libnm-core/nm-setting-user.h index 5ea34ba4..b151cd3e 100644 --- a/libnm-core/nm-setting-user.h +++ b/libnm-core/nm-setting-user.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2017 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-veth.c b/libnm-core/nm-setting-veth.c new file mode 100644 index 00000000..6270afb3 --- /dev/null +++ b/libnm-core/nm-setting-veth.c @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020 Red Hat, Inc. + */ + +#include "libnm-core/nm-default-libnm-core.h" + +#include "nm-setting-veth.h" + +#include + +#include "nm-utils.h" +#include "nm-setting-connection.h" +#include "nm-setting-private.h" +#include "nm-connection-private.h" + +/** + * SECTION:nm-setting-veth + * @short_description: Describes connection properties for veth interfaces + * + * The #NMSettingVeth object is a #NMSetting subclass that describes properties + * necessary for connection to veth interfaces. + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_PEER, ); + +typedef struct { + char *peer; +} NMSettingVethPrivate; + +/** + * NMSettingVeth: + * + * Veth Settings + */ +struct _NMSettingVeth { + NMSetting parent; + NMSettingVethPrivate _priv; +}; + +struct _NMSettingVethClass { + NMSettingClass parent; +}; + +G_DEFINE_TYPE(NMSettingVeth, nm_setting_veth, NM_TYPE_SETTING) + +#define NM_SETTING_VETH_GET_PRIVATE(self) \ + _NM_GET_PRIVATE(self, NMSettingVeth, NM_IS_SETTING_VETH, NMSetting) + +/*****************************************************************************/ + +/** + * nm_setting_veth_get_peer: + * @setting: the #NMSettingVeth + * + * Returns: the #NMSettingVeth:peer property of the setting + * + * Since: 1.30 + **/ +const char * +nm_setting_veth_get_peer(NMSettingVeth *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_VETH(setting), NULL); + return NM_SETTING_VETH_GET_PRIVATE(setting)->peer; +} + +/*****************************************************************************/ + +static gboolean +verify(NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingVethPrivate *priv = NM_SETTING_VETH_GET_PRIVATE(setting); + + if (!priv->peer) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_MISSING_PROPERTY, + _("property is not specified")); + g_prefix_error(error, "%s.%s: ", NM_SETTING_VETH_SETTING_NAME, NM_SETTING_VETH_PEER); + return FALSE; + } + + if (!nm_utils_ifname_valid(priv->peer, NMU_IFACE_KERNEL, NULL)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid interface name"), + priv->peer); + g_prefix_error(error, "%s.%s: ", NM_SETTING_VETH_SETTING_NAME, NM_SETTING_VETH_PEER); + return FALSE; + } + + if (!_nm_connection_verify_required_interface_name(connection, error)) + return FALSE; + + return TRUE; +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMSettingVeth * setting = NM_SETTING_VETH(object); + NMSettingVethPrivate *priv = NM_SETTING_VETH_GET_PRIVATE(setting); + + switch (prop_id) { + case PROP_PEER: + g_value_set_string(value, priv->peer); + break; + } +} + +static void +set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + NMSettingVeth * setting = NM_SETTING_VETH(object); + NMSettingVethPrivate *priv = NM_SETTING_VETH_GET_PRIVATE(setting); + + switch (prop_id) { + case PROP_PEER: + g_free(priv->peer); + priv->peer = g_value_dup_string(value); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_veth_init(NMSettingVeth *setting) +{} + +/** + * nm_setting_veth_new: + * + * Creates a new #NMSettingVeth object with default values. + * + * Returns: (transfer full): the new empty #NMSettingVeth object + * + * Since: 1.30 + **/ +NMSetting * +nm_setting_veth_new(void) +{ + return g_object_new(NM_TYPE_SETTING_VETH, NULL); +} + +static void +finalize(GObject *object) +{ + NMSettingVeth * setting = NM_SETTING_VETH(object); + NMSettingVethPrivate *priv = NM_SETTING_VETH_GET_PRIVATE(setting); + + g_free(priv->peer); + + G_OBJECT_CLASS(nm_setting_veth_parent_class)->finalize(object); +} + +static void +nm_setting_veth_class_init(NMSettingVethClass *klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMSettingClass *setting_class = NM_SETTING_CLASS(klass); + + g_type_class_add_private(klass, sizeof(NMSettingVethPrivate)); + + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->finalize = finalize; + + setting_class->verify = verify; + + /** + * NMSettingVeth:peer: + * + * This property specifies the peer interface name of the veth. This + * property is mandatory. + * + * Since: 1.30 + **/ + obj_properties[PROP_PEER] = g_param_spec_string(NM_SETTING_VETH_PEER, + "", + "", + NULL, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE + | G_PARAM_STATIC_STRINGS); + + g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); + + _nm_setting_class_commit(setting_class, NM_META_SETTING_TYPE_VETH); +} diff --git a/libnm-core/nm-setting-veth.h b/libnm-core/nm-setting-veth.h new file mode 100644 index 00000000..5dbc1927 --- /dev/null +++ b/libnm-core/nm-setting-veth.h @@ -0,0 +1,41 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2020 Red Hat, Inc. + */ + +#ifndef __NM_SETTING_VETH_H__ +#define __NM_SETTING_VETH_H__ + +#if !defined(__NETWORKMANAGER_H_INSIDE__) && !defined(NETWORKMANAGER_COMPILATION) + #error "Only can be included directly." +#endif + +#include "nm-setting.h" + +G_BEGIN_DECLS + +#define NM_TYPE_SETTING_VETH (nm_setting_veth_get_type()) +#define NM_SETTING_VETH(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST((obj), NM_TYPE_SETTING_VETH, NMSettingVeth)) +#define NM_IS_SETTING_VETH(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NM_TYPE_SETTING_VETH)) +#define NM_IS_SETTING_VETH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), NM_TYPE_SETTING_VETH)) +#define NM_SETTING_VETH_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS((obj), NM_TYPE_SETTING_VETH, NMSettingVethClass)) + +#define NM_SETTING_VETH_SETTING_NAME "veth" + +#define NM_SETTING_VETH_PEER "peer" + +typedef struct _NMSettingVethClass NMSettingVethClass; + +NM_AVAILABLE_IN_1_30 +GType nm_setting_veth_get_type(void); +NM_AVAILABLE_IN_1_30 +NMSetting *nm_setting_veth_new(void); + +NM_AVAILABLE_IN_1_30 +const char *nm_setting_veth_get_peer(NMSettingVeth *setting); + +G_END_DECLS + +#endif /* __NM_SETTING_VETH_H__ */ diff --git a/libnm-core/nm-setting-vlan.c b/libnm-core/nm-setting-vlan.c index 515602e3..123c1191 100644 --- a/libnm-core/nm-setting-vlan.c +++ b/libnm-core/nm-setting-vlan.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 - 2014 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-vlan.h" @@ -803,7 +803,7 @@ nm_setting_vlan_init(NMSettingVlan *self) NMSetting * nm_setting_vlan_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_VLAN, NULL); + return g_object_new(NM_TYPE_SETTING_VLAN, NULL); } static void diff --git a/libnm-core/nm-setting-vlan.h b/libnm-core/nm-setting-vlan.h index 9d2cf3a0..4b2ca429 100644 --- a/libnm-core/nm-setting-vlan.h +++ b/libnm-core/nm-setting-vlan.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 - 2014 Red Hat, Inc. */ @@ -11,7 +11,6 @@ #endif #include "nm-setting.h" -#include G_BEGIN_DECLS diff --git a/libnm-core/nm-setting-vpn.c b/libnm-core/nm-setting-vpn.c index e926c65d..8ee5c2b9 100644 --- a/libnm-core/nm-setting-vpn.c +++ b/libnm-core/nm-setting-vpn.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-vpn.h" @@ -1068,7 +1068,7 @@ nm_setting_vpn_init(NMSettingVpn *setting) NMSetting * nm_setting_vpn_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_VPN, NULL); + return g_object_new(NM_TYPE_SETTING_VPN, NULL); } static void diff --git a/libnm-core/nm-setting-vpn.h b/libnm-core/nm-setting-vpn.h index c9485d45..9e5d6e4b 100644 --- a/libnm-core/nm-setting-vpn.h +++ b/libnm-core/nm-setting-vpn.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2013 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-vrf.c b/libnm-core/nm-setting-vrf.c index 71143659..d4198a7b 100644 --- a/libnm-core/nm-setting-vrf.c +++ b/libnm-core/nm-setting-vrf.c @@ -1,6 +1,6 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-vrf.h" @@ -128,7 +128,7 @@ nm_setting_vrf_init(NMSettingVrf *setting) NMSetting * nm_setting_vrf_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_VRF, NULL); + return g_object_new(NM_TYPE_SETTING_VRF, NULL); } static void diff --git a/libnm-core/nm-setting-vrf.h b/libnm-core/nm-setting-vrf.h index d432f7ef..afa044b8 100644 --- a/libnm-core/nm-setting-vrf.h +++ b/libnm-core/nm-setting-vrf.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ #ifndef __NM_SETTING_VRF_H__ #define __NM_SETTING_VRF_H__ diff --git a/libnm-core/nm-setting-vxlan.c b/libnm-core/nm-setting-vxlan.c index 213219ba..ea8d4546 100644 --- a/libnm-core/nm-setting-vxlan.c +++ b/libnm-core/nm-setting-vxlan.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-vxlan.h" @@ -312,43 +312,36 @@ nm_setting_vxlan_get_l3_miss(NMSettingVxlan *setting) static gboolean verify(NMSetting *setting, NMConnection *connection, GError **error) { - NMSettingVxlanPrivate *priv = NM_SETTING_VXLAN_GET_PRIVATE(setting); - int family = AF_UNSPEC; - - if (!priv->remote) { - g_set_error_literal(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_MISSING_PROPERTY, - _("property is missing")); - g_prefix_error(error, "%s.%s: ", NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_REMOTE); - return FALSE; - } + NMSettingVxlanPrivate *priv = NM_SETTING_VXLAN_GET_PRIVATE(setting); + int addr_family = AF_UNSPEC; + gboolean remote_is_valid = TRUE; + gboolean local_is_valid = TRUE; + + if (priv->remote && !nm_utils_parse_inaddr_bin(addr_family, priv->remote, &addr_family, NULL)) + remote_is_valid = FALSE; + if (priv->local && !nm_utils_parse_inaddr_bin(addr_family, priv->local, &addr_family, NULL)) + local_is_valid = FALSE; - if (nm_utils_ipaddr_is_valid(AF_INET, priv->remote)) - family = AF_INET; - else if (nm_utils_ipaddr_is_valid(AF_INET6, priv->remote)) - family = AF_INET6; - else { + if (!remote_is_valid) { g_set_error(error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("'%s' is not a valid IP address"), - priv->remote); + _("'%s' is not a valid IP%s address"), + priv->remote, + addr_family == AF_UNSPEC ? "" : (addr_family == AF_INET ? "4" : "6")); g_prefix_error(error, "%s.%s: ", NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_REMOTE); return FALSE; } - if (priv->local) { - if (!nm_utils_ipaddr_is_valid(family, priv->local)) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("'%s' is not a valid IP%c address"), - priv->local, - family == AF_INET ? '4' : '6'); - g_prefix_error(error, "%s.%s: ", NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_LOCAL); - return FALSE; - } + if (!local_is_valid) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' is not a valid IP%s address"), + priv->local, + addr_family == AF_UNSPEC ? "" : (addr_family == AF_INET ? "4" : "6")); + g_prefix_error(error, "%s.%s: ", NM_SETTING_VXLAN_SETTING_NAME, NM_SETTING_VXLAN_LOCAL); + return FALSE; } if (priv->parent && !nm_utils_ifname_valid_kernel(priv->parent, NULL) @@ -382,6 +375,19 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) /*****************************************************************************/ +static void +_addrstr_set(char **dst, const char *src) +{ + gs_free char *old = NULL; + + old = *dst; + if (!src) + *dst = NULL; + else if (!nm_utils_parse_inaddr(AF_UNSPEC, src, dst)) + *dst = g_strdup(src); +} +/*****************************************************************************/ + static void get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { @@ -458,12 +464,10 @@ set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *ps priv->id = g_value_get_uint(value); break; case PROP_LOCAL: - g_free(priv->local); - priv->local = g_value_dup_string(value); + _addrstr_set(&priv->local, g_value_get_string(value)); break; case PROP_REMOTE: - g_free(priv->remote); - priv->remote = g_value_dup_string(value); + _addrstr_set(&priv->remote, g_value_get_string(value)); break; case PROP_SOURCE_PORT_MIN: priv->source_port_min = g_value_get_uint(value); @@ -531,7 +535,7 @@ nm_setting_vxlan_init(NMSettingVxlan *self) NMSetting * nm_setting_vxlan_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_VXLAN, NULL); + return g_object_new(NM_TYPE_SETTING_VXLAN, NULL); } static void diff --git a/libnm-core/nm-setting-vxlan.h b/libnm-core/nm-setting-vxlan.h index cbc57224..9b987b66 100644 --- a/libnm-core/nm-setting-vxlan.h +++ b/libnm-core/nm-setting-vxlan.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-wifi-p2p.c b/libnm-core/nm-setting-wifi-p2p.c index daa757bc..e026cb8f 100644 --- a/libnm-core/nm-setting-wifi-p2p.c +++ b/libnm-core/nm-setting-wifi-p2p.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-wifi-p2p.h" diff --git a/libnm-core/nm-setting-wifi-p2p.h b/libnm-core/nm-setting-wifi-p2p.h index 4d151f7c..029b75f0 100644 --- a/libnm-core/nm-setting-wifi-p2p.h +++ b/libnm-core/nm-setting-wifi-p2p.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-wimax.c b/libnm-core/nm-setting-wimax.c index e148a435..dcb59412 100644 --- a/libnm-core/nm-setting-wimax.c +++ b/libnm-core/nm-setting-wimax.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011 - 2013 Red Hat, Inc. * Copyright (C) 2009 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-wimax.h" @@ -183,7 +183,7 @@ nm_setting_wimax_init(NMSettingWimax *setting) NMSetting * nm_setting_wimax_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_WIMAX, NULL); + return g_object_new(NM_TYPE_SETTING_WIMAX, NULL); } static void diff --git a/libnm-core/nm-setting-wimax.h b/libnm-core/nm-setting-wimax.h index b3b36b5b..7279e043 100644 --- a/libnm-core/nm-setting-wimax.h +++ b/libnm-core/nm-setting-wimax.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2009 Novell, Inc. */ diff --git a/libnm-core/nm-setting-wired.c b/libnm-core/nm-setting-wired.c index df922e9e..857f11b1 100644 --- a/libnm-core/nm-setting-wired.c +++ b/libnm-core/nm-setting-wired.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-wired.h" @@ -1174,7 +1174,7 @@ nm_setting_wired_init(NMSettingWired *setting) NMSetting * nm_setting_wired_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_WIRED, NULL); + return g_object_new(NM_TYPE_SETTING_WIRED, NULL); } static void diff --git a/libnm-core/nm-setting-wired.h b/libnm-core/nm-setting-wired.h index 430c7203..acabd706 100644 --- a/libnm-core/nm-setting-wired.h +++ b/libnm-core/nm-setting-wired.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-wireguard.c b/libnm-core/nm-setting-wireguard.c index 07ce6d7e..3a36daba 100644 --- a/libnm-core/nm-setting-wireguard.c +++ b/libnm-core/nm-setting-wireguard.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 - 2019 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-wireguard.h" diff --git a/libnm-core/nm-setting-wireguard.h b/libnm-core/nm-setting-wireguard.h index f512ccd2..3f046fc7 100644 --- a/libnm-core/nm-setting-wireguard.h +++ b/libnm-core/nm-setting-wireguard.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 - 2019 Red Hat, Inc. */ diff --git a/libnm-core/nm-setting-wireless-security.c b/libnm-core/nm-setting-wireless-security.c index 13e7a818..162f9220 100644 --- a/libnm-core/nm-setting-wireless-security.c +++ b/libnm-core/nm-setting-wireless-security.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2017 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-wireless-security.h" @@ -861,8 +861,7 @@ need_secrets(NMSetting *setting) goto no_secrets; } - if ((strcmp(priv->key_mgmt, "ieee8021x") == 0) || (strcmp(priv->key_mgmt, "wpa-eap") == 0) - || (strcmp(priv->key_mgmt, "owe") == 0)) { + if (NM_IN_STRSET(priv->key_mgmt, "ieee8021x", "wpa-eap", "owe", "wpa-eap-suite-b-192")) { /* Let caller check the 802.1x setting for secrets */ goto no_secrets; } @@ -881,11 +880,12 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) { NMSettingWirelessSecurity * self = NM_SETTING_WIRELESS_SECURITY(setting); NMSettingWirelessSecurityPrivate *priv = NM_SETTING_WIRELESS_SECURITY_GET_PRIVATE(self); - const char *valid_key_mgmt[] = {"none", "ieee8021x", "wpa-psk", "wpa-eap", "sae", "owe", NULL}; - const char *valid_auth_algs[] = {"open", "shared", "leap", NULL}; - const char *valid_protos[] = {"wpa", "rsn", NULL}; - const char *valid_pairwise[] = {"tkip", "ccmp", NULL}; - const char *valid_groups[] = {"wep40", "wep104", "tkip", "ccmp", NULL}; + const char * valid_key_mgmt[] = + {"none", "ieee8021x", "wpa-psk", "wpa-eap", "wpa-eap-suite-b-192", "sae", "owe", NULL}; + const char * valid_auth_algs[] = {"open", "shared", "leap", NULL}; + const char * valid_protos[] = {"wpa", "rsn", NULL}; + const char * valid_pairwise[] = {"tkip", "ccmp", NULL}; + const char * valid_groups[] = {"wep40", "wep104", "tkip", "ccmp", NULL}; NMSettingWireless *s_wifi; const char * wifi_mode; @@ -961,8 +961,8 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } } else { - if ((strcmp(priv->key_mgmt, "ieee8021x") == 0) - || (strcmp(priv->key_mgmt, "wpa-eap") == 0)) { + if (nm_streq(priv->key_mgmt, "ieee8021x") || nm_streq(priv->key_mgmt, "wpa-eap") + || nm_streq(priv->key_mgmt, "wpa-eap-suite-b-192")) { /* Need an 802.1x setting too */ if (connection && !nm_connection_get_setting_802_1x(connection)) { g_set_error(error, @@ -1098,13 +1098,19 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) if (NM_IN_SET(priv->pmf, NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL, NM_SETTING_WIRELESS_SECURITY_PMF_REQUIRED) - && !NM_IN_STRSET(priv->key_mgmt, "wpa-eap", "wpa-psk", "sae", "owe")) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("'%s' can only be used with 'wpa-eap', 'wpa-psk' or 'sae' key management "), - priv->pmf == NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL ? "optional" - : "required"); + && !NM_IN_STRSET(priv->key_mgmt, + "wpa-eap", + "wpa-eap-suite-b-192", + "wpa-psk", + "sae", + "owe")) { + g_set_error( + error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' can only be used with 'wpa-eap', 'wpa-eap-suite-b-192', 'wpa-psk' or 'sae' key " + "management "), + priv->pmf == NM_SETTING_WIRELESS_SECURITY_PMF_OPTIONAL ? "optional" : "required"); g_prefix_error(error, "%s.%s: ", NM_SETTING_WIRELESS_SECURITY_SETTING_NAME, @@ -1445,7 +1451,7 @@ nm_setting_wireless_security_init(NMSettingWirelessSecurity *self) NMSetting * nm_setting_wireless_security_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_WIRELESS_SECURITY, NULL); + return g_object_new(NM_TYPE_SETTING_WIRELESS_SECURITY, NULL); } static void @@ -1495,14 +1501,14 @@ nm_setting_wireless_security_class_init(NMSettingWirelessSecurityClass *klass) * * Key management used for the connection. One of "none" (WEP), * "ieee8021x" (Dynamic WEP), "wpa-psk" (infrastructure WPA-PSK), "sae" - * (SAE), "owe" (Opportunistic Wireless Encryption) or "wpa-eap" - * (WPA-Enterprise). This property must be set for - * any Wi-Fi connection that uses security. + * (SAE), "owe" (Opportunistic Wireless Encryption), "wpa-eap" + * (WPA-Enterprise) or "wpa-eap-suite-b-192" (WPA3-Enterprise Suite B). + * This property must be set for any Wi-Fi connection that uses security. **/ /* ---ifcfg-rh--- * property: key-mgmt * variable: KEY_MGMT(+) - * values: IEEE8021X, WPA-PSK, WPA-EAP + * values: IEEE8021X, WPA-PSK, WPA-EAP, WPA-EAP-SUITE-B-192 * description: Key management menthod. * ---end--- */ diff --git a/libnm-core/nm-setting-wireless-security.h b/libnm-core/nm-setting-wireless-security.h index d488077d..62a3c6e5 100644 --- a/libnm-core/nm-setting-wireless-security.h +++ b/libnm-core/nm-setting-wireless-security.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2017 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-wireless.c b/libnm-core/nm-setting-wireless.c index 4dd85b45..232bc7a0 100644 --- a/libnm-core/nm-setting-wireless.c +++ b/libnm-core/nm-setting-wireless.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-wireless.h" @@ -1326,7 +1326,7 @@ nm_setting_wireless_init(NMSettingWireless *setting) NMSetting * nm_setting_wireless_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_WIRELESS, NULL); + return g_object_new(NM_TYPE_SETTING_WIRELESS, NULL); } static void diff --git a/libnm-core/nm-setting-wireless.h b/libnm-core/nm-setting-wireless.h index 3a2d38d0..f97e236c 100644 --- a/libnm-core/nm-setting-wireless.h +++ b/libnm-core/nm-setting-wireless.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-setting-wpan.c b/libnm-core/nm-setting-wpan.c index f9868f59..13bd3684 100644 --- a/libnm-core/nm-setting-wpan.c +++ b/libnm-core/nm-setting-wpan.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Lubomir Rintel */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-wpan.h" @@ -281,7 +281,7 @@ nm_setting_wpan_init(NMSettingWpan *setting) NMSetting * nm_setting_wpan_new(void) { - return (NMSetting *) g_object_new(NM_TYPE_SETTING_WPAN, NULL); + return g_object_new(NM_TYPE_SETTING_WPAN, NULL); } static void diff --git a/libnm-core/nm-setting-wpan.h b/libnm-core/nm-setting-wpan.h index b9078278..2a09d49b 100644 --- a/libnm-core/nm-setting-wpan.h +++ b/libnm-core/nm-setting-wpan.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2018 Lubomir Rintel */ diff --git a/libnm-core/nm-setting.c b/libnm-core/nm-setting.c index 0f621289..45644ac3 100644 --- a/libnm-core/nm-setting.c +++ b/libnm-core/nm-setting.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2011 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting.h" @@ -57,26 +57,6 @@ static GenData *_gendata_hash(NMSetting *setting, gboolean create_if_necessary); /*****************************************************************************/ -static NMSettingPriority -_get_base_type_priority(const NMMetaSettingInfo *setting_info, GType gtype) -{ - /* Historical oddity: PPPoE is a base-type even though it's not - * priority 1. It needs to be sorted *after* lower-level stuff like - * Wi-Fi security or 802.1x for secrets, but it's still allowed as a - * base type. - */ - - if (setting_info) { - if (NM_IN_SET(setting_info->setting_priority, - NM_SETTING_PRIORITY_HW_BASE, - NM_SETTING_PRIORITY_HW_NON_BASE) - || gtype == NM_TYPE_SETTING_PPPOE) - return setting_info->setting_priority; - } - - return NM_SETTING_PRIORITY_INVALID; -} - NMSettingPriority _nm_setting_get_setting_priority(NMSetting *setting) { @@ -88,19 +68,13 @@ _nm_setting_get_setting_priority(NMSetting *setting) return setting_info ? setting_info->setting_priority : NM_SETTING_PRIORITY_INVALID; } -NMSettingPriority -_nm_setting_type_get_base_type_priority(GType type) -{ - return _get_base_type_priority(nm_meta_setting_infos_by_gtype(type), type); -} - NMSettingPriority _nm_setting_get_base_type_priority(NMSetting *setting) { g_return_val_if_fail(NM_IS_SETTING(setting), NM_SETTING_PRIORITY_INVALID); - return _get_base_type_priority(NM_SETTING_GET_CLASS(setting)->setting_info, - G_OBJECT_TYPE(setting)); + return nm_meta_setting_info_get_base_type_priority(NM_SETTING_GET_CLASS(setting)->setting_info, + G_OBJECT_TYPE(setting)); } /** @@ -797,7 +771,7 @@ _nm_setting_new_from_dbus(GType setting_type, * either be ignored or else has a backward-compatibility equivalent * that we do know about. */ - setting = (NMSetting *) g_object_new(setting_type, NULL); + setting = g_object_new(setting_type, NULL); if (NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) { GVariantIter iter; @@ -1481,10 +1455,10 @@ _nm_setting_compare(NMConnection * con_a, GenData *a_gendata = _gendata_hash(a, FALSE); GenData *b_gendata = _gendata_hash(b, FALSE); - return nm_utils_hash_table_equal(a_gendata ? a_gendata->hash : NULL, - b_gendata ? b_gendata->hash : NULL, - TRUE, - g_variant_equal); + return nm_utils_hashtable_equal(a_gendata ? a_gendata->hash : NULL, + b_gendata ? b_gendata->hash : NULL, + TRUE, + g_variant_equal); } for (i = 0; i < sett_info->property_infos_len; i++) { diff --git a/libnm-core/nm-setting.h b/libnm-core/nm-setting.h index 8583c4a7..e5cf753d 100644 --- a/libnm-core/nm-setting.h +++ b/libnm-core/nm-setting.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2011 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. diff --git a/libnm-core/nm-simple-connection.c b/libnm-core/nm-simple-connection.c index 41ba018f..6f1e3a9b 100644 --- a/libnm-core/nm-simple-connection.c +++ b/libnm-core/nm-simple-connection.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2008 Novell, Inc. * Copyright (C) 2007 - 2014 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-simple-connection.h" @@ -44,7 +44,7 @@ nm_simple_connection_init(NMSimpleConnection *self) NMConnection * nm_simple_connection_new(void) { - return (NMConnection *) g_object_new(NM_TYPE_SIMPLE_CONNECTION, NULL); + return g_object_new(NM_TYPE_SIMPLE_CONNECTION, NULL); } /** diff --git a/libnm-core/nm-simple-connection.h b/libnm-core/nm-simple-connection.h index a1cf6827..38473b62 100644 --- a/libnm-core/nm-simple-connection.h +++ b/libnm-core/nm-simple-connection.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2014 Red Hat, Inc. */ diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c index 2f1fba33..b7da35aa 100644 --- a/libnm-core/nm-team-utils.c +++ b/libnm-core/nm-team-utils.c @@ -1,11 +1,11 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019 Red Hat, Inc. */ #define NM_VALUE_TYPE_DEFINE_FUNCTIONS -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-team-utils.h" @@ -524,10 +524,10 @@ _team_attr_data_cmp(const TeamAttrData *attr_data, v_ptrarray_a = *((const GPtrArray *const *) val_a); v_ptrarray_b = *((const GPtrArray *const *) val_b); NM_CMP_RETURN( - _nm_utils_strv_cmp_n(v_ptrarray_a ? (const char *const *) v_ptrarray_a->pdata : NULL, - v_ptrarray_a ? v_ptrarray_a->len : 0u, - v_ptrarray_b ? (const char *const *) v_ptrarray_b->pdata : NULL, - v_ptrarray_b ? v_ptrarray_b->len : 0u)); + nm_utils_strv_cmp_n(v_ptrarray_a ? (const char *const *) v_ptrarray_a->pdata : NULL, + v_ptrarray_a ? v_ptrarray_a->len : 0u, + v_ptrarray_b ? (const char *const *) v_ptrarray_b->pdata : NULL, + v_ptrarray_b ? v_ptrarray_b->len : 0u)); } else nm_assert_not_reached(); return 0; @@ -1136,13 +1136,12 @@ _team_setting_value_master_runner_tx_hash_set_list(NMTeamSetting * self, gboolean changed; guint i; - if (_nm_utils_strv_cmp_n(self->d.master.runner_tx_hash - ? (const char *const *) self->d.master.runner_tx_hash->pdata - : NULL, - self->d.master.runner_tx_hash ? self->d.master.runner_tx_hash->len - : 0u, - arr, - len) + if (nm_utils_strv_cmp_n(self->d.master.runner_tx_hash + ? (const char *const *) self->d.master.runner_tx_hash->pdata + : NULL, + self->d.master.runner_tx_hash ? self->d.master.runner_tx_hash->len : 0u, + arr, + len) == 0) { changed = FALSE; goto out; diff --git a/libnm-core/nm-team-utils.h b/libnm-core/nm-team-utils.h index 9fcde437..77a34e5f 100644 --- a/libnm-core/nm-team-utils.h +++ b/libnm-core/nm-team-utils.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2019 Red Hat, Inc. */ diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h index dc2a6d29..eb545d0f 100644 --- a/libnm-core/nm-utils-private.h +++ b/libnm-core/nm-utils-private.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2005 - 2017 Red Hat, Inc. */ diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index fa65c8a3..6ceef1e4 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -1,20 +1,22 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2005 - 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-utils.h" #include -#include +#include #include +#include #include #include #include #include #include +#include #include "nm-glib-aux/nm-json-aux.h" #include "nm-glib-aux/nm-str-buf.h" @@ -858,7 +860,7 @@ GPtrArray * _nm_utils_copy_array(const GPtrArray *array, NMUtilsCopyFunc copy_func, GDestroyNotify free_func) { GPtrArray *copy; - int i; + guint i; if (!array) return g_ptr_array_new_with_free_func(free_func); @@ -1084,6 +1086,7 @@ nm_utils_ap_mode_security_valid(NMUtilsSecurityType type, NMDeviceWifiCapabiliti case NMU_SEC_DYNAMIC_WEP: case NMU_SEC_WPA_ENTERPRISE: case NMU_SEC_WPA2_ENTERPRISE: + case NMU_SEC_WPA3_SUITE_B_192: return FALSE; case NMU_SEC_INVALID: break; @@ -1257,6 +1260,16 @@ nm_utils_security_valid(NMUtilsSecurityType type, if (!NM_FLAGS_ANY(ap_rsn, NM_802_11_AP_SEC_KEY_MGMT_OWE | NM_802_11_AP_SEC_KEY_MGMT_OWE_TM)) return FALSE; return TRUE; + case NMU_SEC_WPA3_SUITE_B_192: + if (adhoc) + return FALSE; + if (!(wifi_caps & NM_WIFI_DEVICE_CAP_RSN)) + return FALSE; + if (!have_ap) + return TRUE; + if (ap_rsn & NM_802_11_AP_SEC_KEY_MGMT_EAP_SUITE_B_192) + return TRUE; + return FALSE; case NMU_SEC_INVALID: break; } @@ -1276,7 +1289,8 @@ nm_utils_security_valid(NMUtilsSecurityType type, gboolean nm_utils_wep_key_valid(const char *key, NMWepKeyType wep_type) { - int keylen, i; + gsize keylen; + gsize i; if (!key) return FALSE; @@ -1321,7 +1335,8 @@ nm_utils_wep_key_valid(const char *key, NMWepKeyType wep_type) gboolean nm_utils_wpa_psk_valid(const char *psk) { - int psklen, i; + gsize psklen; + gsize i; if (!psk) return FALSE; @@ -1354,7 +1369,7 @@ GVariant * nm_utils_ip4_dns_to_variant(char **dns) { GVariantBuilder builder; - int i; + gsize i; g_variant_builder_init(&builder, G_VARIANT_TYPE("au")); @@ -1385,13 +1400,12 @@ nm_utils_ip4_dns_from_variant(GVariant *value) const guint32 *array; gsize length; char ** dns; - int i; + gsize i; g_return_val_if_fail(g_variant_is_of_type(value, G_VARIANT_TYPE("au")), NULL); array = g_variant_get_fixed_array(value, &length, sizeof(guint32)); - dns = g_new(char *, length + 1); - + dns = g_new(char *, length + 1u); for (i = 0; i < length; i++) dns[i] = nm_utils_inet4_ntop_dup(array[i]); dns[i] = NULL; @@ -1416,7 +1430,7 @@ GVariant * nm_utils_ip4_addresses_to_variant(GPtrArray *addresses, const char *gateway) { GVariantBuilder builder; - int i; + guint i; g_variant_builder_init(&builder, G_VARIANT_TYPE("aau")); @@ -1424,16 +1438,23 @@ nm_utils_ip4_addresses_to_variant(GPtrArray *addresses, const char *gateway) for (i = 0; i < addresses->len; i++) { NMIPAddress *addr = addresses->pdata[i]; guint32 array[3]; + in_addr_t gw; if (nm_ip_address_get_family(addr) != AF_INET) continue; + gw = 0u; + if (gateway) { + in_addr_t a; + + if (inet_pton(AF_INET, gateway, &a) == 1) + gw = a; + gateway = NULL; + } + nm_ip_address_get_address_binary(addr, &array[0]); array[1] = nm_ip_address_get_prefix(addr); - if (i == 0 && gateway) - inet_pton(AF_INET, gateway, &array[2]); - else - array[2] = 0; + array[2] = gw; g_variant_builder_add( &builder, @@ -1519,7 +1540,7 @@ GVariant * nm_utils_ip4_routes_to_variant(GPtrArray *routes) { GVariantBuilder builder; - int i; + guint i; g_variant_builder_init(&builder, G_VARIANT_TYPE("aau")); @@ -1655,28 +1676,26 @@ nm_utils_ip4_get_default_prefix(guint32 ip) * Utility function to convert an array of IP address strings int a #GVariant of * type 'aay' representing an array of IPv6 addresses. * + * If a string cannot be parsed, it will be silently ignored. + * * Returns: (transfer none): a new floating #GVariant representing @dns. **/ GVariant * nm_utils_ip6_dns_to_variant(char **dns) { GVariantBuilder builder; - int i; + gsize i; g_variant_builder_init(&builder, G_VARIANT_TYPE("aay")); - if (dns) { for (i = 0; dns[i]; i++) { struct in6_addr ip; - inet_pton(AF_INET6, dns[i], &ip); - g_variant_builder_add( - &builder, - "@ay", - g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &ip, sizeof(ip), 1)); + if (inet_pton(AF_INET6, dns[i], &ip) != 1) + continue; + g_variant_builder_add(&builder, "@ay", nm_g_variant_new_ay_in6addr(&ip)); } } - return g_variant_builder_end(&builder); } @@ -1697,7 +1716,7 @@ nm_utils_ip6_dns_from_variant(GVariant *value) GVariantIter iter; GVariant * ip_var; char ** dns; - int i; + gsize i; g_return_val_if_fail(g_variant_is_of_type(value, G_VARIANT_TYPE("aay")), NULL); @@ -1737,32 +1756,34 @@ GVariant * nm_utils_ip6_addresses_to_variant(GPtrArray *addresses, const char *gateway) { GVariantBuilder builder; - int i; + guint i; g_variant_builder_init(&builder, G_VARIANT_TYPE("a(ayuay)")); if (addresses) { for (i = 0; i < addresses->len; i++) { - NMIPAddress * addr = addresses->pdata[i]; - struct in6_addr ip_bytes, gateway_bytes; - GVariant * ip_var, *gateway_var; - guint32 prefix; + NMIPAddress * addr = addresses->pdata[i]; + struct in6_addr address_bin; + struct in6_addr gateway_bin_data; + const struct in6_addr *gateway_bin; if (nm_ip_address_get_family(addr) != AF_INET6) continue; - nm_ip_address_get_address_binary(addr, &ip_bytes); - ip_var = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &ip_bytes, 16, 1); - - prefix = nm_ip_address_get_prefix(addr); + nm_ip_address_get_address_binary(addr, &address_bin); - if (i == 0 && gateway) - inet_pton(AF_INET6, gateway, &gateway_bytes); - else - memset(&gateway_bytes, 0, sizeof(gateway_bytes)); - gateway_var = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &gateway_bytes, 16, 1); + gateway_bin = &in6addr_any; + if (gateway) { + if (inet_pton(AF_INET6, gateway, &gateway_bin_data) == 1) + gateway_bin = &gateway_bin_data; + gateway = NULL; + } - g_variant_builder_add(&builder, "(@ayu@ay)", ip_var, prefix, gateway_var); + g_variant_builder_add(&builder, + "(@ayu@ay)", + nm_g_variant_new_ay_in6addr(&address_bin), + (guint32) nm_ip_address_get_prefix(addr), + nm_g_variant_new_ay_in6addr(gateway_bin)); } } @@ -1860,29 +1881,32 @@ GVariant * nm_utils_ip6_routes_to_variant(GPtrArray *routes) { GVariantBuilder builder; - int i; + guint i; g_variant_builder_init(&builder, G_VARIANT_TYPE("a(ayuayu)")); if (routes) { for (i = 0; i < routes->len; i++) { NMIPRoute * route = routes->pdata[i]; - struct in6_addr dest_bytes, next_hop_bytes; - GVariant * dest, *next_hop; - guint32 prefix, metric; + struct in6_addr dest_bytes; + struct in6_addr next_hop_bytes; + guint32 metric; if (nm_ip_route_get_family(route) != AF_INET6) continue; nm_ip_route_get_dest_binary(route, &dest_bytes); - dest = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &dest_bytes, 16, 1); - prefix = nm_ip_route_get_prefix(route); nm_ip_route_get_next_hop_binary(route, &next_hop_bytes); - next_hop = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &next_hop_bytes, 16, 1); - /* The old routes format uses "0" for default, not "-1" */ - metric = MAX(0, nm_ip_route_get_metric(route)); - g_variant_builder_add(&builder, "(@ayu@ayu)", dest, prefix, next_hop, metric); + /* The old routes format uses "0" for default, not "-1" */ + metric = NM_MAX(0, nm_ip_route_get_metric(route)); + + g_variant_builder_add(&builder, + "(@ayu@ayu)", + nm_g_variant_new_ay_in6addr(&dest_bytes), + (guint32) nm_ip_route_get_prefix(route), + nm_g_variant_new_ay_in6addr(&next_hop_bytes), + metric); } } @@ -2088,7 +2112,7 @@ GVariant * nm_utils_ip_routes_to_variant(GPtrArray *routes) { GVariantBuilder builder; - int i; + guint i; g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); @@ -3147,7 +3171,7 @@ nm_utils_uuid_is_null(const NMUuid *uuid) if (!uuid) return TRUE; - for (i = 0; i < G_N_ELEMENTS(uuid->uuid); i++) { + for (i = 0; i < (int) G_N_ELEMENTS(uuid->uuid); i++) { if (uuid->uuid[i]) return FALSE; } @@ -3334,7 +3358,7 @@ static gboolean file_has_extension(const char *filename, const char *extensions[]) { const char *ext; - int i; + gsize i; ext = strrchr(filename, '.'); if (!ext) @@ -3599,7 +3623,8 @@ nm_utils_file_search_in_paths(const char * progname, if (!path[0]) continue; - nm_str_buf_reset(&strbuf, path); + nm_str_buf_reset(&strbuf); + nm_str_buf_append(&strbuf, path); nm_str_buf_ensure_trailing_c(&strbuf, '/'); s = nm_str_buf_append0(&strbuf, progname); @@ -3833,7 +3858,7 @@ nm_utils_wifi_is_channel_valid(guint32 channel, const char *band) G_STATIC_ASSERT(G_N_ELEMENTS(table) > 0); \ G_STATIC_ASSERT(G_N_ELEMENTS(table) == G_N_ELEMENTS(table_freqs)); \ \ - for (i = 0; i < G_N_ELEMENTS(table); i++) { \ + for (i = 0; i < (int) G_N_ELEMENTS(table); i++) { \ nm_assert((i == G_N_ELEMENTS(table) - 1) == (table[i].chan == 0)); \ nm_assert((i == G_N_ELEMENTS(table) - 1) == (table[i].freq == 0)); \ nm_assert(table[i].freq == table_freqs[i]); \ @@ -3971,16 +3996,13 @@ GByteArray * nm_utils_hwaddr_atoba(const char *asc, gsize length) { GByteArray *ba; - gsize l; g_return_val_if_fail(asc, NULL); g_return_val_if_fail(length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL); ba = g_byte_array_sized_new(length); g_byte_array_set_size(ba, length); - if (!_nm_utils_hwaddr_aton(asc, ba->data, length, &l)) - goto fail; - if (length != l) + if (!_nm_utils_hwaddr_aton_exact(asc, ba->data, length)) goto fail; return ba; @@ -4005,17 +4027,11 @@ fail: guint8 * nm_utils_hwaddr_aton(const char *asc, gpointer buffer, gsize length) { - gsize l; - g_return_val_if_fail(asc, NULL); g_return_val_if_fail(buffer, NULL); g_return_val_if_fail(length > 0 && length <= NM_UTILS_HWADDR_LEN_MAX, NULL); - if (!_nm_utils_hwaddr_aton(asc, buffer, length, &l)) - return NULL; - if (length != l) - return NULL; - return buffer; + return _nm_utils_hwaddr_aton_exact(asc, buffer, length); } /** @@ -4942,20 +4958,7 @@ nm_utils_check_virtual_device_compatibility(GType virtual_type, GType other_type } } -typedef struct { - const char *str; - const char *num; -} BondMode; - -static const BondMode bond_mode_table[] = { - [0] = {"balance-rr", "0"}, - [1] = {"active-backup", "1"}, - [2] = {"balance-xor", "2"}, - [3] = {"broadcast", "3"}, - [4] = {"802.3ad", "4"}, - [5] = {"balance-tlb", "5"}, - [6] = {"balance-alb", "6"}, -}; +/*****************************************************************************/ /** * nm_utils_bond_mode_int_to_string: @@ -4972,9 +4975,7 @@ static const BondMode bond_mode_table[] = { const char * nm_utils_bond_mode_int_to_string(int mode) { - if (mode >= 0 && mode < G_N_ELEMENTS(bond_mode_table)) - return bond_mode_table[mode].str; - return NULL; + return _nm_setting_bond_mode_to_string(mode); } /** @@ -4993,16 +4994,7 @@ nm_utils_bond_mode_int_to_string(int mode) int nm_utils_bond_mode_string_to_int(const char *mode) { - int i; - - if (!mode || !*mode) - return -1; - - for (i = 0; i < G_N_ELEMENTS(bond_mode_table); i++) { - if (NM_IN_STRSET(mode, bond_mode_table[i].str, bond_mode_table[i].num)) - return i; - } - return -1; + return _nm_setting_bond_mode_from_string(mode); } /*****************************************************************************/ @@ -5739,7 +5731,7 @@ NM_UTILS_FLAGS2STR_DEFINE(nm_bluetooth_capability_to_string, NMBluetoothCapabilities, NM_UTILS_FLAGS2STR(NM_BT_CAPABILITY_NONE, "NONE"), NM_UTILS_FLAGS2STR(NM_BT_CAPABILITY_DUN, "DUN"), - NM_UTILS_FLAGS2STR(NM_BT_CAPABILITY_NAP, "NAP"), ) + NM_UTILS_FLAGS2STR(NM_BT_CAPABILITY_NAP, "NAP"), ); /*****************************************************************************/ diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h index 9589c514..0f8dcda0 100644 --- a/libnm-core/nm-utils.h +++ b/libnm-core/nm-utils.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2005 - 2017 Red Hat, Inc. */ @@ -12,12 +12,6 @@ #include -#include - -/* For ETH_ALEN and INFINIBAND_ALEN */ -#include -#include - #include "nm-core-enum-types.h" #include "nm-setting-sriov.h" #include "nm-setting-tc-config.h" @@ -54,6 +48,7 @@ char * nm_utils_ssid_to_utf8(const guint8 *ssid, gsize len); * @NMU_SEC_WPA2_ENTERPRISE: WPA2 is used with 802.1x authentication * @NMU_SEC_SAE: is used with WPA3 Enterprise * @NMU_SEC_OWE: is used with Enhanced Open + * @NMU_SEC_WPA3_SUITE_B_192: is used with WPA3 Enterprise Suite-B 192 bit mode. Since: 1.30. * * Describes generic security mechanisms that 802.11 access points may offer. * Used with nm_utils_security_valid() for checking whether a given access @@ -71,6 +66,7 @@ typedef enum { NMU_SEC_WPA2_ENTERPRISE, NMU_SEC_SAE, NMU_SEC_OWE, + NMU_SEC_WPA3_SUITE_B_192, } NMUtilsSecurityType; gboolean nm_utils_security_valid(NMUtilsSecurityType type, @@ -185,7 +181,10 @@ gboolean nm_utils_is_uuid(const char *str); * for both nm_utils_inet4_ntop() and nm_utils_inet6_ntop(). **/ #define NM_UTILS_INET_ADDRSTRLEN INET6_ADDRSTRLEN -const char *nm_utils_inet4_ntop(in_addr_t inaddr, char *dst); + +const char *nm_utils_inet4_ntop(guint32 inaddr, char *dst); + +struct in6_addr; const char *nm_utils_inet6_ntop(const struct in6_addr *in6addr, char *dst); gboolean nm_utils_ipaddr_valid(int family, const char *ip); diff --git a/libnm-core/nm-version-macros.h b/libnm-core/nm-version-macros.h new file mode 100644 index 00000000..8ed5bb72 --- /dev/null +++ b/libnm-core/nm-version-macros.h @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2011, 2015 Red Hat, Inc. + */ + +#ifndef __NM_VERSION_MACROS_H__ +#define __NM_VERSION_MACROS_H__ + +/* This header must not include glib or libnm. */ + +/** + * NM_MAJOR_VERSION: + * + * Evaluates to the major version number of NetworkManager which this source + * is compiled against. + */ +#define NM_MAJOR_VERSION (1) + +/** + * NM_MINOR_VERSION: + * + * Evaluates to the minor version number of NetworkManager which this source + * is compiled against. + */ +#define NM_MINOR_VERSION (29) + +/** + * NM_MICRO_VERSION: + * + * Evaluates to the micro version number of NetworkManager which this source + * compiled against. + */ +#define NM_MICRO_VERSION (90) + +/** + * NM_CHECK_VERSION: + * @major: major version (e.g. 1 for version 1.2.5) + * @minor: minor version (e.g. 2 for version 1.2.5) + * @micro: micro version (e.g. 5 for version 1.2.5) + * + * Returns: %TRUE if the version of the NetworkManager header files + * is the same as or newer than the passed-in version. + */ +#define NM_CHECK_VERSION(major,minor,micro) \ + (NM_MAJOR_VERSION > (major) || \ + (NM_MAJOR_VERSION == (major) && NM_MINOR_VERSION > (minor)) || \ + (NM_MAJOR_VERSION == (major) && NM_MINOR_VERSION == (minor) && NM_MICRO_VERSION >= (micro))) + + +#define NM_ENCODE_VERSION(major,minor,micro) ((major) << 16 | (minor) << 8 | (micro)) + +#define NM_VERSION_0_9_8 (NM_ENCODE_VERSION (0, 9, 8)) +#define NM_VERSION_0_9_10 (NM_ENCODE_VERSION (0, 9, 10)) +#define NM_VERSION_1_0 (NM_ENCODE_VERSION (1, 0, 0)) +#define NM_VERSION_1_2 (NM_ENCODE_VERSION (1, 2, 0)) +#define NM_VERSION_1_4 (NM_ENCODE_VERSION (1, 4, 0)) +#define NM_VERSION_1_6 (NM_ENCODE_VERSION (1, 6, 0)) +#define NM_VERSION_1_8 (NM_ENCODE_VERSION (1, 8, 0)) +#define NM_VERSION_1_10 (NM_ENCODE_VERSION (1, 10, 0)) +#define NM_VERSION_1_12 (NM_ENCODE_VERSION (1, 12, 0)) +#define NM_VERSION_1_14 (NM_ENCODE_VERSION (1, 14, 0)) +#define NM_VERSION_1_16 (NM_ENCODE_VERSION (1, 16, 0)) +#define NM_VERSION_1_18 (NM_ENCODE_VERSION (1, 18, 0)) +#define NM_VERSION_1_20 (NM_ENCODE_VERSION (1, 20, 0)) +#define NM_VERSION_1_22 (NM_ENCODE_VERSION (1, 22, 0)) +#define NM_VERSION_1_24 (NM_ENCODE_VERSION (1, 24, 0)) +#define NM_VERSION_1_26 (NM_ENCODE_VERSION (1, 26, 0)) +#define NM_VERSION_1_28 (NM_ENCODE_VERSION (1, 28, 0)) +#define NM_VERSION_1_30 (NM_ENCODE_VERSION (1, 30, 0)) + +/* For releases, NM_API_VERSION is equal to NM_VERSION. + * + * For development builds, NM_API_VERSION is the next + * stable API after NM_VERSION. When you run a development + * version, you are already using the future API, even if + * it is not yet release. Hence, the currently used API + * version is the future one. */ +#define NM_API_VERSION \ + (((NM_MINOR_VERSION % 2) == 1) \ + ? NM_ENCODE_VERSION (NM_MAJOR_VERSION, NM_MINOR_VERSION + 1, 0 ) \ + : NM_ENCODE_VERSION (NM_MAJOR_VERSION, NM_MINOR_VERSION , ((NM_MICRO_VERSION + 1) / 2) * 2)) + +/* deprecated. */ +#define NM_VERSION_CUR_STABLE NM_API_VERSION + +/* deprecated. */ +#define NM_VERSION_NEXT_STABLE NM_API_VERSION + +#define NM_VERSION NM_ENCODE_VERSION (NM_MAJOR_VERSION, NM_MINOR_VERSION, NM_MICRO_VERSION) + +#endif /* __NM_VERSION_MACROS_H__ */ diff --git a/libnm-core/nm-version-macros.h.in b/libnm-core/nm-version-macros.h.in new file mode 100644 index 00000000..4a6f46e9 --- /dev/null +++ b/libnm-core/nm-version-macros.h.in @@ -0,0 +1,91 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2011, 2015 Red Hat, Inc. + */ + +#ifndef __NM_VERSION_MACROS_H__ +#define __NM_VERSION_MACROS_H__ + +/* This header must not include glib or libnm. */ + +/** + * NM_MAJOR_VERSION: + * + * Evaluates to the major version number of NetworkManager which this source + * is compiled against. + */ +#define NM_MAJOR_VERSION (@NM_MAJOR_VERSION@) + +/** + * NM_MINOR_VERSION: + * + * Evaluates to the minor version number of NetworkManager which this source + * is compiled against. + */ +#define NM_MINOR_VERSION (@NM_MINOR_VERSION@) + +/** + * NM_MICRO_VERSION: + * + * Evaluates to the micro version number of NetworkManager which this source + * compiled against. + */ +#define NM_MICRO_VERSION (@NM_MICRO_VERSION@) + +/** + * NM_CHECK_VERSION: + * @major: major version (e.g. 1 for version 1.2.5) + * @minor: minor version (e.g. 2 for version 1.2.5) + * @micro: micro version (e.g. 5 for version 1.2.5) + * + * Returns: %TRUE if the version of the NetworkManager header files + * is the same as or newer than the passed-in version. + */ +#define NM_CHECK_VERSION(major,minor,micro) \ + (NM_MAJOR_VERSION > (major) || \ + (NM_MAJOR_VERSION == (major) && NM_MINOR_VERSION > (minor)) || \ + (NM_MAJOR_VERSION == (major) && NM_MINOR_VERSION == (minor) && NM_MICRO_VERSION >= (micro))) + + +#define NM_ENCODE_VERSION(major,minor,micro) ((major) << 16 | (minor) << 8 | (micro)) + +#define NM_VERSION_0_9_8 (NM_ENCODE_VERSION (0, 9, 8)) +#define NM_VERSION_0_9_10 (NM_ENCODE_VERSION (0, 9, 10)) +#define NM_VERSION_1_0 (NM_ENCODE_VERSION (1, 0, 0)) +#define NM_VERSION_1_2 (NM_ENCODE_VERSION (1, 2, 0)) +#define NM_VERSION_1_4 (NM_ENCODE_VERSION (1, 4, 0)) +#define NM_VERSION_1_6 (NM_ENCODE_VERSION (1, 6, 0)) +#define NM_VERSION_1_8 (NM_ENCODE_VERSION (1, 8, 0)) +#define NM_VERSION_1_10 (NM_ENCODE_VERSION (1, 10, 0)) +#define NM_VERSION_1_12 (NM_ENCODE_VERSION (1, 12, 0)) +#define NM_VERSION_1_14 (NM_ENCODE_VERSION (1, 14, 0)) +#define NM_VERSION_1_16 (NM_ENCODE_VERSION (1, 16, 0)) +#define NM_VERSION_1_18 (NM_ENCODE_VERSION (1, 18, 0)) +#define NM_VERSION_1_20 (NM_ENCODE_VERSION (1, 20, 0)) +#define NM_VERSION_1_22 (NM_ENCODE_VERSION (1, 22, 0)) +#define NM_VERSION_1_24 (NM_ENCODE_VERSION (1, 24, 0)) +#define NM_VERSION_1_26 (NM_ENCODE_VERSION (1, 26, 0)) +#define NM_VERSION_1_28 (NM_ENCODE_VERSION (1, 28, 0)) +#define NM_VERSION_1_30 (NM_ENCODE_VERSION (1, 30, 0)) + +/* For releases, NM_API_VERSION is equal to NM_VERSION. + * + * For development builds, NM_API_VERSION is the next + * stable API after NM_VERSION. When you run a development + * version, you are already using the future API, even if + * it is not yet release. Hence, the currently used API + * version is the future one. */ +#define NM_API_VERSION \ + (((NM_MINOR_VERSION % 2) == 1) \ + ? NM_ENCODE_VERSION (NM_MAJOR_VERSION, NM_MINOR_VERSION + 1, 0 ) \ + : NM_ENCODE_VERSION (NM_MAJOR_VERSION, NM_MINOR_VERSION , ((NM_MICRO_VERSION + 1) / 2) * 2)) + +/* deprecated. */ +#define NM_VERSION_CUR_STABLE NM_API_VERSION + +/* deprecated. */ +#define NM_VERSION_NEXT_STABLE NM_API_VERSION + +#define NM_VERSION NM_ENCODE_VERSION (NM_MAJOR_VERSION, NM_MINOR_VERSION, NM_MICRO_VERSION) + +#endif /* __NM_VERSION_MACROS_H__ */ diff --git a/libnm-core/nm-version.h b/libnm-core/nm-version.h index 1fbcf5ab..3f1ad3f2 100644 --- a/libnm-core/nm-version.h +++ b/libnm-core/nm-version.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2011, 2015 Red Hat, Inc. */ @@ -257,6 +257,20 @@ #define NM_AVAILABLE_IN_1_28 #endif +#if NM_VERSION_MIN_REQUIRED >= NM_VERSION_1_30 + #define NM_DEPRECATED_IN_1_30 G_DEPRECATED + #define NM_DEPRECATED_IN_1_30_FOR(f) G_DEPRECATED_FOR(f) +#else + #define NM_DEPRECATED_IN_1_30 + #define NM_DEPRECATED_IN_1_30_FOR(f) +#endif + +#if NM_VERSION_MAX_ALLOWED < NM_VERSION_1_30 + #define NM_AVAILABLE_IN_1_30 G_UNAVAILABLE(1, 30) +#else + #define NM_AVAILABLE_IN_1_30 +#endif + /* * Synchronous API for calling D-Bus in libnm is deprecated. See * https://developer.gnome.org/libnm/stable/usage.html#sync-api diff --git a/libnm-core/nm-vpn-dbus-interface.h b/libnm-core/nm-vpn-dbus-interface.h index fc72c4fa..c0e23f6f 100644 --- a/libnm-core/nm-vpn-dbus-interface.h +++ b/libnm-core/nm-vpn-dbus-interface.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2004 Red Hat, Inc. */ @@ -141,26 +141,18 @@ typedef enum { */ NM_DEPRECATED_IN_1_8_FOR(NMActiveConnectionStateReason) typedef enum { - 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, + NM_VPN_CONNECTION_STATE_REASON_UNKNOWN = 0, + NM_VPN_CONNECTION_STATE_REASON_NONE = 1, + NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED = 2, + NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED = 3, + NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED = 4, + NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID = 5, + NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT = 6, + NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT = 7, + NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED = 8, + NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS = 9, + NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED = 10, + NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED = 11, } NMVpnConnectionStateReason; /** diff --git a/libnm-core/nm-vpn-dbus-types.xml b/libnm-core/nm-vpn-dbus-types.xml index 571b437e..5da02420 100644 --- a/libnm-core/nm-vpn-dbus-types.xml +++ b/libnm-core/nm-vpn-dbus-types.xml @@ -144,62 +144,62 @@ NM_VPN_CONNECTION_STATE_REASON_UNKNOWN - = NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN + = 0 The reason for the VPN connection state change is unknown. NM_VPN_CONNECTION_STATE_REASON_NONE - = NM_ACTIVE_CONNECTION_STATE_REASON_NONE + = 1 No reason was given for the VPN connection state change. NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED - = NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED + = 2 The VPN connection changed state because the user disconnected it. NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED - = NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED + = 3 The VPN connection changed state because the device it was using was disconnected. NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED - = NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED + = 4 The service providing the VPN connection was stopped. NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID - = NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID + = 5 The IP config of the VPN connection was invalid. NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT - = NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT + = 6 The connection attempt to the VPN service timed out. NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT - = NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT + = 7 A timeout occurred while starting the service providing the VPN connection. NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED - = NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED + = 8 Starting the service starting the service providing the VPN connection failed. NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS - = NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS + = 9 Necessary secrets for the VPN connection were not provided. NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED - = NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED + = 10 Authentication to the VPN server failed. NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED - = NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED + = 11 The connection was deleted from settings. diff --git a/libnm-core/nm-vpn-editor-plugin.c b/libnm-core/nm-vpn-editor-plugin.c index 1f389fd2..e68bdc24 100644 --- a/libnm-core/nm-vpn-editor-plugin.c +++ b/libnm-core/nm-vpn-editor-plugin.c @@ -1,11 +1,11 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2008 Novell, Inc. * Copyright (C) 2008 - 2010 Red Hat, Inc. * Copyright (C) 2015 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-vpn-editor-plugin.h" diff --git a/libnm-core/nm-vpn-editor-plugin.h b/libnm-core/nm-vpn-editor-plugin.h index a21ac2fa..e318da07 100644 --- a/libnm-core/nm-vpn-editor-plugin.h +++ b/libnm-core/nm-vpn-editor-plugin.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2008 Novell, Inc. * Copyright (C) 2008 - 2015 Red Hat, Inc. diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c index 977be284..cb739510 100644 --- a/libnm-core/nm-vpn-plugin-info.c +++ b/libnm-core/nm-vpn-plugin-info.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-vpn-plugin-info.h" diff --git a/libnm-core/nm-vpn-plugin-info.h b/libnm-core/nm-vpn-plugin-info.h index 18b5c5ff..1e9870c8 100644 --- a/libnm-core/nm-vpn-plugin-info.h +++ b/libnm-core/nm-vpn-plugin-info.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ diff --git a/libnm-core/tests/meson.build b/libnm-core/tests/meson.build index 4ce42526..df5209b4 100644 --- a/libnm-core/tests/meson.build +++ b/libnm-core/tests/meson.build @@ -1,36 +1,12 @@ -# SPDX-License-Identifier: LGPL-2.1+ - -# test-cert.p12 created with: -# -# openssl pkcs12 -export \ -# -in test_key_and_cert.pem \ -# -inkey test_key_and_cert.pem \ -# -certfile test_ca_cert.pem \ -# -name "test-pkcs12" \ -# -out test-cert.p12 - -enum_types = 'nm-core-tests-enum-types' +# SPDX-License-Identifier: LGPL-2.1-or-later enum_sources = gnome.mkenums_simple( - enum_types, + 'nm-core-tests-enum-types', sources: 'test-general-enums.h', identifier_prefix: nm_id_prefix, - body_prefix: '#include "nm-default.h"', + body_prefix: '#include "libnm-core/nm-default-libnm-core.h"', ) -deps = [ - libnm_keyfile_dep, - libnm_core_dep, - libnm_core_nm_default_dep, -] - -c_flags = [ - '-DNETWORKMANAGER_COMPILATION_TEST', - '-DNETWORKMANAGER_COMPILATION=NM_NETWORKMANAGER_COMPILATION_LIBNM_CORE', -] - -test_cert_dir = join_paths(meson.current_source_dir(), 'certs') - test_units = [ 'test-compare', 'test-crypto', @@ -45,8 +21,14 @@ foreach test_unit: test_units exe = executable( 'libnm-core-' + test_unit, [test_unit + '.c'] + enum_sources, - dependencies: deps, - c_args: c_flags, + dependencies: [ + libnm_core_dep, + libnm_core_nm_default_dep, + libnm_base_dep, + ], + c_args: [ + '-DG_LOG_DOMAIN="test"', + ], link_with: libnm_systemd_logging_stub, ) diff --git a/libnm-core/tests/test-compare.c b/libnm-core/tests/test-compare.c index e8c3ec33..27049e87 100644 --- a/libnm-core/tests/test-compare.c +++ b/libnm-core/tests/test-compare.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2007 - 2014 Red Hat, Inc. * Copyright (C) 2007 - 2008 Novell, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include #include diff --git a/libnm-core/tests/test-crypto.c b/libnm-core/tests/test-crypto.c index a8af7f84..4e288b7b 100644 --- a/libnm-core/tests/test-crypto.c +++ b/libnm-core/tests/test-crypto.c @@ -1,10 +1,10 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Dan Williams * Copyright (C) 2007 - 2011 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include #include diff --git a/libnm-core/tests/test-general-enums.h b/libnm-core/tests/test-general-enums.h index 29b8823c..b3163e23 100644 --- a/libnm-core/tests/test-general-enums.h +++ b/libnm-core/tests/test-general-enums.h @@ -1,4 +1,4 @@ -/* SPDX-License-Identifier: LGPL-2.1+ */ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index 65717144..885319fc 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -1,20 +1,23 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2008 - 2018 Red Hat, Inc. */ #define NM_GLIB_COMPAT_H_TEST -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include #include #include +#include +#include #include "nm-std-aux/c-list-util.h" #include "nm-glib-aux/nm-enum-utils.h" #include "nm-glib-aux/nm-str-buf.h" #include "nm-glib-aux/nm-json-aux.h" +#include "nm-base/nm-base.h" #include "systemd/nm-sd-utils-shared.h" #include "nm-utils.h" @@ -54,9 +57,10 @@ #include "nm-setting-wireless-security.h" #include "nm-setting-wpan.h" #include "nm-simple-connection.h" -#include "nm-keyfile/nm-keyfile-internal.h" +#include "nm-keyfile-internal.h" #include "nm-glib-aux/nm-dedup-multi.h" -#include "nm-libnm-core-intern/nm-ethtool-utils.h" +#include "nm-base/nm-ethtool-base.h" +#include "nm-base/nm-ethtool-utils-base.h" #include "test-general-enums.h" @@ -72,6 +76,12 @@ G_STATIC_ASSERT(sizeof(bool) <= sizeof(int)); /*****************************************************************************/ +/* NM_UTILS_HWADDR_LEN_MAX is public API of libnm(-core) and _NM_UTILS_HWADDR_LEN_MAX + * is internal API. They are the same, but the latter can be used without including libnm-core. */ +G_STATIC_ASSERT(NM_UTILS_HWADDR_LEN_MAX == _NM_UTILS_HWADDR_LEN_MAX); + +/*****************************************************************************/ + static void test_nm_ascii_spaces(void) { @@ -95,6 +105,57 @@ test_nm_ascii_spaces(void) /*****************************************************************************/ +static void +test_wired_wake_on_lan_enum(void) +{ + nm_auto_unref_gtypeclass GFlagsClass *flags_class = NULL; + gs_unref_hashtable GHashTable *vals = g_hash_table_new(nm_direct_hash, NULL); + guint i; + + G_STATIC_ASSERT_EXPR(sizeof(NMSettingWiredWakeOnLan) == sizeof(_NMSettingWiredWakeOnLan)); + G_STATIC_ASSERT_EXPR(sizeof(NMSettingWiredWakeOnLan) < sizeof(gint64)); + + G_STATIC_ASSERT_EXPR(sizeof(NMSettingWiredWakeOnLan) < sizeof(gint64)); + g_assert((((gint64)((NMSettingWiredWakeOnLan) -1)) < 0) + == (((gint64)((_NMSettingWiredWakeOnLan) -1)) < 0)); + +#define _E(n) \ + G_STMT_START \ + { \ + G_STATIC_ASSERT_EXPR(n == (gint64) _##n); \ + G_STATIC_ASSERT_EXPR(_##n == (gint64) n); \ + g_assert(_##n == _NM_SETTING_WIRED_WAKE_ON_LAN_CAST(n)); \ + if (!g_hash_table_add(vals, GUINT_TO_POINTER(n))) \ + g_assert_not_reached(); \ + } \ + G_STMT_END + _E(NM_SETTING_WIRED_WAKE_ON_LAN_NONE); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_PHY); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_UNICAST); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_MULTICAST); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_BROADCAST); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_ARP); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_MAGIC); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_ALL); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_DEFAULT); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_IGNORE); + _E(NM_SETTING_WIRED_WAKE_ON_LAN_EXCLUSIVE_FLAGS); +#undef _E + + flags_class = G_FLAGS_CLASS(g_type_class_ref(NM_TYPE_SETTING_WIRED_WAKE_ON_LAN)); + for (i = 0; i < flags_class->n_values; i++) { + const GFlagsValue *value = &flags_class->values[i]; + + if (!g_hash_table_contains(vals, GUINT_TO_POINTER(value->value))) { + g_error("The enum value %s from NMSettingWiredWakeOnLan is not checked for " + "_NMSettingWiredWakeOnLan", + value->value_name); + } + } +} + +/*****************************************************************************/ + typedef struct _nm_packed { int v0; char v1; @@ -330,7 +391,7 @@ _do_test_nm_utils_strsplit_set_f_one(NMUtilsStrsplitSetFlags flags, } g_assert(words_g[words_len] == NULL); g_assert_cmpint(NM_PTRARRAY_LEN(words_g), ==, words_len); - g_assert(_nm_utils_strv_cmp_n(exp_words, words_len, NM_CAST_STRV_CC(words_g), -1) == 0); + g_assert(nm_utils_strv_cmp_n(exp_words, words_len, words_g, -1) == 0); } } @@ -354,7 +415,7 @@ _do_test_nm_utils_strsplit_set_f_one(NMUtilsStrsplitSetFlags flags, g_assert_cmpstr(exp_words[i], ==, words[i]); g_assert(words[words_len] == NULL); - g_assert(_nm_utils_strv_cmp_n(exp_words, words_len, words, -1) == 0); + g_assert(nm_utils_strv_cmp_n(exp_words, words_len, words, -1) == 0); s1 = words[0]; g_assert(s1 >= (char *) &words[words_len + 1]); @@ -515,7 +576,7 @@ _do_test_nm_utils_strsplit_set_simple(NMUtilsStrsplitSetFlags flags, g_assert_cmpint(words_len, >, 0); n_tokens = NM_PTRARRAY_LEN(tokens); - if (_nm_utils_strv_cmp_n(exp_words, words_len, tokens, -1) != 0) { + if (nm_utils_strv_cmp_n(exp_words, words_len, tokens, -1) != 0) { gsize i; g_print(">>> split \"%s\" (flags %x) got %zu tokens (%zu expected)\n", @@ -1225,7 +1286,7 @@ _dedup_obj_destroy(NMDedupMultiObj *obj) { DedupObj *o = (DedupObj *) obj; - nm_assert(o->parent._ref_count == 0); + g_assert(o->parent._ref_count == 0); o->parent._ref_count = 1; o = _dedup_obj_assert(obj); g_slice_free(DedupObj, o); @@ -5425,7 +5486,7 @@ _test_connection_normalize_type_normalizable_type(const char *type, if (add_setting_fcn) s_base = add_setting_fcn(con); else { - s_base = NM_SETTING(g_object_new(base_type, NULL)); + s_base = g_object_new(base_type, NULL); nm_connection_add_setting(con, s_base); } @@ -8803,6 +8864,20 @@ test_nm_utils_enum(void) NULL, color_value_infos); + _test_nm_utils_enum_from_str_do_full(NM_TYPE_SETTING_CONNECTION_LLMNR, + "-1", + TRUE, + -1, + NULL, + NULL); + + _test_nm_utils_enum_from_str_do_full(NM_TYPE_SETTING_CONNECTION_LLMNR, + "-0x1", + TRUE, + -1, + NULL, + NULL); + _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, @@ -9538,6 +9613,11 @@ test_ethtool_offload(void) g_assert(d); g_assert_cmpint(d->id, ==, NM_ETHTOOL_ID_FEATURE_RXHASH); g_assert_cmpstr(d->optname, ==, NM_ETHTOOL_OPTNAME_FEATURE_RXHASH); + + /* these features are NETIF_F_NEVER_CHANGE: */ + g_assert(!nm_ethtool_data_get_by_optname("feature-netns-local")); + g_assert(!nm_ethtool_data_get_by_optname("feature-tx-lockless")); + g_assert(!nm_ethtool_data_get_by_optname("feature-vlan-challenged")); } /*****************************************************************************/ @@ -10058,7 +10138,7 @@ _strsplit_quoted_assert_strv(const char * topic, g_assert(strv1); g_assert(strv2); - if (_nm_utils_strv_equal((char **) strv1, (char **) strv2)) + if (nm_utils_strv_equal(strv1, strv2)) return; for (i = 0; strv1[i]; i++) { @@ -10198,6 +10278,45 @@ test_nm_utils_wifi_ghz_freqs(void) /*****************************************************************************/ +static void +test_vpn_connection_state_reason(void) +{ +#define ASSERT(v1, v2) \ + G_STMT_START \ + { \ + G_STATIC_ASSERT((gint64)(v1) == v2); \ + G_STATIC_ASSERT((gint64)(v2) == v1); \ + \ + nm_assert(((NMActiveConnectionStateReason)(int) (v1)) == v2); \ + nm_assert(((NMVpnConnectionStateReason)(int) (v2)) == v1); \ + } \ + G_STMT_END + + ASSERT(NM_VPN_CONNECTION_STATE_REASON_UNKNOWN, NM_ACTIVE_CONNECTION_STATE_REASON_UNKNOWN); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_NONE, NM_ACTIVE_CONNECTION_STATE_REASON_NONE); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED, + NM_ACTIVE_CONNECTION_STATE_REASON_USER_DISCONNECTED); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED, + NM_ACTIVE_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_STOPPED); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_IP_CONFIG_INVALID, + NM_ACTIVE_CONNECTION_STATE_REASON_IP_CONFIG_INVALID); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_CONNECT_TIMEOUT, + NM_ACTIVE_CONNECTION_STATE_REASON_CONNECT_TIMEOUT); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_FAILED, + NM_ACTIVE_CONNECTION_STATE_REASON_SERVICE_START_FAILED); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_NO_SECRETS, NM_ACTIVE_CONNECTION_STATE_REASON_NO_SECRETS); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_LOGIN_FAILED, + NM_ACTIVE_CONNECTION_STATE_REASON_LOGIN_FAILED); + ASSERT(NM_VPN_CONNECTION_STATE_REASON_CONNECTION_REMOVED, + NM_ACTIVE_CONNECTION_STATE_REASON_CONNECTION_REMOVED); +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -10206,6 +10325,7 @@ main(int argc, char **argv) nmtst_init(&argc, &argv, TRUE); g_test_add_func("/core/general/test_nm_ascii_spaces", test_nm_ascii_spaces); + g_test_add_func("/core/general/test_wired_wake_on_lan_enum", test_wired_wake_on_lan_enum); g_test_add_func("/core/general/test_nm_hash", test_nm_hash); g_test_add_func("/core/general/test_nm_g_slice_free_fcn", test_nm_g_slice_free_fcn); g_test_add_func("/core/general/test_c_list_sort", test_c_list_sort); @@ -10527,6 +10647,8 @@ main(int argc, char **argv) g_test_add_func("/core/general/test_nm_utils_wifi_ghz_freqs", test_nm_utils_wifi_ghz_freqs); g_test_add_func("/core/general/test_strsplit_quoted", test_strsplit_quoted); + g_test_add_func("/core/general/test_vpn_connection_state_reason", + test_vpn_connection_state_reason); return g_test_run(); } diff --git a/libnm-core/tests/test-keyfile.c b/libnm-core/tests/test-keyfile.c index 2b3750a9..b3af6c4e 100644 --- a/libnm-core/tests/test-keyfile.c +++ b/libnm-core/tests/test-keyfile.c @@ -1,13 +1,13 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2015 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-glib-aux/nm-json-aux.h" -#include "nm-keyfile/nm-keyfile-utils.h" -#include "nm-keyfile/nm-keyfile-internal.h" +#include "nm-keyfile-utils.h" +#include "nm-keyfile-internal.h" #include "nm-simple-connection.h" #include "nm-setting-connection.h" #include "nm-setting-wired.h" diff --git a/libnm-core/tests/test-secrets.c b/libnm-core/tests/test-secrets.c index eb08104a..42f1fd0a 100644 --- a/libnm-core/tests/test-secrets.c +++ b/libnm-core/tests/test-secrets.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2008 - 2011 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-setting-8021x.h" #include "nm-setting-cdma.h" diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 8978f73e..01cdb41c 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -1,14 +1,15 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2008 - 2017 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include #include #include "nm-glib-aux/nm-json-aux.h" +#include "nm-base/nm-ethtool-utils-base.h" #include "nm-core-internal.h" #include "nm-utils.h" #include "nm-utils-private.h" @@ -25,7 +26,7 @@ #include "nm-simple-connection.h" #include "nm-setting-connection.h" #include "nm-errors.h" -#include "nm-keyfile/nm-keyfile-internal.h" +#include "nm-keyfile-internal.h" #include "nm-utils/nm-test-utils.h" diff --git a/libnm-core/tests/test-settings-defaults.c b/libnm-core/tests/test-settings-defaults.c index 9e4b09a1..1e6acd3c 100644 --- a/libnm-core/tests/test-settings-defaults.c +++ b/libnm-core/tests/test-settings-defaults.c @@ -1,9 +1,9 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ +/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2008 - 2011 Red Hat, Inc. */ -#include "nm-default.h" +#include "libnm-core/nm-default-libnm-core.h" #include "nm-utils.h" #include "nm-setting-8021x.h" -- cgit 1.3.0-6-gf8a5 From 3a56bce6c0ea7ba0fe269520547740783b342e0d Mon Sep 17 00:00:00 2001 From: Michael Biebl Date: Thu, 18 Feb 2021 18:53:54 +0100 Subject: New upstream version 1.30.0 --- libnm-core/nm-version-macros.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'libnm-core') diff --git a/libnm-core/nm-version-macros.h b/libnm-core/nm-version-macros.h index 8ed5bb72..a7b074de 100644 --- a/libnm-core/nm-version-macros.h +++ b/libnm-core/nm-version-macros.h @@ -22,7 +22,7 @@ * Evaluates to the minor version number of NetworkManager which this source * is compiled against. */ -#define NM_MINOR_VERSION (29) +#define NM_MINOR_VERSION (30) /** * NM_MICRO_VERSION: @@ -30,7 +30,7 @@ * Evaluates to the micro version number of NetworkManager which this source * compiled against. */ -#define NM_MICRO_VERSION (90) +#define NM_MICRO_VERSION (0) /** * NM_CHECK_VERSION: -- cgit 1.3.0-6-gf8a5