diff options
author | Thomas Haller <thaller@redhat.com> | 2022-03-28 18:31:41 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2022-03-28 18:31:41 +0200 |
commit | 2bdca1f5d6f514586d6b3fdd43066eba09b0e50f (patch) | |
tree | 607fb1c9dc6bdba188729493db6adeb70ad36aa4 | |
parent | 321b59e84bf74233c043bfa58e7e4f78c6308580 (diff) | |
parent | 782f2fa8ef86a99b2dd6a25be5e742792a5b7b16 (diff) |
libnm/keyfile: merge branch 'th/keyfile-cleanup'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1161
-rw-r--r-- | src/libnm-core-impl/nm-keyfile.c | 759 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-meta-setting-base-impl.c | 62 | ||||
-rw-r--r-- | src/libnm-core-impl/nm-setting.c | 6 | ||||
-rw-r--r-- | src/libnm-core-impl/tests/test-keyfile.c | 109 | ||||
-rw-r--r-- | src/libnm-core-intern/nm-meta-setting-base-impl.h | 4 | ||||
-rw-r--r-- | src/libnm-glib-aux/nm-macros-internal.h | 14 | ||||
-rw-r--r-- | src/libnmc-setting/nm-meta-setting-base-impl.c | 62 | ||||
-rw-r--r-- | src/libnmc-setting/nm-meta-setting-base-impl.h | 4 |
8 files changed, 647 insertions, 373 deletions
diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c index dce53ae27e..00fb8a335d 100644 --- a/src/libnm-core-impl/nm-keyfile.c +++ b/src/libnm-core-impl/nm-keyfile.c @@ -115,12 +115,14 @@ _key_file_handler_data_init_write(NMKeyfileHandlerData *handler_data, &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, - ...) +/*****************************************************************************/ + +_nm_printf(5, 6) static void _read_handle_warn(KeyfileReaderInfo *info, + const char *kf_key, + const char *cur_property, + NMKeyfileWarnSeverity severity, + const char *fmt, + ...) { NMKeyfileHandlerData handler_data; @@ -148,16 +150,75 @@ _nm_printf(5, 6) static void _handle_warn(KeyfileReaderInfo *info, 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; \ +#define read_handle_warn(arg_info, arg_kf_key, arg_property_name, arg_severity, ...) \ + ({ \ + KeyfileReaderInfo *_info = (arg_info); \ + \ + nm_assert(!_info->error); \ + \ + if (_info->read_handler) { \ + _read_handle_warn(_info, \ + (arg_kf_key), \ + (arg_property_name), \ + (arg_severity), \ + __VA_ARGS__); \ + } \ + _info->error == NULL; \ + }) + +/*****************************************************************************/ + +_nm_printf(6, 7) static void _write_handle_warn(KeyfileWriterInfo *info, + NMSetting *setting, + const char *kf_key, + const char *cur_property, + NMKeyfileWarnSeverity severity, + const char *fmt, + ...) +{ + NMKeyfileHandlerData handler_data; + + _key_file_handler_data_init_write(&handler_data, + NM_KEYFILE_HANDLER_TYPE_WARN, + info, + nm_setting_get_name(setting), + cur_property, + setting, + kf_key); + handler_data.warn = (NMKeyfileHandlerDataWarn){ + .severity = severity, + .message = NULL, + .fmt = fmt, + }; + + va_start(handler_data.warn.ap, fmt); + + info->write_handler(info->connection, + info->keyfile, + NM_KEYFILE_HANDLER_TYPE_WARN, + &handler_data, + info->user_data); + + va_end(handler_data.warn.ap); + + g_free(handler_data.warn.message); +} + +#define write_handle_warn(arg_info, arg_setting, arg_kf_key, arg_property_name, arg_severity, ...) \ + ({ \ + KeyfileWriterInfo *_info = (arg_info); \ + \ + nm_assert(!_info->error); \ + \ + if (_info->write_handler) { \ + _write_handle_warn(_info, \ + (arg_setting), \ + (arg_kf_key), \ + (arg_property_name), \ + (arg_severity), \ + __VA_ARGS__); \ + } \ + _info->error == NULL; \ }) /*****************************************************************************/ @@ -264,11 +325,11 @@ get_one_int(KeyfileReaderInfo *info, if (!str || !str[0]) { if (info) { - handle_warn(info, - kf_key, - property_name, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("ignoring missing number")); + read_handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring missing number")); } return FALSE; } @@ -276,12 +337,12 @@ get_one_int(KeyfileReaderInfo *info, 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); + read_handle_warn(info, + kf_key, + property_name, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid number '%s'"), + str); } return FALSE; } @@ -305,13 +366,13 @@ build_address(KeyfileReaderInfo *info, 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); + read_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); } @@ -351,13 +412,13 @@ build_route(KeyfileReaderInfo *info, 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"); + read_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; } } @@ -373,13 +434,13 @@ build_route(KeyfileReaderInfo *info, 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); + read_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); } @@ -551,15 +612,15 @@ read_one_ip_address_or_route(KeyfileReaderInfo *info, /* 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); + read_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) */ @@ -567,30 +628,31 @@ read_one_ip_address_or_route(KeyfileReaderInfo *info, /* 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); + read_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); + read_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 @@ -599,23 +661,23 @@ read_one_ip_address_or_route(KeyfileReaderInfo *info, /* 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, + read_handle_warn(info, kf_key, property_name, - NM_KEYFILE_WARN_SEVERITY_INFO, - _("deprecated semicolon at the end of value %s: '%s'"), + NM_KEYFILE_WARN_SEVERITY_WARN, + _("garbage at the end of value %s: '%s'"), kf_key, - VALUE_ORIG())) + VALUE_ORIG()); + return NULL; + } else { + /* semicolon at the end of input */ + if (!read_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; } } @@ -628,26 +690,26 @@ read_one_ip_address_or_route(KeyfileReaderInfo *info, 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)) + || !read_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)) + if (!read_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; } @@ -983,13 +1045,13 @@ ip_routing_rule_parser_full(KeyfileReaderInfo *info, 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)) + if (!read_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; } @@ -1061,13 +1123,13 @@ ip_dns_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) 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])) { + if (!read_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); @@ -1098,13 +1160,13 @@ ip6_addr_gen_mode_parser(KeyfileReaderInfo *info, NMSetting *setting, const char 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"); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid option '%s', use one of [%s]"), + s, + "eui64,stable-privacy"); return; } } else @@ -1160,7 +1222,11 @@ mac_address_parser(KeyfileReaderInfo *info, goto good_addr_bin; } - handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("ignoring invalid MAC address")); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid MAC address")); return; good_addr_bin: @@ -1232,14 +1298,14 @@ read_hash_of_string(KeyfileReaderInfo *info, 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)) + if (!read_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); @@ -1426,7 +1492,7 @@ ssid_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) bytes = get_bytes(info, setting_name, key, FALSE, TRUE); if (!bytes) { - handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("ignoring invalid SSID")); + read_handle_warn(info, key, key, NM_KEYFILE_WARN_SEVERITY_WARN, _("ignoring invalid SSID")); return; } g_object_set(setting, key, bytes, NULL); @@ -1440,11 +1506,11 @@ password_raw_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key 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")); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("ignoring invalid raw password")); return; } g_object_set(setting, key, bytes, NULL); @@ -1585,7 +1651,11 @@ cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) 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")); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value")); } return; } @@ -1596,12 +1666,12 @@ cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) 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); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value path \"%s\""), + bin); return; } @@ -1621,12 +1691,12 @@ cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) * 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); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, + _("certificate or key file '%s' does not exist"), + path2); } return; } @@ -1634,12 +1704,12 @@ cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) 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); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid PKCS#11 URI \"%s\""), + bin); return; } @@ -1680,11 +1750,11 @@ cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) 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")); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value data:;base64, is not base64")); return; } @@ -1693,11 +1763,11 @@ cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) /* 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://")); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value data:;base64,file://")); return; } @@ -1718,12 +1788,12 @@ cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) /* 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); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE, + _("certificate or key file '%s' does not exist"), + path); } return; } @@ -1734,11 +1804,11 @@ cert_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) * 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")); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key/cert value is not a valid blob")); return; } @@ -1836,12 +1906,12 @@ parity_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) goto parity_good; } - handle_warn(info, - key, - key, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid parity value '%s'"), - tmp_str ?: ""); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid parity value '%s'"), + tmp_str ?: ""); return; parity_good: @@ -1858,12 +1928,12 @@ out_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); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid setting: %s"), + err->message); } static void @@ -1878,12 +1948,12 @@ team_config_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) 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); + read_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); } } @@ -1909,12 +1979,12 @@ bridge_vlan_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) 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); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + "invalid bridge VLAN: %s", + local->message); g_clear_error(&local); continue; } @@ -1961,12 +2031,12 @@ qdisc_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) 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); + read_handle_warn(info, + keys[i], + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid qdisc: %s"), + err->message); } else { g_ptr_array_add(qdiscs, qdisc); } @@ -2011,12 +2081,12 @@ tfilter_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) 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); + read_handle_warn(info, + keys[i], + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid tfilter: %s"), + err->message); } else { g_ptr_array_add(tfilters, tfilter); } @@ -2689,16 +2759,10 @@ cert_writer_default(NMConnection *connection, static void cert_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) { - const NMSetting8021xSchemeVtable *vtable = NULL; + const NMSetting8021xSchemeVtable *vtable; 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; - } - } + vtable = nm_setting_8021x_scheme_vtable_by_setting_key(key); if (!vtable) g_return_if_reached(); @@ -3181,12 +3245,12 @@ read_one_setting_value(KeyfileReaderInfo *info, && !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)) + if (!read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("error loading setting value: %s"), + err->message)) return; } return; @@ -3296,7 +3360,7 @@ read_one_setting_value(KeyfileReaderInfo *info, if (val > 255u) { if (!already_warned - && !handle_warn( + && !read_handle_warn( info, key, key, @@ -3356,12 +3420,12 @@ read_one_setting_value(KeyfileReaderInfo *info, 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); + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid setting: %s"), + err->message); } } } @@ -3381,12 +3445,12 @@ _read_setting(KeyfileReaderInfo *info) type = nm_setting_lookup_type(alias); if (!type) { - handle_warn(info, - NULL, - NULL, - NM_KEYFILE_WARN_SEVERITY_WARN, - _("invalid setting name '%s'"), - info->group); + read_handle_warn(info, + NULL, + NULL, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid setting name '%s'"), + info->group); return; } @@ -3428,13 +3492,13 @@ _read_setting(KeyfileReaderInfo *info) 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)) + if (!read_handle_warn(info, + key, + NULL, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("invalid key '%s.%s'"), + info->group, + key)) break; continue; } @@ -3444,13 +3508,13 @@ _read_setting(KeyfileReaderInfo *info) 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)) + if (!read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not boolean"), + info->group, + key)) break; continue; } @@ -3461,13 +3525,13 @@ _read_setting(KeyfileReaderInfo *info) 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)) + if (!read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' is not a uint32"), + info->group, + key)) break; continue; } @@ -3518,12 +3582,12 @@ _read_setting_wireguard_peer(KeyfileReaderInfo *info) || !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); + read_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); @@ -3533,13 +3597,13 @@ _read_setting_wireguard_peer(KeyfileReaderInfo *info) 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)) + if (!read_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); @@ -3556,13 +3620,13 @@ _read_setting_wireguard_peer(KeyfileReaderInfo *info) 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)) + if (!read_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); @@ -3579,13 +3643,13 @@ _read_setting_wireguard_peer(KeyfileReaderInfo *info) 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)) + if (!read_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); @@ -3595,13 +3659,13 @@ _read_setting_wireguard_peer(KeyfileReaderInfo *info) 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)) + if (!read_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; } } @@ -3621,13 +3685,13 @@ _read_setting_wireguard_peer(KeyfileReaderInfo *info) 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)) + if (!read_handle_warn(info, + key, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("key '%s.%s' has invalid allowed-ips"), + info->group, + key)) return; } } @@ -3636,13 +3700,13 @@ _read_setting_wireguard_peer(KeyfileReaderInfo *info) 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); + read_handle_warn(info, + NULL, + NM_SETTING_WIREGUARD_PEERS, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("peer '%s' is invalid: %s"), + info->group, + error->message); return; } @@ -3855,29 +3919,24 @@ write_setting_value(KeyfileWriterInfo *info, _parse_info_find(setting, key, &setting_info, NULL, &pip); + if (pip && pip->has_writer_full) { + pip->writer_full(info, setting_info, property_info, pip, setting); + return; + } + + if (pip && pip->writer_skip) + return; + 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. */ + /* the setting type is unknown. Handle this gracefully by + * ignoring 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); @@ -4089,8 +4148,10 @@ _write_setting_wireguard(NMSetting *setting, KeyfileWriterInfo *info) * @user_data: argument for @handler. * @error: the #GError in case writing fails. * - * @connection must verify as a valid profile according to - * nm_connection_verify(). + * @connection should verify as a valid profile according to + * nm_connection_verify(). If it does not verify, the keyfile may + * be incomplete and the parser may not be able to fully recreate + * the original profile. * * Returns: (transfer full): a new #GKeyFile or %NULL on error. * @@ -4104,7 +4165,6 @@ nm_keyfile_write(NMConnection *connection, GError **error) { nm_auto_unref_keyfile GKeyFile *keyfile = NULL; - GError *local = NULL; KeyfileWriterInfo info; NMSetting **settings; int i; @@ -4114,28 +4174,6 @@ nm_keyfile_write(NMConnection *connection, 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){ @@ -4189,11 +4227,16 @@ nm_keyfile_write(NMConnection *connection, 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(); + if (!write_handle_warn(&info, + setting, + NULL, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + _("unsupported option \"%s.%s\" of variant type %s"), + setting_name, + key, + g_variant_get_type_string(v))) + goto out_with_info_error; continue; } } diff --git a/src/libnm-core-impl/nm-meta-setting-base-impl.c b/src/libnm-core-impl/nm-meta-setting-base-impl.c index cd55779f11..69daa76c9d 100644 --- a/src/libnm-core-impl/nm-meta-setting-base-impl.c +++ b/src/libnm-core-impl/nm-meta-setting-base-impl.c @@ -153,6 +153,68 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { #undef _D }; +const NMSetting8021xSchemeVtable * +nm_setting_8021x_scheme_vtable_by_setting_key(const char *key) +{ + static const NMSetting8021xSchemeType sorted_index[] = { + NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY, + NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY, + }; + int imin, imax; + + nm_assert(key); + + if (NM_MORE_ASSERT_ONCE(5)) { + const NMSetting8021xSchemeVtable *vtable_prev = NULL; + int i, j; + + for (i = 0; i < (int) G_N_ELEMENTS(sorted_index); i++) { + const NMSetting8021xSchemeType t = sorted_index[i]; + const NMSetting8021xSchemeVtable *vtable; + + nm_assert(_NM_INT_NOT_NEGATIVE(t)); + nm_assert(t < G_N_ELEMENTS(nm_setting_8021x_scheme_vtable) - 1); + + for (j = 0; j < i; j++) + nm_assert(t != sorted_index[j]); + + vtable = &nm_setting_8021x_scheme_vtable[t]; + + nm_assert(vtable->scheme_type == t); + nm_assert(vtable->setting_key); + + if (vtable_prev) + nm_assert(strcmp(vtable_prev->setting_key, vtable->setting_key) < 0); + vtable_prev = vtable; + } + } + + imin = 0; + imax = G_N_ELEMENTS(sorted_index) - 1; + while (imin <= imax) { + const NMSetting8021xSchemeVtable *vtable; + const int imid = imin + (imax - imin) / 2; + int cmp; + + vtable = &nm_setting_8021x_scheme_vtable[sorted_index[imid]]; + + cmp = strcmp(vtable->setting_key, key); + if (cmp == 0) + return vtable; + + if (cmp < 0) + imin = imid + 1; + else + imax = imid - 1; + } + + return NULL; +} + /*****************************************************************************/ const NMMetaSettingInfo nm_meta_setting_infos[] = { diff --git a/src/libnm-core-impl/nm-setting.c b/src/libnm-core-impl/nm-setting.c index e65e75e736..35070baed1 100644 --- a/src/libnm-core-impl/nm-setting.c +++ b/src/libnm-core-impl/nm-setting.c @@ -3975,7 +3975,7 @@ nm_setting_option_set(NMSetting *setting, const char *opt_name, GVariant *varian g_hash_table_insert(hash, g_strdup(opt_name), g_variant_ref_sink(variant)); if (changed_value) - _nm_setting_option_notify(setting, !changed_name); + _nm_setting_option_notify(setting, changed_name); } /** @@ -4012,7 +4012,7 @@ nm_setting_option_set_boolean(NMSetting *setting, const char *opt_name, gboolean g_hash_table_insert(hash, g_strdup(opt_name), g_variant_ref_sink(g_variant_new_boolean(value))); if (changed_value) - _nm_setting_option_notify(setting, !changed_name); + _nm_setting_option_notify(setting, changed_name); } /** @@ -4047,7 +4047,7 @@ nm_setting_option_set_uint32(NMSetting *setting, const char *opt_name, guint32 v g_hash_table_insert(hash, g_strdup(opt_name), g_variant_ref_sink(g_variant_new_uint32(value))); if (changed_value) - _nm_setting_option_notify(setting, !changed_name); + _nm_setting_option_notify(setting, changed_name); } /*****************************************************************************/ diff --git a/src/libnm-core-impl/tests/test-keyfile.c b/src/libnm-core-impl/tests/test-keyfile.c index 9bd13ffc30..c163c4293b 100644 --- a/src/libnm-core-impl/tests/test-keyfile.c +++ b/src/libnm-core-impl/tests/test-keyfile.c @@ -5,16 +5,18 @@ #include "libnm-core-impl/nm-default-libnm-core.h" -#include "libnm-glib-aux/nm-json-aux.h" -#include "libnm-core-intern/nm-keyfile-utils.h" +#include "libnm-base/nm-ethtool-utils-base.h" #include "libnm-core-intern/nm-keyfile-internal.h" -#include "nm-simple-connection.h" -#include "nm-setting-connection.h" -#include "nm-setting-wired.h" +#include "libnm-core-intern/nm-keyfile-utils.h" +#include "libnm-glib-aux/nm-json-aux.h" #include "nm-setting-8021x.h" +#include "nm-setting-connection.h" +#include "nm-setting-ethtool.h" +#include "nm-setting-proxy.h" #include "nm-setting-team.h" #include "nm-setting-user.h" -#include "nm-setting-proxy.h" +#include "nm-setting-wired.h" +#include "nm-simple-connection.h" #include "libnm-glib-aux/nm-test-utils.h" @@ -887,6 +889,100 @@ test_bridge_port_vlans(void) /*****************************************************************************/ +typedef struct { + bool expect; + guint n_calls; +} InvalidOptionWriteData; + +static gboolean +_invalid_option_write_handler(NMConnection *connection, + GKeyFile *keyfile, + NMKeyfileHandlerType handler_type, + NMKeyfileHandlerData *handler_data, + void *user_data) +{ + InvalidOptionWriteData *data = user_data; + const char *message; + NMKeyfileWarnSeverity severity; + + g_assert(data); + g_assert(data->expect); + + g_assert(data->n_calls == 0); + data->n_calls++; + + switch (handler_type) { + case NM_KEYFILE_HANDLER_TYPE_WARN: + nm_keyfile_handler_data_warn_get(handler_data, &message, &severity); + g_assert(message && strstr(message, "ethtool.bogus")); + break; + default: + g_assert_not_reached(); + } + + return TRUE; +} + +static void +test_invalid_option(void) +{ + gs_unref_object NMConnection *con = NULL; + NMSetting *s_ethtool; + nm_auto_unref_keyfile GKeyFile *kf = NULL; + gs_free_error GError *error = NULL; + InvalidOptionWriteData data; + + con = nmtst_create_minimal_connection("test invalid option", + NULL, + NM_SETTING_WIRED_SETTING_NAME, + NULL); + + s_ethtool = nm_setting_ethtool_new(); + + nm_connection_add_setting(con, s_ethtool); + + nm_setting_option_set_boolean(s_ethtool, NM_ETHTOOL_OPTNAME_PAUSE_RX, TRUE); + + data = (InvalidOptionWriteData){}; + kf = nm_keyfile_write(con, + NM_KEYFILE_HANDLER_FLAGS_NONE, + _invalid_option_write_handler, + &data, + nmtst_get_rand_bool() ? &error : NULL); + nmtst_assert_success(kf, error); + nm_clear_pointer(&kf, g_key_file_unref); + + nmtst_connection_normalize(con); + + nmtst_assert_connection_verifies_without_normalization(con); + + data = (InvalidOptionWriteData){}; + kf = nm_keyfile_write(con, + NM_KEYFILE_HANDLER_FLAGS_NONE, + _invalid_option_write_handler, + &data, + nmtst_get_rand_bool() ? &error : NULL); + nmtst_assert_success(kf, error); + nm_clear_pointer(&kf, g_key_file_unref); + + nm_setting_option_set(s_ethtool, "bogus", g_variant_new_int64(0)); + + data = (InvalidOptionWriteData){ + .expect = TRUE, + }; + kf = nm_keyfile_write(con, + NM_KEYFILE_HANDLER_FLAGS_NONE, + _invalid_option_write_handler, + &data, + nmtst_get_rand_bool() ? &error : NULL); + nmtst_assert_success(kf, error); + nm_clear_pointer(&kf, g_key_file_unref); + + g_assert_cmpint(data.n_calls, ==, 1); +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -904,6 +1000,7 @@ main(int argc, char **argv) g_test_add_func("/core/keyfile/test_vpn/1", test_vpn_1); g_test_add_func("/core/keyfile/bridge/vlans", test_bridge_vlans); g_test_add_func("/core/keyfile/bridge-port/vlans", test_bridge_port_vlans); + g_test_add_func("/core/keyfile/invalid-option", test_invalid_option); return g_test_run(); } diff --git a/src/libnm-core-intern/nm-meta-setting-base-impl.h b/src/libnm-core-intern/nm-meta-setting-base-impl.h index b1f1263693..1268865954 100644 --- a/src/libnm-core-intern/nm-meta-setting-base-impl.h +++ b/src/libnm-core-intern/nm-meta-setting-base-impl.h @@ -51,7 +51,7 @@ typedef enum /*< skip >*/ { /*****************************************************************************/ -typedef enum { +typedef enum _nm_packed { 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, @@ -92,6 +92,8 @@ typedef struct { extern const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[_NM_SETTING_802_1X_SCHEME_TYPE_NUM + 1]; +const NMSetting8021xSchemeVtable *nm_setting_8021x_scheme_vtable_by_setting_key(const char *key); + /*****************************************************************************/ typedef enum _nm_packed { diff --git a/src/libnm-glib-aux/nm-macros-internal.h b/src/libnm-glib-aux/nm-macros-internal.h index 140104d350..7cc8ac9797 100644 --- a/src/libnm-glib-aux/nm-macros-internal.h +++ b/src/libnm-glib-aux/nm-macros-internal.h @@ -620,10 +620,16 @@ nm_str_realloc(char *str) /* invokes _notify() for all arguments (of type _PropertyEnums). Note, that if * there are more than one prop arguments, this will involve a freeze/thaw * of GObject property notifications. */ -#define nm_gobject_notify_together_full(suffix, obj, ...) \ - _nm_gobject_notify_together_impl##suffix(obj, \ - NM_NARG(__VA_ARGS__), \ - (const _PropertyEnums##suffix[]){__VA_ARGS__}) +#define nm_gobject_notify_together_full(suffix, obj, ...) \ + G_STMT_START \ + { \ + const _PropertyEnums##suffix _props[] = {__VA_ARGS__}; \ + \ + G_STATIC_ASSERT(G_N_ELEMENTS(_props) == NM_NARG(__VA_ARGS__)); \ + \ + _nm_gobject_notify_together_impl##suffix(obj, G_N_ELEMENTS(_props), _props); \ + } \ + G_STMT_END #define nm_gobject_notify_together(obj, ...) nm_gobject_notify_together_full(, obj, __VA_ARGS__) diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.c b/src/libnmc-setting/nm-meta-setting-base-impl.c index cd55779f11..69daa76c9d 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.c +++ b/src/libnmc-setting/nm-meta-setting-base-impl.c @@ -153,6 +153,68 @@ const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[] = { #undef _D }; +const NMSetting8021xSchemeVtable * +nm_setting_8021x_scheme_vtable_by_setting_key(const char *key) +{ + static const NMSetting8021xSchemeType sorted_index[] = { + NM_SETTING_802_1X_SCHEME_TYPE_CA_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_CLIENT_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CA_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_CLIENT_CERT, + NM_SETTING_802_1X_SCHEME_TYPE_PHASE2_PRIVATE_KEY, + NM_SETTING_802_1X_SCHEME_TYPE_PRIVATE_KEY, + }; + int imin, imax; + + nm_assert(key); + + if (NM_MORE_ASSERT_ONCE(5)) { + const NMSetting8021xSchemeVtable *vtable_prev = NULL; + int i, j; + + for (i = 0; i < (int) G_N_ELEMENTS(sorted_index); i++) { + const NMSetting8021xSchemeType t = sorted_index[i]; + const NMSetting8021xSchemeVtable *vtable; + + nm_assert(_NM_INT_NOT_NEGATIVE(t)); + nm_assert(t < G_N_ELEMENTS(nm_setting_8021x_scheme_vtable) - 1); + + for (j = 0; j < i; j++) + nm_assert(t != sorted_index[j]); + + vtable = &nm_setting_8021x_scheme_vtable[t]; + + nm_assert(vtable->scheme_type == t); + nm_assert(vtable->setting_key); + + if (vtable_prev) + nm_assert(strcmp(vtable_prev->setting_key, vtable->setting_key) < 0); + vtable_prev = vtable; + } + } + + imin = 0; + imax = G_N_ELEMENTS(sorted_index) - 1; + while (imin <= imax) { + const NMSetting8021xSchemeVtable *vtable; + const int imid = imin + (imax - imin) / 2; + int cmp; + + vtable = &nm_setting_8021x_scheme_vtable[sorted_index[imid]]; + + cmp = strcmp(vtable->setting_key, key); + if (cmp == 0) + return vtable; + + if (cmp < 0) + imin = imid + 1; + else + imax = imid - 1; + } + + return NULL; +} + /*****************************************************************************/ const NMMetaSettingInfo nm_meta_setting_infos[] = { diff --git a/src/libnmc-setting/nm-meta-setting-base-impl.h b/src/libnmc-setting/nm-meta-setting-base-impl.h index b1f1263693..1268865954 100644 --- a/src/libnmc-setting/nm-meta-setting-base-impl.h +++ b/src/libnmc-setting/nm-meta-setting-base-impl.h @@ -51,7 +51,7 @@ typedef enum /*< skip >*/ { /*****************************************************************************/ -typedef enum { +typedef enum _nm_packed { 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, @@ -92,6 +92,8 @@ typedef struct { extern const NMSetting8021xSchemeVtable nm_setting_8021x_scheme_vtable[_NM_SETTING_802_1X_SCHEME_TYPE_NUM + 1]; +const NMSetting8021xSchemeVtable *nm_setting_8021x_scheme_vtable_by_setting_key(const char *key); + /*****************************************************************************/ typedef enum _nm_packed { |