2019-09-10 11:19:01 +02:00
|
|
|
// SPDX-License-Identifier: GPL-2.0+
|
2019-09-25 13:13:40 +02:00
|
|
|
/*
|
2015-02-18 19:59:28 +01:00
|
|
|
* Copyright (C) 2008 - 2009 Novell, Inc.
|
2017-11-18 17:16:50 +01:00
|
|
|
* Copyright (C) 2008 - 2017 Red Hat, Inc.
|
2015-02-18 19:59:28 +01:00
|
|
|
*/
|
|
|
|
|
|
2016-02-12 14:44:52 +01:00
|
|
|
#include "nm-default.h"
|
2016-02-19 14:57:48 +01:00
|
|
|
|
2016-02-12 14:44:52 +01:00
|
|
|
#include "nm-keyfile-internal.h"
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
#include <stdlib.h>
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
#include <stdio.h>
|
2015-02-18 19:59:28 +01:00
|
|
|
#include <sys/stat.h>
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#include <arpa/inet.h>
|
2017-11-18 17:16:50 +01:00
|
|
|
#include <linux/pkt_sched.h>
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-04-15 08:16:00 +02:00
|
|
|
#include "nm-glib-aux/nm-secret-utils.h"
|
2019-01-30 12:36:13 +01:00
|
|
|
#include "systemd/nm-sd-utils-shared.h"
|
shared: build helper "libnm-libnm-core-{intern|aux}.la" library for libnm-core
"libnm-core" implements common functionality for "NetworkManager" and
"libnm".
Note that clients like "nmcli" cannot access the internal API provided
by "libnm-core". So, if nmcli wants to do something that is also done by
"libnm-core", , "libnm", or "NetworkManager", the code would have to be
duplicated.
Instead, such code can be in "libnm-libnm-core-{intern|aux}.la".
Note that:
0) "libnm-libnm-core-intern.la" is used by libnm-core itsself.
On the other hand, "libnm-libnm-core-aux.la" is not used by
libnm-core, but provides utilities on top of it.
1) they both extend "libnm-core" with utlities that are not public
API of libnm itself. Maybe part of the code should one day become
public API of libnm. On the other hand, this is code for which
we may not want to commit to a stable interface or which we
don't want to provide as part of the API.
2) "libnm-libnm-core-intern.la" is statically linked by "libnm-core"
and thus directly available to "libnm" and "NetworkManager".
On the other hand, "libnm-libnm-core-aux.la" may be used by "libnm"
and "NetworkManager".
Both libraries may be statically linked by libnm clients (like
nmcli).
3) it must only use glib, libnm-glib-aux.la, and the public API
of libnm-core.
This is important: it must not use "libnm-core/nm-core-internal.h"
nor "libnm-core/nm-utils-private.h" so the static library is usable
by nmcli which couldn't access these.
Note that "shared/nm-meta-setting.c" is an entirely different case,
because it behaves differently depending on whether linking against
"libnm-core" or the client programs. As such, this file must be compiled
twice.
(cherry picked from commit af07ed01c04867e281cc3982a7ab0d244d4f8e2e)
2019-04-15 09:26:53 +02:00
|
|
|
#include "nm-libnm-core-intern/nm-common-macros.h"
|
2015-02-18 19:59:28 +01:00
|
|
|
#include "nm-core-internal.h"
|
2015-02-18 18:59:35 +01:00
|
|
|
#include "nm-keyfile-utils.h"
|
|
|
|
|
|
2017-05-04 14:50:07 +02:00
|
|
|
#include "nm-setting-user.h"
|
|
|
|
|
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-03-22 15:16:48 +01:00
|
|
|
typedef struct _ParseInfoProperty ParseInfoProperty;
|
|
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
typedef struct {
|
|
|
|
|
NMConnection *connection;
|
|
|
|
|
GKeyFile *keyfile;
|
|
|
|
|
const char *base_dir;
|
|
|
|
|
NMKeyfileReadHandler handler;
|
|
|
|
|
void *user_data;
|
|
|
|
|
GError *error;
|
|
|
|
|
const char *group;
|
|
|
|
|
NMSetting *setting;
|
|
|
|
|
} KeyfileReaderInfo;
|
|
|
|
|
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
typedef struct {
|
|
|
|
|
NMConnection *connection;
|
|
|
|
|
GKeyFile *keyfile;
|
|
|
|
|
GError *error;
|
|
|
|
|
NMKeyfileWriteHandler handler;
|
|
|
|
|
void *user_data;
|
|
|
|
|
} KeyfileWriterInfo;
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2015-02-18 18:59:35 +01:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_handle_warn (KeyfileReaderInfo *info,
|
|
|
|
|
const char *property_name,
|
|
|
|
|
NMKeyfileWarnSeverity severity,
|
|
|
|
|
char *message)
|
|
|
|
|
{
|
|
|
|
|
NMKeyfileReadTypeDataWarn type_data = {
|
|
|
|
|
.group = info->group,
|
|
|
|
|
.setting = info->setting,
|
|
|
|
|
.property_name = property_name,
|
|
|
|
|
.severity = severity,
|
|
|
|
|
.message = message,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
info->handler (info->keyfile,
|
|
|
|
|
info->connection,
|
|
|
|
|
NM_KEYFILE_READ_TYPE_WARN,
|
|
|
|
|
&type_data,
|
|
|
|
|
info->user_data,
|
|
|
|
|
&info->error);
|
|
|
|
|
g_free (message);
|
|
|
|
|
}
|
|
|
|
|
#define handle_warn(arg_info, arg_property_name, arg_severity, ...) \
|
|
|
|
|
({ \
|
|
|
|
|
KeyfileReaderInfo *_info = (arg_info); \
|
|
|
|
|
\
|
|
|
|
|
if (_info->handler) { \
|
|
|
|
|
_handle_warn (_info, (arg_property_name), (arg_severity), \
|
|
|
|
|
g_strdup_printf (__VA_ARGS__)); \
|
|
|
|
|
} \
|
|
|
|
|
_info->error == NULL; \
|
|
|
|
|
})
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-01-02 12:39:05 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
_secret_flags_persist_secret (NMSettingSecretFlags flags)
|
|
|
|
|
{
|
|
|
|
|
return flags == NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2015-02-18 19:59:28 +01:00
|
|
|
/* 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
|
2015-02-18 18:59:35 +01:00
|
|
|
setting_alias_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
|
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
|
|
|
|
const char *key_setting_name;
|
2019-01-02 09:09:37 +01:00
|
|
|
gs_free char *s = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
s = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
|
2019-01-02 09:09:37 +01:00
|
|
|
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);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
2019-01-02 09:09:37 +01:00
|
|
|
if (n_keys == 0)
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
|
|
|
|
|
2018-12-01 17:44:37 +01:00
|
|
|
vf = _nm_utils_sriov_vf_from_strparts (rest, value, TRUE, NULL);
|
2018-05-25 12:05:24 +02:00
|
|
|
if (vf)
|
|
|
|
|
g_ptr_array_add (vfs, vf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_set (G_OBJECT (setting),
|
|
|
|
|
key, vfs,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
static void
|
2015-02-18 19:59:28 +01:00
|
|
|
read_array_of_uint (GKeyFile *file,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
const char *key)
|
|
|
|
|
{
|
2016-12-21 20:10:03 +01:00
|
|
|
gs_unref_array GArray *array = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
gsize length;
|
2016-12-21 20:10:03 +01:00
|
|
|
gsize i;
|
2016-12-21 20:19:13 +01:00
|
|
|
gs_free int *tmp = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
tmp = nm_keyfile_plugin_kf_get_integer_list (file, nm_setting_get_name (setting), key, &length, NULL);
|
2016-12-21 20:10:03 +01:00
|
|
|
if (length > G_MAXUINT)
|
|
|
|
|
return;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2016-12-21 20:10:03 +01:00
|
|
|
array = g_array_sized_new (FALSE, FALSE, sizeof (guint), length);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
|
if (tmp[i] < 0)
|
|
|
|
|
return;
|
2015-02-18 19:59:28 +01:00
|
|
|
g_array_append_val (array, tmp[i]);
|
2016-12-21 20:10:03 +01:00
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
g_object_set (setting, key, array, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2015-02-18 18:59:35 +01:00
|
|
|
get_one_int (KeyfileReaderInfo *info, const char *property_name, const char *str, guint32 max_val, guint32 *out)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
2017-10-04 11:14:48 +02:00
|
|
|
gint64 tmp;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
g_return_val_if_fail (!info == !property_name, FALSE);
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
if (!str || !str[0]) {
|
2015-02-18 18:59:35 +01:00
|
|
|
if (property_name)
|
|
|
|
|
handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring missing number"));
|
2015-02-18 19:59:28 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2017-10-04 11:14:48 +02:00
|
|
|
tmp = _nm_utils_ascii_str_to_int64 (str, 10, 0, max_val, -1);
|
|
|
|
|
if (tmp == -1) {
|
|
|
|
|
if (property_name) {
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring invalid number '%s'"),
|
|
|
|
|
str);
|
2017-10-04 11:14:48 +02:00
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
*out = (guint32) tmp;
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gpointer
|
2015-02-18 18:59:35 +01:00
|
|
|
build_address (KeyfileReaderInfo *info, int family, const char *address_str, guint32 plen, const char *property_name)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
|
|
|
|
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) {
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
2015-05-04 19:10:29 +03:00
|
|
|
_("ignoring invalid %s address: %s"),
|
2015-02-18 18:59:35 +01:00
|
|
|
family == AF_INET ? "IPv4" : "IPv6", error->message);
|
2015-02-18 19:59:28 +01:00
|
|
|
g_error_free (error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return addr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gpointer
|
2015-02-18 18:59:35 +01:00
|
|
|
build_route (KeyfileReaderInfo *info,
|
|
|
|
|
const char *property_name,
|
|
|
|
|
int family,
|
all: allow configuring default-routes as manual, static routes
Up until now, a default-route (with prefix length zero) could not
be configured directly. The user could only set ipv4.gateway,
ipv4.never-default, ipv4.route-metric and ipv4.route-table to influence
the setting of the default-route (respectively for IPv6).
That is a problematic limitation. For one, whether a route has prefix
length zero or non-zero does not make a fundamental difference. Also,
it makes it impossible to configure all the routing attributes that one can
configure otherwise for static routes. For example, the default-route could
not be configured as "onlink", could not have a special MTU, nor could it be
placed in a dedicated routing table.
Fix that by lifting the restriction. Note that "ipv4.never-default" does
not apply to /0 manual routes. Likewise, the previous manners of
configuring default-routes ("ipv4.gateway") don't conflict with manual
default-routes.
Server-side this all the pieces are already in place to accept a default-route
as static routes. This was done by earlier commits like 5c299454b49b
('core: rework tracking of gateway/default-route in ip-config').
A long time ago, NMIPRoute would assert that the prefix length is
positive. That was relaxed by commit a2e93f2de4ac ('libnm: allow zero
prefix length for NMIPRoute'), already before 1.0.0. Using libnm from
before 1.0.0 would result in assertion failures.
Note that the default-route-metric-penalty based on connectivity
checking applies to all /0 routes, even these static routes. Be they
added due to DHCP, "ipv4.gateway", "ipv4.routes" or "wireguard.peer-routes".
I wonder whether doing that unconditionally is desirable, and maybe
there should be a way to opt-out/opt-in for the entire profile or even
per-routes.
https://bugzilla.redhat.com/show_bug.cgi?id=1714438
2019-08-03 08:15:50 +02:00
|
|
|
const char *dest_str,
|
|
|
|
|
guint32 plen,
|
|
|
|
|
const char *gateway_str,
|
|
|
|
|
const char *metric_str)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
|
|
|
|
NMIPRoute *route;
|
2017-10-04 11:28:15 +02:00
|
|
|
guint32 u32;
|
|
|
|
|
gint64 metric = -1;
|
2015-02-18 19:59:28 +01:00
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (dest_str, NULL);
|
|
|
|
|
|
|
|
|
|
/* Next hop */
|
|
|
|
|
if (gateway_str && gateway_str[0]) {
|
|
|
|
|
if (!nm_utils_ipaddr_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
|
2017-10-04 11:28:15 +02:00
|
|
|
&& get_one_int (NULL, NULL, gateway_str, G_MAXUINT32, &u32)) {
|
|
|
|
|
metric = u32;
|
2015-02-18 19:59:28 +01:00
|
|
|
gateway_str = NULL;
|
2017-10-04 11:28:15 +02:00
|
|
|
} else {
|
2015-02-18 18:59:35 +01:00
|
|
|
if (!info->error) {
|
|
|
|
|
handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring invalid gateway '%s' for %s route"),
|
|
|
|
|
gateway_str, family == AF_INET ? "IPv4" : "IPv6");
|
|
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
gateway_str = NULL;
|
|
|
|
|
|
2017-10-04 11:28:15 +02:00
|
|
|
/* parse metric, default to -1 */
|
2015-02-18 19:59:28 +01:00
|
|
|
if (metric_str) {
|
2017-10-04 11:28:15 +02:00
|
|
|
if (!get_one_int (info, property_name, metric_str, G_MAXUINT32, &u32))
|
2015-02-18 19:59:28 +01:00
|
|
|
return NULL;
|
2017-10-04 11:28:15 +02:00
|
|
|
metric = u32;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
all: allow configuring default-routes as manual, static routes
Up until now, a default-route (with prefix length zero) could not
be configured directly. The user could only set ipv4.gateway,
ipv4.never-default, ipv4.route-metric and ipv4.route-table to influence
the setting of the default-route (respectively for IPv6).
That is a problematic limitation. For one, whether a route has prefix
length zero or non-zero does not make a fundamental difference. Also,
it makes it impossible to configure all the routing attributes that one can
configure otherwise for static routes. For example, the default-route could
not be configured as "onlink", could not have a special MTU, nor could it be
placed in a dedicated routing table.
Fix that by lifting the restriction. Note that "ipv4.never-default" does
not apply to /0 manual routes. Likewise, the previous manners of
configuring default-routes ("ipv4.gateway") don't conflict with manual
default-routes.
Server-side this all the pieces are already in place to accept a default-route
as static routes. This was done by earlier commits like 5c299454b49b
('core: rework tracking of gateway/default-route in ip-config').
A long time ago, NMIPRoute would assert that the prefix length is
positive. That was relaxed by commit a2e93f2de4ac ('libnm: allow zero
prefix length for NMIPRoute'), already before 1.0.0. Using libnm from
before 1.0.0 would result in assertion failures.
Note that the default-route-metric-penalty based on connectivity
checking applies to all /0 routes, even these static routes. Be they
added due to DHCP, "ipv4.gateway", "ipv4.routes" or "wireguard.peer-routes".
I wonder whether doing that unconditionally is desirable, and maybe
there should be a way to opt-out/opt-in for the entire profile or even
per-routes.
https://bugzilla.redhat.com/show_bug.cgi?id=1714438
2019-08-03 08:15:50 +02:00
|
|
|
route = nm_ip_route_new (family,
|
|
|
|
|
dest_str,
|
|
|
|
|
plen,
|
|
|
|
|
gateway_str,
|
2017-10-04 11:28:15 +02:00
|
|
|
metric,
|
2015-02-18 19:59:28 +01:00
|
|
|
&error);
|
|
|
|
|
if (!route) {
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring invalid %s route: %s"),
|
2015-02-18 19:59:28 +01:00
|
|
|
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;
|
|
|
|
|
*/
|
2017-10-04 11:16:36 +02:00
|
|
|
static const char *
|
|
|
|
|
read_field (char **current, const char **out_err_str, const char *characters, const char *delimiters)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
2017-10-04 11:16:36 +02:00
|
|
|
const char *start;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2017-10-04 11:16:36 +02:00
|
|
|
nm_assert (current);
|
|
|
|
|
nm_assert (out_err_str);
|
|
|
|
|
nm_assert (characters);
|
|
|
|
|
nm_assert (delimiters);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2017-10-04 11:16:36 +02:00
|
|
|
*out_err_str = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
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 */
|
2017-10-04 11:16:36 +02:00
|
|
|
*out_err_str = *current;
|
|
|
|
|
*current = (char *) start;
|
2015-02-18 19:59:28 +01:00
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
/* success, end of input */
|
|
|
|
|
*current = NULL;
|
|
|
|
|
return start;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-24 15:01:21 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
#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 requrie 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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
#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 (/),
|
2018-09-15 07:20:54 -04:00
|
|
|
* semicolon (;) and comma (,) are interchangeable. The choice of
|
2015-02-18 19:59:28 +01:00
|
|
|
* 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
|
2015-02-18 18:59:35 +01:00
|
|
|
read_one_ip_address_or_route (KeyfileReaderInfo *info,
|
|
|
|
|
const char *property_name,
|
2015-02-18 19:59:28 +01:00
|
|
|
const char *setting_name,
|
|
|
|
|
const char *key_name,
|
|
|
|
|
gboolean ipv6,
|
|
|
|
|
gboolean route,
|
2015-02-18 18:59:35 +01:00
|
|
|
char **out_gateway,
|
|
|
|
|
NMSetting *setting)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
2017-10-04 11:16:36 +02:00
|
|
|
guint plen;
|
2015-02-18 19:59:28 +01:00
|
|
|
gpointer result;
|
2017-10-04 11:16:36 +02:00
|
|
|
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;
|
2015-02-18 18:59:35 +01:00
|
|
|
|
2018-04-24 11:20:03 +02:00
|
|
|
#define VALUE_ORIG() (value_orig ?: (value_orig = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key_name, NULL)))
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2017-10-04 11:16:36 +02:00
|
|
|
value = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key_name, NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
if (!value)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2017-10-04 11:16:36 +02:00
|
|
|
current = value;
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
/* get address field */
|
2017-10-04 11:16:36 +02:00
|
|
|
address_str = read_field (¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS);
|
|
|
|
|
if (err_str) {
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("unexpected character '%c' for address %s: '%s' (position %td)"),
|
2017-10-04 11:16:36 +02:00
|
|
|
*err_str, key_name, VALUE_ORIG (), err_str - current);
|
2015-02-18 18:59:35 +01:00
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
/* get prefix length field (skippable) */
|
2017-10-04 11:16:36 +02:00
|
|
|
plen_str = read_field (¤t, &err_str, DIGITS, DELIMITERS);
|
2015-02-18 19:59:28 +01:00
|
|
|
/* get gateway field */
|
2017-10-04 11:16:36 +02:00
|
|
|
gateway_str = read_field (¤t, &err_str, IP_ADDRESS_CHARS, DELIMITERS);
|
|
|
|
|
if (err_str) {
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("unexpected character '%c' for %s: '%s' (position %td)"),
|
2017-10-04 11:16:36 +02:00
|
|
|
*err_str, key_name, VALUE_ORIG (), err_str - current);
|
2015-02-18 18:59:35 +01:00
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
/* for routes, get metric */
|
|
|
|
|
if (route) {
|
2017-10-04 11:16:36 +02:00
|
|
|
metric_str = read_field (¤t, &err_str, DIGITS, DELIMITERS);
|
|
|
|
|
if (err_str) {
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("unexpected character '%c' in prefix length for %s: '%s' (position %td)"),
|
2017-10-04 11:16:36 +02:00
|
|
|
*err_str, key_name, VALUE_ORIG (), err_str - current);
|
2015-02-18 18:59:35 +01:00
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
} else
|
|
|
|
|
metric_str = NULL;
|
|
|
|
|
if (current) {
|
|
|
|
|
/* there is still some data */
|
|
|
|
|
if (*current) {
|
|
|
|
|
/* another field follows */
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("garbage at the end of value %s: '%s'"),
|
|
|
|
|
key_name, VALUE_ORIG ());
|
|
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
} else {
|
|
|
|
|
/* semicolon at the end of input */
|
2015-02-18 18:59:35 +01:00
|
|
|
if (!handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_INFO,
|
|
|
|
|
_("deprecated semicolon at the end of value %s: '%s'"),
|
|
|
|
|
key_name, VALUE_ORIG ()))
|
|
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#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) {
|
all: allow configuring default-routes as manual, static routes
Up until now, a default-route (with prefix length zero) could not
be configured directly. The user could only set ipv4.gateway,
ipv4.never-default, ipv4.route-metric and ipv4.route-table to influence
the setting of the default-route (respectively for IPv6).
That is a problematic limitation. For one, whether a route has prefix
length zero or non-zero does not make a fundamental difference. Also,
it makes it impossible to configure all the routing attributes that one can
configure otherwise for static routes. For example, the default-route could
not be configured as "onlink", could not have a special MTU, nor could it be
placed in a dedicated routing table.
Fix that by lifting the restriction. Note that "ipv4.never-default" does
not apply to /0 manual routes. Likewise, the previous manners of
configuring default-routes ("ipv4.gateway") don't conflict with manual
default-routes.
Server-side this all the pieces are already in place to accept a default-route
as static routes. This was done by earlier commits like 5c299454b49b
('core: rework tracking of gateway/default-route in ip-config').
A long time ago, NMIPRoute would assert that the prefix length is
positive. That was relaxed by commit a2e93f2de4ac ('libnm: allow zero
prefix length for NMIPRoute'), already before 1.0.0. Using libnm from
before 1.0.0 would result in assertion failures.
Note that the default-route-metric-penalty based on connectivity
checking applies to all /0 routes, even these static routes. Be they
added due to DHCP, "ipv4.gateway", "ipv4.routes" or "wireguard.peer-routes".
I wonder whether doing that unconditionally is desirable, and maybe
there should be a way to opt-out/opt-in for the entire profile or even
per-routes.
https://bugzilla.redhat.com/show_bug.cgi?id=1714438
2019-08-03 08:15:50 +02:00
|
|
|
if (!get_one_int (info, property_name, plen_str, ipv6 ? 128 : 32, &plen)) {
|
2015-02-18 19:59:28 +01:00
|
|
|
plen = DEFAULT_PREFIX (route, ipv6);
|
2015-02-18 18:59:35 +01:00
|
|
|
if ( info->error
|
|
|
|
|
|| !handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("invalid prefix length for %s '%s', defaulting to %d"),
|
|
|
|
|
key_name, VALUE_ORIG (), plen))
|
|
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
plen = DEFAULT_PREFIX (route, ipv6);
|
2015-02-18 18:59:35 +01:00
|
|
|
if (!handle_warn (info, property_name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("missing prefix length for %s '%s', defaulting to %d"),
|
|
|
|
|
key_name, VALUE_ORIG (), plen))
|
|
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* build the appropriate data structure for NetworkManager settings */
|
|
|
|
|
if (route) {
|
all: allow configuring default-routes as manual, static routes
Up until now, a default-route (with prefix length zero) could not
be configured directly. The user could only set ipv4.gateway,
ipv4.never-default, ipv4.route-metric and ipv4.route-table to influence
the setting of the default-route (respectively for IPv6).
That is a problematic limitation. For one, whether a route has prefix
length zero or non-zero does not make a fundamental difference. Also,
it makes it impossible to configure all the routing attributes that one can
configure otherwise for static routes. For example, the default-route could
not be configured as "onlink", could not have a special MTU, nor could it be
placed in a dedicated routing table.
Fix that by lifting the restriction. Note that "ipv4.never-default" does
not apply to /0 manual routes. Likewise, the previous manners of
configuring default-routes ("ipv4.gateway") don't conflict with manual
default-routes.
Server-side this all the pieces are already in place to accept a default-route
as static routes. This was done by earlier commits like 5c299454b49b
('core: rework tracking of gateway/default-route in ip-config').
A long time ago, NMIPRoute would assert that the prefix length is
positive. That was relaxed by commit a2e93f2de4ac ('libnm: allow zero
prefix length for NMIPRoute'), already before 1.0.0. Using libnm from
before 1.0.0 would result in assertion failures.
Note that the default-route-metric-penalty based on connectivity
checking applies to all /0 routes, even these static routes. Be they
added due to DHCP, "ipv4.gateway", "ipv4.routes" or "wireguard.peer-routes".
I wonder whether doing that unconditionally is desirable, and maybe
there should be a way to opt-out/opt-in for the entire profile or even
per-routes.
https://bugzilla.redhat.com/show_bug.cgi?id=1714438
2019-08-03 08:15:50 +02:00
|
|
|
result = build_route (info,
|
|
|
|
|
property_name,
|
2015-02-18 18:59:35 +01:00
|
|
|
ipv6 ? AF_INET6 : AF_INET,
|
all: allow configuring default-routes as manual, static routes
Up until now, a default-route (with prefix length zero) could not
be configured directly. The user could only set ipv4.gateway,
ipv4.never-default, ipv4.route-metric and ipv4.route-table to influence
the setting of the default-route (respectively for IPv6).
That is a problematic limitation. For one, whether a route has prefix
length zero or non-zero does not make a fundamental difference. Also,
it makes it impossible to configure all the routing attributes that one can
configure otherwise for static routes. For example, the default-route could
not be configured as "onlink", could not have a special MTU, nor could it be
placed in a dedicated routing table.
Fix that by lifting the restriction. Note that "ipv4.never-default" does
not apply to /0 manual routes. Likewise, the previous manners of
configuring default-routes ("ipv4.gateway") don't conflict with manual
default-routes.
Server-side this all the pieces are already in place to accept a default-route
as static routes. This was done by earlier commits like 5c299454b49b
('core: rework tracking of gateway/default-route in ip-config').
A long time ago, NMIPRoute would assert that the prefix length is
positive. That was relaxed by commit a2e93f2de4ac ('libnm: allow zero
prefix length for NMIPRoute'), already before 1.0.0. Using libnm from
before 1.0.0 would result in assertion failures.
Note that the default-route-metric-penalty based on connectivity
checking applies to all /0 routes, even these static routes. Be they
added due to DHCP, "ipv4.gateway", "ipv4.routes" or "wireguard.peer-routes".
I wonder whether doing that unconditionally is desirable, and maybe
there should be a way to opt-out/opt-in for the entire profile or even
per-routes.
https://bugzilla.redhat.com/show_bug.cgi?id=1714438
2019-08-03 08:15:50 +02:00
|
|
|
address_str,
|
|
|
|
|
plen,
|
|
|
|
|
gateway_str,
|
|
|
|
|
metric_str);
|
2015-02-18 19:59:28 +01:00
|
|
|
} else {
|
all: allow configuring default-routes as manual, static routes
Up until now, a default-route (with prefix length zero) could not
be configured directly. The user could only set ipv4.gateway,
ipv4.never-default, ipv4.route-metric and ipv4.route-table to influence
the setting of the default-route (respectively for IPv6).
That is a problematic limitation. For one, whether a route has prefix
length zero or non-zero does not make a fundamental difference. Also,
it makes it impossible to configure all the routing attributes that one can
configure otherwise for static routes. For example, the default-route could
not be configured as "onlink", could not have a special MTU, nor could it be
placed in a dedicated routing table.
Fix that by lifting the restriction. Note that "ipv4.never-default" does
not apply to /0 manual routes. Likewise, the previous manners of
configuring default-routes ("ipv4.gateway") don't conflict with manual
default-routes.
Server-side this all the pieces are already in place to accept a default-route
as static routes. This was done by earlier commits like 5c299454b49b
('core: rework tracking of gateway/default-route in ip-config').
A long time ago, NMIPRoute would assert that the prefix length is
positive. That was relaxed by commit a2e93f2de4ac ('libnm: allow zero
prefix length for NMIPRoute'), already before 1.0.0. Using libnm from
before 1.0.0 would result in assertion failures.
Note that the default-route-metric-penalty based on connectivity
checking applies to all /0 routes, even these static routes. Be they
added due to DHCP, "ipv4.gateway", "ipv4.routes" or "wireguard.peer-routes".
I wonder whether doing that unconditionally is desirable, and maybe
there should be a way to opt-out/opt-in for the entire profile or even
per-routes.
https://bugzilla.redhat.com/show_bug.cgi?id=1714438
2019-08-03 08:15:50 +02:00
|
|
|
result = build_address (info,
|
|
|
|
|
ipv6 ? AF_INET6 : AF_INET,
|
|
|
|
|
address_str,
|
|
|
|
|
plen,
|
|
|
|
|
property_name);
|
2015-02-18 18:59:35 +01:00
|
|
|
if (!result)
|
|
|
|
|
return NULL;
|
2018-04-13 14:07:33 +02:00
|
|
|
if (gateway_str)
|
|
|
|
|
NM_SET_OUT (out_gateway, g_strdup (gateway_str));
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
#undef VALUE_ORIG
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
2017-02-16 00:14:25 +01:00
|
|
|
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));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-13 14:54:23 +02:00
|
|
|
typedef struct {
|
|
|
|
|
const char *s_key;
|
|
|
|
|
gint32 key_idx;
|
|
|
|
|
gint8 key_type;
|
2019-03-20 19:09:19 +01:00
|
|
|
} BuildListData;
|
|
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
|
BUILD_LIST_TYPE_ADDRESSES,
|
|
|
|
|
BUILD_LIST_TYPE_ROUTES,
|
2019-03-14 12:04:21 +01:00
|
|
|
BUILD_LIST_TYPE_ROUTING_RULES,
|
2019-03-20 19:09:19 +01:00
|
|
|
} BuildListType;
|
2018-04-13 14:54:23 +02:00
|
|
|
|
|
|
|
|
static int
|
2019-03-20 19:09:19 +01:00
|
|
|
_build_list_data_cmp (gconstpointer p_a, gconstpointer p_b, gpointer user_data)
|
2018-04-13 14:54:23 +02:00
|
|
|
{
|
2019-03-20 19:09:19 +01:00
|
|
|
const BuildListData *a = p_a;
|
|
|
|
|
const BuildListData *b = p_b;
|
2018-04-13 14:54:23 +02:00
|
|
|
|
|
|
|
|
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
|
2019-03-20 19:09:19 +01:00
|
|
|
_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)
|
2018-04-13 14:54:23 +02:00
|
|
|
{
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-20 19:09:19 +01:00
|
|
|
#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)
|
2018-04-13 14:54:23 +02:00
|
|
|
|
2019-03-20 19:09:19 +01:00
|
|
|
static BuildListData *
|
|
|
|
|
_build_list_create (GKeyFile *keyfile,
|
|
|
|
|
const char *group_name,
|
|
|
|
|
BuildListType build_list_type,
|
|
|
|
|
gsize *out_build_list_len,
|
|
|
|
|
char ***out_keys_strv)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
2018-04-13 14:54:23 +02:00
|
|
|
gs_strfreev char **keys = NULL;
|
2019-01-02 09:09:37 +01:00
|
|
|
gsize i_keys, n_keys;
|
2019-03-20 19:09:19 +01:00
|
|
|
gs_free BuildListData *build_list = NULL;
|
|
|
|
|
gsize build_list_len = 0;
|
2018-04-13 14:54:23 +02:00
|
|
|
|
2019-03-20 19:09:19 +01:00
|
|
|
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);
|
2019-01-02 09:09:37 +01:00
|
|
|
if (n_keys == 0)
|
2019-03-20 19:09:19 +01:00
|
|
|
return NULL;
|
2018-04-13 14:54:23 +02:00
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
for (i_keys = 0; i_keys < n_keys; i_keys++) {
|
2018-04-13 14:54:23 +02:00
|
|
|
const char *s_key = keys[i_keys];
|
|
|
|
|
gint32 key_idx;
|
2019-04-04 15:22:30 +02:00
|
|
|
gint8 key_type = 0;
|
2018-04-13 14:54:23 +02:00
|
|
|
|
2019-03-20 19:09:19 +01:00
|
|
|
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;
|
2019-03-14 12:04:21 +01:00
|
|
|
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;
|
2019-03-20 19:09:19 +01:00
|
|
|
default:
|
|
|
|
|
nm_assert_not_reached ();
|
|
|
|
|
break;
|
|
|
|
|
}
|
2018-04-13 14:54:23 +02:00
|
|
|
|
|
|
|
|
if (G_UNLIKELY (!build_list))
|
2019-03-20 19:09:19 +01:00
|
|
|
build_list = g_new (BuildListData, n_keys - i_keys);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-03-20 19:09:19 +01:00
|
|
|
build_list[build_list_len++] = (BuildListData) {
|
|
|
|
|
.s_key = s_key,
|
|
|
|
|
.key_idx = key_idx,
|
|
|
|
|
.key_type = key_type,
|
|
|
|
|
};
|
2018-04-13 14:54:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (build_list_len == 0)
|
2019-03-20 19:09:19 +01:00
|
|
|
return NULL;
|
2018-04-13 14:54:23 +02:00
|
|
|
|
2019-03-20 19:09:19 +01:00
|
|
|
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;
|
2018-04-13 14:54:23 +02:00
|
|
|
|
|
|
|
|
list = g_ptr_array_new_with_free_func (is_routes
|
2018-04-13 14:07:33 +02:00
|
|
|
? (GDestroyNotify) nm_ip_route_unref
|
|
|
|
|
: (GDestroyNotify) nm_ip_address_unref);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2018-04-13 14:54:23 +02:00
|
|
|
for (i_build_list = 0; i_build_list < build_list_len; i_build_list++) {
|
2019-03-20 19:09:19 +01:00
|
|
|
const char *s_key;
|
2018-04-13 14:54:23 +02:00
|
|
|
gpointer item;
|
|
|
|
|
|
2019-03-20 19:09:19 +01:00
|
|
|
if (_build_list_data_is_shadowed (build_list, build_list_len, i_build_list))
|
2018-04-13 14:54:23 +02:00
|
|
|
continue;
|
2015-02-18 18:59:35 +01:00
|
|
|
|
2019-03-20 19:09:19 +01:00
|
|
|
s_key = build_list[i_build_list].s_key;
|
2018-04-13 14:54:23 +02:00
|
|
|
item = read_one_ip_address_or_route (info,
|
|
|
|
|
setting_key,
|
|
|
|
|
setting_name,
|
2019-03-20 19:09:19 +01:00
|
|
|
s_key,
|
2018-04-13 14:54:23 +02:00
|
|
|
is_ipv6,
|
|
|
|
|
is_routes,
|
|
|
|
|
gateway ? NULL : &gateway,
|
|
|
|
|
setting);
|
|
|
|
|
if (item && is_routes) {
|
2017-02-16 00:14:25 +01:00
|
|
|
char options_key[128];
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-03-20 19:09:19 +01:00
|
|
|
nm_sprintf_buf (options_key, "%s_options", s_key);
|
2018-04-13 14:54:23 +02:00
|
|
|
fill_route_attributes (info->keyfile,
|
|
|
|
|
item,
|
|
|
|
|
setting_name,
|
|
|
|
|
options_key,
|
|
|
|
|
is_ipv6 ? AF_INET6 : AF_INET);
|
|
|
|
|
}
|
2017-02-16 00:14:25 +01:00
|
|
|
|
2018-04-13 14:54:23 +02:00
|
|
|
if (info->error)
|
|
|
|
|
return;
|
2018-04-13 14:07:33 +02:00
|
|
|
|
2018-04-13 14:54:23 +02:00
|
|
|
if (item)
|
|
|
|
|
g_ptr_array_add (list, item);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (list->len >= 1)
|
2018-04-13 14:54:23 +02:00
|
|
|
g_object_set (setting, setting_key, list, NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2018-04-13 14:07:33 +02:00
|
|
|
if (gateway)
|
2015-02-18 19:59:28 +01:00
|
|
|
g_object_set (setting, "gateway", gateway, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
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) {
|
|
|
|
|
handle_warn (info, property_info->name, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("invalid value for \"%s\": %s"),
|
|
|
|
|
build_list[i_build_list].s_key,
|
|
|
|
|
local->message);
|
|
|
|
|
if (info->error)
|
|
|
|
|
return;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_setting_ip_config_add_routing_rule (NM_SETTING_IP_CONFIG (setting), rule);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
static void
|
2018-04-13 16:43:43 +02:00
|
|
|
ip_dns_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
2018-04-13 16:36:41 +02:00
|
|
|
int addr_family;
|
2018-04-13 16:23:13 +02:00
|
|
|
gs_strfreev char **list = NULL;
|
2018-04-13 16:36:41 +02:00
|
|
|
gsize i, n, length;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2018-04-13 16:36:41 +02:00
|
|
|
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)
|
2015-02-18 19:59:28 +01:00
|
|
|
return;
|
|
|
|
|
|
2018-04-13 16:36:41 +02:00
|
|
|
addr_family = NM_IS_SETTING_IP4_CONFIG (setting) ? AF_INET : AF_INET6;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2018-04-13 16:36:41 +02:00
|
|
|
n = 0;
|
|
|
|
|
for (i = 0; i < length; i++) {
|
2018-04-13 16:43:43 +02:00
|
|
|
NMIPAddr addr;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2018-04-13 16:36:41 +02:00
|
|
|
if (inet_pton (addr_family, list[i], &addr) <= 0) {
|
2015-02-18 18:59:35 +01:00
|
|
|
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
2018-04-13 16:43:43 +02:00
|
|
|
_("ignoring invalid DNS server IPv%c address '%s'"),
|
|
|
|
|
nm_utils_addr_family_to_char (addr_family),
|
2018-04-13 16:36:41 +02:00
|
|
|
list[i])) {
|
|
|
|
|
do {
|
|
|
|
|
nm_clear_g_free (&list[i]);
|
|
|
|
|
} while (++i < length);
|
2015-02-18 18:59:35 +01:00
|
|
|
return;
|
|
|
|
|
}
|
2018-04-13 16:36:41 +02:00
|
|
|
nm_clear_g_free (&list[i]);
|
2015-02-18 19:59:28 +01:00
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:36:41 +02:00
|
|
|
if (n != i)
|
|
|
|
|
list[n] = g_steal_pointer (&list[i]);
|
|
|
|
|
n++;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-13 16:36:41 +02:00
|
|
|
g_object_set (setting, key, list, NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
2015-10-26 18:00:03 +01:00
|
|
|
static void
|
|
|
|
|
ip6_addr_gen_mode_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
|
|
|
|
{
|
2015-10-26 18:21:18 +01:00
|
|
|
NMSettingIP6ConfigAddrGenMode addr_gen_mode;
|
2015-10-26 18:00:03 +01:00
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
2015-10-26 18:21:18 +01:00
|
|
|
gs_free char *s = NULL;
|
2015-10-26 18:00:03 +01:00
|
|
|
|
|
|
|
|
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,
|
2015-10-26 18:21:18 +01:00
|
|
|
(int *) &addr_gen_mode, NULL)) {
|
2015-10-26 18:00:03 +01:00
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
2015-10-26 18:21:18 +01:00
|
|
|
_("invalid option '%s', use one of [%s]"),
|
|
|
|
|
s, "eui64,stable-privacy");
|
|
|
|
|
return;
|
2015-10-26 18:00:03 +01:00
|
|
|
}
|
2015-10-26 18:21:18 +01:00
|
|
|
} else
|
|
|
|
|
addr_gen_mode = NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE_EUI64;
|
2015-10-26 18:00:03 +01:00
|
|
|
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
g_object_set (G_OBJECT (setting), key, (int) addr_gen_mode, NULL);
|
2015-10-26 18:00:03 +01:00
|
|
|
}
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
static void
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
mac_address_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key, gsize enforce_length, gboolean cloned_mac_addr)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
|
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
gs_free char *tmp_string = NULL;
|
|
|
|
|
const char *p, *mac_str;
|
|
|
|
|
gs_free guint8 *buf_arr = NULL;
|
2016-07-01 09:42:50 +02:00
|
|
|
guint buf_len = 0;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
if (tmp_string && tmp_string[0]) {
|
|
|
|
|
/* Look for enough ':' characters to signify a MAC address */
|
|
|
|
|
guint i = 0;
|
|
|
|
|
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
p = tmp_string;
|
2015-02-18 19:59:28 +01:00
|
|
|
while (*p) {
|
|
|
|
|
if (*p == ':')
|
|
|
|
|
i++;
|
|
|
|
|
p++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (enforce_length == 0 || enforce_length == i+1) {
|
|
|
|
|
/* If we found enough it's probably a string-format MAC address */
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
buf_len = i + 1;
|
|
|
|
|
buf_arr = g_new (guint8, buf_len);
|
|
|
|
|
if (!nm_utils_hwaddr_aton (tmp_string, buf_arr, buf_len))
|
|
|
|
|
g_clear_pointer (&buf_arr, g_free);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
g_clear_pointer (&tmp_string, g_free);
|
|
|
|
|
|
|
|
|
|
if (!buf_arr) {
|
|
|
|
|
gs_free int *tmp_list = NULL;
|
2019-01-02 09:09:37 +01:00
|
|
|
gsize length;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
/* Old format; list of ints */
|
2015-02-18 18:59:35 +01:00
|
|
|
tmp_list = nm_keyfile_plugin_kf_get_integer_list (info->keyfile, setting_name, key, &length, NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
if (length > 0 && (enforce_length == 0 || enforce_length == length)) {
|
|
|
|
|
gsize i;
|
|
|
|
|
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
buf_len = length;
|
|
|
|
|
buf_arr = g_new (guint8, buf_len);
|
2015-02-18 19:59:28 +01:00
|
|
|
for (i = 0; i < length; i++) {
|
|
|
|
|
int val = tmp_list[i];
|
|
|
|
|
|
|
|
|
|
if (val < 0 || val > 255) {
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
|
|
|
|
|
val);
|
|
|
|
|
return;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
2017-05-06 13:33:21 +02:00
|
|
|
buf_arr[i] = (guint8) val;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
if (!buf_arr) {
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring invalid MAC address"));
|
2015-02-18 19:59:28 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
tmp_string = nm_utils_hwaddr_ntoa (buf_arr, buf_len);
|
|
|
|
|
mac_str = tmp_string;
|
|
|
|
|
|
|
|
|
|
out:
|
2015-02-18 19:59:28 +01:00
|
|
|
g_object_set (setting, key, mac_str, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-02-18 18:59:35 +01:00
|
|
|
mac_address_parser_ETHER (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
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);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-02-18 18:59:35 +01:00
|
|
|
mac_address_parser_INFINIBAND (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
device: extend MAC address handling including randomization for ethernet and wifi
Extend the "ethernet.cloned-mac-address" and "wifi.cloned-mac-address"
settings. Instead of specifying an explicit MAC address, the additional
special values "permanent", "preserve", "random", "random-bia", "stable" and
"stable-bia" are supported.
"permanent" means to use the permanent hardware address. Previously that
was the default if no explict cloned-mac-address was set. The default is
thus still "permanent", but it can be overwritten by global
configuration.
"preserve" means not to configure the MAC address when activating the
device. That was actually the default behavior before introducing MAC
address handling with commit 1b49f941a69af910b0e68530be7339e8053068e5.
"random" and "random-bia" use a randomized MAC address for each
connection. "stable" and "stable-bia" use a generated, stable
address based on some token. The "bia" suffix says to generate a
burned-in address. The stable method by default uses as token the
connection UUID, but the token can be explicitly choosen via
"stable:<TOKEN>" and "stable-bia:<TOKEN>".
On a D-Bus level, the "cloned-mac-address" is a bytestring and thus
cannot express the new forms. It is replaced by the new
"assigned-mac-address" field. For the GObject property, libnm's API,
nmcli, keyfile, etc. the old name "cloned-mac-address" is still used.
Deprecating the old field seems more complicated then just extending
the use of the existing "cloned-mac-address" field, although the name
doesn't match well with the extended meaning.
There is some overlap with the "wifi.mac-address-randomization" setting.
https://bugzilla.gnome.org/show_bug.cgi?id=705545
https://bugzilla.gnome.org/show_bug.cgi?id=708820
https://bugzilla.gnome.org/show_bug.cgi?id=758301
2016-05-24 15:57:16 +02:00
|
|
|
mac_address_parser (info, setting, key, INFINIBAND_ALEN, FALSE);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
read_hash_of_string (GKeyFile *file, NMSetting *setting, const char *key)
|
|
|
|
|
{
|
2017-05-04 14:42:00 +02:00
|
|
|
gs_strfreev char **keys = NULL;
|
|
|
|
|
const char *const*iter;
|
2015-02-18 19:59:28 +01:00
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
2017-05-04 14:50:07 +02:00
|
|
|
gboolean is_vpn;
|
2019-01-02 09:09:37 +01:00
|
|
|
gsize n_keys;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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)));
|
|
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
keys = nm_keyfile_plugin_kf_get_keys (file, setting_name, &n_keys, NULL);
|
|
|
|
|
if (n_keys == 0)
|
2015-02-18 19:59:28 +01:00
|
|
|
return;
|
|
|
|
|
|
2017-05-04 14:50:07 +02:00
|
|
|
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 {
|
2019-01-02 09:09:37 +01:00
|
|
|
if (!nm_streq (name, "interface-name"))
|
2017-05-04 14:50:07 +02:00
|
|
|
nm_setting_bond_add_option (NM_SETTING_BOND (setting), name, value);
|
|
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
2019-05-24 15:01:21 +02:00
|
|
|
openconnect_fix_secret_flags (setting);
|
2017-05-04 14:50:07 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (NM_IS_SETTING_USER (setting)) {
|
|
|
|
|
gs_unref_hashtable GHashTable *data = NULL;
|
|
|
|
|
|
2017-11-15 16:06:43 +01:00
|
|
|
data = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_free);
|
2017-05-04 14:50:07 +02:00
|
|
|
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);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
2017-05-04 14:50:07 +02:00
|
|
|
g_object_set (setting, NM_SETTING_USER_DATA, data, NULL);
|
2019-04-24 12:03:10 +02:00
|
|
|
return;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
2019-04-24 12:03:10 +02:00
|
|
|
|
|
|
|
|
nm_assert_not_reached ();
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
static gsize
|
2015-02-18 19:59:28 +01:00
|
|
|
unescape_semicolons (char *str)
|
|
|
|
|
{
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
gsize i, j;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
for (i = 0, j = 0; str[i]; ) {
|
|
|
|
|
if (str[i] == '\\' && str[i+1] == ';')
|
|
|
|
|
i++;
|
|
|
|
|
str[j++] = str[i++];;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
2018-09-02 14:54:11 +02:00
|
|
|
nm_explicit_bzero (&str[j], i - j);
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
return j;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GBytes *
|
2015-02-18 18:59:35 +01:00
|
|
|
get_bytes (KeyfileReaderInfo *info,
|
2015-02-18 19:59:28 +01:00
|
|
|
const char *setting_name,
|
|
|
|
|
const char *key,
|
|
|
|
|
gboolean zero_terminate,
|
|
|
|
|
gboolean unescape_semicolon)
|
|
|
|
|
{
|
2018-09-02 14:54:11 +02:00
|
|
|
nm_auto_free_secret char *tmp_string = NULL;
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
gboolean may_be_int_list = TRUE;
|
2015-02-18 19:59:28 +01:00
|
|
|
gsize length;
|
2018-09-02 14:54:11 +02:00
|
|
|
GBytes *result;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
/* New format: just a string
|
|
|
|
|
* Old format: integer list; e.g. 11;25;38;
|
|
|
|
|
*/
|
2015-02-18 18:59:35 +01:00
|
|
|
tmp_string = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
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.
|
|
|
|
|
*/
|
2018-09-02 14:33:34 +02:00
|
|
|
return g_bytes_new_static ("", 0);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
for (length = 0; tmp_string[length]; length++) {
|
|
|
|
|
const char ch = tmp_string[length];
|
2015-02-18 18:59:35 +01:00
|
|
|
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
if ( !g_ascii_isspace (ch)
|
|
|
|
|
&& !g_ascii_isdigit (ch)
|
|
|
|
|
&& ch != ';') {
|
|
|
|
|
may_be_int_list = FALSE;
|
|
|
|
|
length += strlen (&tmp_string[length]);
|
|
|
|
|
break;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Try to parse the string as a integer list. */
|
|
|
|
|
if (may_be_int_list && length > 0) {
|
2018-09-02 14:54:11 +02:00
|
|
|
nm_auto_free_secret_buf NMSecretBuf *bin = NULL;
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
const char *const s = tmp_string;
|
|
|
|
|
gsize i, d;
|
|
|
|
|
|
2018-09-02 14:54:11 +02:00
|
|
|
bin = nm_secret_buf_new (length / 2 + 3);
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
|
|
|
|
|
#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++;
|
2015-02-18 18:59:35 +01:00
|
|
|
}
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
}
|
|
|
|
|
if (n > 255) {
|
|
|
|
|
d = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
2018-09-02 14:54:11 +02:00
|
|
|
nm_assert (d < bin->len);
|
|
|
|
|
bin->bin[d++] = n;
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
|
|
|
|
|
/* 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
|
2018-09-02 14:54:11 +02:00
|
|
|
* 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.
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
*
|
2018-09-02 14:54:11 +02:00
|
|
|
* 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);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
keyfile: refactor parsing in get_bytes() to replace regex
No longer use a regex to pre-evaluate whether @tmp_string looks
like a integer list. Instead, parse the integer list ourself.
First, drop the nm_keyfile_plugin_kf_has_key() check.
Note that this merely verifies that such a key exits. It's rather
pointless, because get_bytes() is only called for existing keys.
Still, in case the check would actually yield differing results
from the following nm_keyfile_plugin_kf_get_string(), we want to
act depending on what nm_keyfile_plugin_kf_get_string() returns.
Note that nm_keyfile_plugin_kf_get_string() looks up the key, alternatively
fallback to the settings alias. Then, GKeyFile would parse the raw keyfile
value and return it as string.
Previously, we would first decide whether @tmp_string look like a integer list
to decide wether to parse it via nm_keyfile_plugin_kf_get_integer_list().
But note that it's not clear that nm_keyfile_plugin_kf_get_integer_list()
operates on the same string as nm_keyfile_plugin_kf_get_string().
Could it decide to return different strings based on whether such
a key exists?
E.g. when setting "802-11-wireless.ssid=foo" and "wifi.ssid=60;" they
clearly would yield differing results: "foo" vs. [60].
Ok, probably it is not an issue because we call first
nm_keyfile_plugin_kf_get_string(), decide whether it looks like a
integer list, and return "foo" right away.
This is still confusing and relyies on knowledge about how the value
is encoded as string-list.
Likewise, could our regex determine that the value looks like a integer
list but then the integer list is unable to parse it? Certainly that can
happen for values larger then 255.
Just make it consistent. Get *one* @tmp_string. Try (manually) to
interpret it as string list, or bail using it as plain text.
Also, allow returning empty GBytes arrays. If somebody specifies an
empty list, it's empty. Not NULL.
2016-12-21 16:27:24 +01:00
|
|
|
/* Handle as a simple string (ie, new format) */
|
|
|
|
|
if (unescape_semicolon)
|
|
|
|
|
length = unescape_semicolons (tmp_string);
|
|
|
|
|
if (zero_terminate)
|
|
|
|
|
length++;
|
|
|
|
|
if (length == 0)
|
2015-02-18 19:59:28 +01:00
|
|
|
return NULL;
|
2018-09-02 14:54:11 +02:00
|
|
|
|
|
|
|
|
result = g_bytes_new_with_free_func (tmp_string,
|
|
|
|
|
length,
|
|
|
|
|
(GDestroyNotify) nm_free_secret,
|
|
|
|
|
tmp_string);
|
|
|
|
|
tmp_string = NULL;
|
|
|
|
|
return result;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-02-18 18:59:35 +01:00
|
|
|
ssid_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
|
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
|
|
|
|
GBytes *bytes;
|
|
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
bytes = get_bytes (info, setting_name, key, FALSE, TRUE);
|
2015-02-18 19:59:28 +01:00
|
|
|
if (bytes) {
|
|
|
|
|
g_object_set (setting, key, bytes, NULL);
|
|
|
|
|
g_bytes_unref (bytes);
|
2015-02-18 18:59:35 +01:00
|
|
|
} else if (!info->error) {
|
|
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring invalid SSID"));
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2015-02-18 18:59:35 +01:00
|
|
|
password_raw_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
|
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
|
|
|
|
GBytes *bytes;
|
|
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
bytes = get_bytes (info, setting_name, key, FALSE, TRUE);
|
2015-02-18 19:59:28 +01:00
|
|
|
if (bytes) {
|
|
|
|
|
g_object_set (setting, key, bytes, NULL);
|
|
|
|
|
g_bytes_unref (bytes);
|
2015-02-18 18:59:35 +01:00
|
|
|
} else if (!info->error) {
|
|
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring invalid raw password"));
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static char *
|
2015-02-18 18:59:35 +01:00
|
|
|
get_cert_path (const char *base_dir, const guint8 *cert_path, gsize cert_path_len)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
|
|
|
|
const char *base;
|
2015-02-18 18:59:35 +01:00
|
|
|
char *p = NULL, *path, *tmp;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
g_return_val_if_fail (base_dir != NULL, NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
g_return_val_if_fail (cert_path != NULL, NULL);
|
|
|
|
|
|
2018-09-02 14:54:11 +02:00
|
|
|
path = g_strndup ((char *) cert_path, cert_path_len);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
if (path[0] == '/')
|
|
|
|
|
return path;
|
|
|
|
|
|
2018-09-02 14:54:11 +02:00
|
|
|
base = path;
|
2015-02-18 19:59:28 +01:00
|
|
|
p = strrchr (path, '/');
|
|
|
|
|
if (p)
|
|
|
|
|
base = p + 1;
|
|
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
tmp = g_build_path ("/", base_dir, base, NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
char *
|
|
|
|
|
nm_keyfile_detect_unqualified_path_scheme (const char *base_dir,
|
|
|
|
|
gconstpointer pdata,
|
|
|
|
|
gsize data_len,
|
|
|
|
|
gboolean consider_exists,
|
|
|
|
|
gboolean *out_exists)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
const char *data = pdata;
|
|
|
|
|
gboolean exists = FALSE;
|
2015-02-18 19:59:28 +01:00
|
|
|
gsize validate_len;
|
2018-08-30 15:47:15 +02:00
|
|
|
gsize path_len, pathuri_len;
|
2018-04-16 12:54:04 +02:00
|
|
|
gs_free char *path = NULL;
|
2018-08-30 15:47:15 +02:00
|
|
|
gs_free char *pathuri = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
g_return_val_if_fail (base_dir && base_dir[0] == '/', NULL);
|
|
|
|
|
|
|
|
|
|
if (!pdata)
|
|
|
|
|
return NULL;
|
|
|
|
|
if (data_len == -1)
|
|
|
|
|
data_len = strlen (data);
|
2015-02-18 19:59:28 +01:00
|
|
|
if (data_len > 500 || data_len < 1)
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
/* 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)
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
|
*/
|
|
|
|
|
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
path = get_cert_path (base_dir, (const guint8 *) data, data_len);
|
settings/keyfile: check whether profile can be re-read before writing to disk and fail
First of all, keyfile writer (and reader) are supposed to be able to store
every profile to disk and re-read a valid profile back. Note that the profile
might be modified in the process, for example, blob certificates are written
to a file. So, the result might no be exactly the same, but it must still be
valid (and should only diverge in expected ways from the original, like mangled
certificates).
Previously, we would re-read the profile after writing to disk. If that failed,
we would only fail an assertion but otherwise proceeed. It is a bug
after all. However, it's bad to check only after writing to file,
because it results in a unreadable profile on disk, and in the first
moment it appears that noting went wrong. Instead, we should fail early.
Note that nms_keyfile_reader_from_keyfile() must entirely operate on the in-memory
representation of the keyfile. It must not actually access any files on disk. Hence,
moving this check before writing the profile must work. Otherwise, that would be
a separate bug. Actually, keyfile reader and writer violate this. I
added FIXME comments for that. But it doesn't interfere with this
patch.
2019-08-27 11:06:45 +02:00
|
|
|
|
|
|
|
|
/* 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. */
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
if ( !memchr (data, '/', data_len)
|
|
|
|
|
&& !has_cert_ext (path)) {
|
|
|
|
|
if (!consider_exists)
|
2018-04-16 12:54:04 +02:00
|
|
|
return NULL;
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
exists = g_file_test (path, G_FILE_TEST_EXISTS);
|
|
|
|
|
if (!exists)
|
2018-04-16 12:54:04 +02:00
|
|
|
return NULL;
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
} else if (out_exists)
|
|
|
|
|
exists = g_file_test (path, G_FILE_TEST_EXISTS);
|
|
|
|
|
|
2018-04-16 12:54:04 +02:00
|
|
|
/* 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. */
|
2018-08-30 15:47:15 +02:00
|
|
|
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)
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
return NULL;
|
2018-04-16 12:54:04 +02:00
|
|
|
|
|
|
|
|
NM_SET_OUT (out_exists, exists);
|
2018-08-30 15:47:15 +02:00
|
|
|
return g_steal_pointer (&pathuri);
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
}
|
|
|
|
|
|
2018-02-21 19:11:05 +01:00
|
|
|
#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); \
|
|
|
|
|
})
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
static void
|
2015-02-18 18:59:35 +01:00
|
|
|
cert_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
|
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
gs_unref_bytes GBytes *bytes = NULL;
|
2018-02-21 18:57:13 +01:00
|
|
|
const char *bin = NULL;
|
|
|
|
|
gsize bin_len = 0;
|
2018-02-21 19:11:05 +01:00
|
|
|
char *path;
|
|
|
|
|
gboolean path_exists;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
bytes = get_bytes (info, setting_name, key, TRUE, FALSE);
|
2018-02-21 18:57:13 +01:00
|
|
|
if (bytes)
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
bin = g_bytes_get_data (bytes, &bin_len);
|
2018-02-21 18:57:13 +01:00
|
|
|
if (bin_len == 0) {
|
|
|
|
|
if (!info->error) {
|
keyfile: support writing certificates as blob inside the keyfile
keyfile should become our main import/export format. It is desirable,
that a keyfile can contain every aspect of a connection.
For blob certificates, the writer in core daemon would always write
them to a file and convert the scheme to path.
This behavior is not great for a (hyptetical) `nmcli connection export`
command because it would have to export them somehow outside of keyfile,
e.g. by writing them to temporary files.
Instead, if the write handler does not handle a certificate, use a
default implementation in nm_keyfile_write() which adds the blob inside
the keyfile.
Interestingly, keyfile reader already supported reading certificate
blobs. But this legacy format accepts the blob as arbitrary
binary without marking the format and without scheme prefix.
Instead of writing the binary data directly, write it with a new
uri scheme "data:;base64," and encode it in base64.
Also go through some lengths to make sure that whatever path
keyfile plugin writes, can be read back again. That is, because
keyfile writer preferably writes relative paths without prefix.
Add nm_keyfile_detect_unqualified_path_scheme() to encapsulate
the detection of pathnames without file:// prefix and use it to
check whether the path name must be fully qualified.
2015-02-24 22:22:14 +01:00
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
2018-02-21 18:57:13 +01:00
|
|
|
_("invalid key/cert value"));
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2018-02-21 19:11:05 +01:00
|
|
|
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, 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;
|
|
|
|
|
}
|
|
|
|
|
|
settings/keyfile: check whether profile can be re-read before writing to disk and fail
First of all, keyfile writer (and reader) are supposed to be able to store
every profile to disk and re-read a valid profile back. Note that the profile
might be modified in the process, for example, blob certificates are written
to a file. So, the result might no be exactly the same, but it must still be
valid (and should only diverge in expected ways from the original, like mangled
certificates).
Previously, we would re-read the profile after writing to disk. If that failed,
we would only fail an assertion but otherwise proceeed. It is a bug
after all. However, it's bad to check only after writing to file,
because it results in a unreadable profile on disk, and in the first
moment it appears that noting went wrong. Instead, we should fail early.
Note that nms_keyfile_reader_from_keyfile() must entirely operate on the in-memory
representation of the keyfile. It must not actually access any files on disk. Hence,
moving this check before writing the profile must work. Otherwise, that would be
a separate bug. Actually, keyfile reader and writer violate this. I
added FIXME comments for that. But it doesn't interfere with this
patch.
2019-08-27 11:06:45 +02:00
|
|
|
/* 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). */
|
2018-02-21 19:11:05 +01:00
|
|
|
if (!g_file_test (path2, G_FILE_TEST_EXISTS)) {
|
|
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE,
|
|
|
|
|
_("certificate or key file '%s' does not exist"),
|
|
|
|
|
path2);
|
|
|
|
|
}
|
2018-02-21 18:57:13 +01:00
|
|
|
return;
|
2018-02-21 19:11:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("invalid PKCS#11 URI \"%s\""), bin);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_object_set (setting, key, bytes, NULL);
|
2018-02-21 18:57:13 +01:00
|
|
|
return;
|
2018-02-21 19:11:05 +01:00
|
|
|
}
|
2018-02-21 18:57:13 +01:00
|
|
|
|
2018-02-21 19:11:05 +01:00
|
|
|
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, 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, 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);
|
2018-02-21 18:57:13 +01:00
|
|
|
return;
|
2018-02-21 19:11:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 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, NM_KEYFILE_WARN_SEVERITY_INFO_MISSING_FILE,
|
|
|
|
|
_("certificate or key file '%s' does not exist"),
|
|
|
|
|
path);
|
|
|
|
|
}
|
2018-02-21 18:57:13 +01:00
|
|
|
return;
|
2018-02-21 19:11:05 +01:00
|
|
|
}
|
2018-02-21 18:57:13 +01:00
|
|
|
|
|
|
|
|
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. */
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
2018-02-21 18:57:13 +01:00
|
|
|
_("invalid key/cert value is not a valid blob"));
|
|
|
|
|
return;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
2018-02-21 18:57:13 +01:00
|
|
|
|
|
|
|
|
g_object_set (setting, key, bytes, NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
static void
|
2015-02-18 18:59:35 +01:00
|
|
|
parity_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
|
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
gs_free_error GError *err = NULL;
|
|
|
|
|
int parity;
|
|
|
|
|
gs_free char *tmp_str = NULL;
|
|
|
|
|
gint64 i64;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
/* 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).
|
|
|
|
|
*/
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
|
|
|
|
|
/* Finally, take the numeric value as is. */
|
|
|
|
|
parity = i64;
|
|
|
|
|
goto parity_good;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("invalid parity value '%s'"),
|
|
|
|
|
tmp_str ?: "");
|
|
|
|
|
return;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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 ( err->domain == G_KEY_FILE_ERROR
|
|
|
|
|
&& NM_IN_SET (err->code, G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
|
|
|
|
|
G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
|
|
|
|
|
/* ignore such errors. The key is not present. */
|
2015-02-18 19:59:28 +01:00
|
|
|
return;
|
|
|
|
|
}
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("invalid setting: %s"), err->message);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
2016-08-30 15:21:16 +02:00
|
|
|
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);
|
2019-05-22 19:51:35 +02:00
|
|
|
|
|
|
|
|
g_object_set (G_OBJECT (setting), key, conf, NULL);
|
|
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
if ( conf
|
2019-05-22 19:51:35 +02:00
|
|
|
&& !nm_setting_verify (setting, NULL, &error)) {
|
2016-08-30 15:21:16 +02:00
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring invalid team configuration: %s"),
|
|
|
|
|
error->message);
|
2019-05-22 19:51:35 +02:00
|
|
|
g_object_set (G_OBJECT (setting), key, NULL, NULL);
|
2016-08-30 15:21:16 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 17:33:40 +01:00
|
|
|
static void
|
|
|
|
|
bridge_vlan_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
|
|
|
|
{
|
|
|
|
|
gs_unref_ptrarray GPtrArray *vlans = NULL;
|
2019-04-15 15:14:33 +02:00
|
|
|
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])
|
2019-03-19 17:33:40 +01:00
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
vlans = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref);
|
|
|
|
|
|
2019-04-17 14:40:11 +02:00
|
|
|
strv = nm_utils_escaped_tokens_split (value, ",");
|
2019-04-15 15:14:33 +02:00
|
|
|
if (strv) {
|
|
|
|
|
for (iter = strv; *iter; iter++) {
|
|
|
|
|
vlan = nm_bridge_vlan_from_str (*iter, &local);
|
|
|
|
|
if (!vlan) {
|
|
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
"invalid bridge VLAN: %s", local->message);
|
|
|
|
|
g_clear_error (&local);
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
g_ptr_array_add (vlans, vlan);
|
2019-03-19 17:33:40 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
if (vlans->len > 0)
|
2019-03-19 17:33:40 +01:00
|
|
|
g_object_set (setting, key, vlans, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-18 17:16:50 +01:00
|
|
|
static void
|
|
|
|
|
qdisc_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
|
|
|
|
{
|
|
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
2019-03-19 18:38:31 +01:00
|
|
|
gs_unref_ptrarray GPtrArray *qdiscs = NULL;
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
gs_strfreev char **keys = NULL;
|
2017-11-18 17:16:50 +01:00
|
|
|
gsize n_keys = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
|
2019-01-02 09:09:37 +01:00
|
|
|
if (n_keys == 0)
|
2017-11-18 17:16:50 +01:00
|
|
|
return;
|
|
|
|
|
|
2019-03-19 18:38:31 +01:00
|
|
|
qdiscs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_qdisc_unref);
|
|
|
|
|
|
2017-11-18 17:16:50 +01:00
|
|
|
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], 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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-18 17:16:50 +01:00
|
|
|
static void
|
|
|
|
|
tfilter_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
|
|
|
|
|
{
|
|
|
|
|
const char *setting_name = nm_setting_get_name (setting);
|
2019-03-19 18:38:31 +01:00
|
|
|
gs_unref_ptrarray GPtrArray *tfilters = NULL;
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
gs_strfreev char **keys = NULL;
|
2017-11-18 17:16:50 +01:00
|
|
|
gsize n_keys = 0;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
|
2019-01-02 09:09:37 +01:00
|
|
|
if (n_keys == 0)
|
2017-11-18 17:16:50 +01:00
|
|
|
return;
|
|
|
|
|
|
2019-03-19 18:38:31 +01:00
|
|
|
tfilters = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_tfilter_unref);
|
|
|
|
|
|
2017-11-18 17:16:50 +01:00
|
|
|
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], 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);
|
|
|
|
|
}
|
|
|
|
|
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
/* 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,
|
2018-04-24 11:20:03 +02:00
|
|
|
alias ?: str);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
}
|
|
|
|
|
|
2018-05-25 12:05:24 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
static void
|
|
|
|
|
write_array_of_uint (GKeyFile *file,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
const char *key,
|
|
|
|
|
const GValue *value)
|
|
|
|
|
{
|
|
|
|
|
GArray *array;
|
|
|
|
|
guint i;
|
|
|
|
|
gs_free int *tmp_array = NULL;
|
|
|
|
|
|
|
|
|
|
array = (GArray *) g_value_get_boxed (value);
|
|
|
|
|
if (!array || !array->len)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (g_array_get_element_size (array) == sizeof (guint));
|
|
|
|
|
|
all: don't use gchar/gshort/gint/glong but C types
We commonly don't use the glib typedefs for char/short/int/long,
but their C types directly.
$ git grep '\<g\(char\|short\|int\|long\|float\|double\)\>' | wc -l
587
$ git grep '\<\(char\|short\|int\|long\|float\|double\)\>' | wc -l
21114
One could argue that using the glib typedefs is preferable in
public API (of our glib based libnm library) or where it clearly
is related to glib, like during
g_object_set (obj, PROPERTY, (gint) value, NULL);
However, that argument does not seem strong, because in practice we don't
follow that argument today, and seldomly use the glib typedefs.
Also, the style guide for this would be hard to formalize, because
"using them where clearly related to a glib" is a very loose suggestion.
Also note that glib typedefs will always just be typedefs of the
underlying C types. There is no danger of glib changing the meaning
of these typedefs (because that would be a major API break of glib).
A simple style guide is instead: don't use these typedefs.
No manual actions, I only ran the bash script:
FILES=($(git ls-files '*.[hc]'))
sed -i \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>\( [^ ]\)/\1\2/g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\> /\1 /g' \
-e 's/\<g\(char\|short\|int\|long\|float\|double\)\>/\1/g' \
"${FILES[@]}"
2018-07-11 07:40:19 +02:00
|
|
|
tmp_array = g_new (int, array->len);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
for (i = 0; i < array->len; i++) {
|
|
|
|
|
guint v = g_array_index (array, guint, i);
|
|
|
|
|
|
|
|
|
|
if (v > G_MAXINT)
|
|
|
|
|
g_return_if_reached ();
|
|
|
|
|
tmp_array[i] = (int) v;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_keyfile_plugin_kf_set_integer_list (file, nm_setting_get_name (setting), key, tmp_array, 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)
|
|
|
|
|
{
|
2019-01-02 09:09:37 +01:00
|
|
|
nm_auto_free_gstring GString *output = NULL;
|
|
|
|
|
int addr_family;
|
|
|
|
|
guint i;
|
|
|
|
|
const char *addr;
|
|
|
|
|
const char *gw;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
guint32 plen;
|
2019-01-02 09:09:37 +01:00
|
|
|
char key_name[64];
|
|
|
|
|
char *key_name_idx;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
|
|
|
|
if (!array->len)
|
|
|
|
|
return;
|
|
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
addr_family = nm_streq (setting_name, NM_SETTING_IP4_CONFIG_SETTING_NAME)
|
|
|
|
|
? AF_INET
|
|
|
|
|
: AF_INET6;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
|
|
|
|
strcpy (key_name, is_route ? "route" : "address");
|
|
|
|
|
key_name_idx = key_name + strlen (key_name);
|
|
|
|
|
|
|
|
|
|
output = g_string_sized_new (2*INET_ADDRSTRLEN + 10);
|
|
|
|
|
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);
|
2019-01-02 09:09:37 +01:00
|
|
|
gw = (i == 0)
|
|
|
|
|
? gateway
|
|
|
|
|
: NULL;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_string_set_size (output, 0);
|
|
|
|
|
g_string_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) {
|
2019-01-02 09:09:37 +01:00
|
|
|
if (addr_family == AF_INET)
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
gw = "0.0.0.0";
|
|
|
|
|
else
|
|
|
|
|
gw = "::";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_string_append_printf (output, ",%s", gw);
|
2019-01-02 09:09:37 +01:00
|
|
|
if ( is_route
|
|
|
|
|
&& metric != -1)
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
g_string_append_printf (output, ",%lu", (unsigned long) metric);
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
sprintf (key_name_idx, "%u", i + 1);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
nm_keyfile_plugin_kf_set_string (file, setting_name, key_name, output->str);
|
|
|
|
|
|
|
|
|
|
if (is_route) {
|
|
|
|
|
gs_free char *attributes = NULL;
|
|
|
|
|
|
2019-04-19 11:51:42 +02:00
|
|
|
attributes = nm_utils_format_variant_attributes (_nm_ip_route_get_attributes (array->pdata[i]),
|
|
|
|
|
',', '=');
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-19 17:33:40 +01:00
|
|
|
static void
|
|
|
|
|
bridge_vlan_writer (KeyfileWriterInfo *info,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
const char *key,
|
|
|
|
|
const GValue *value)
|
|
|
|
|
{
|
2019-04-15 15:14:33 +02:00
|
|
|
NMBridgeVlan *vlan;
|
|
|
|
|
GPtrArray *vlans;
|
|
|
|
|
GString *string;
|
|
|
|
|
guint i;
|
2019-03-19 17:33:40 +01:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
vlans = (GPtrArray *) g_value_get_boxed (value);
|
|
|
|
|
if (!vlans || !vlans->len)
|
2019-03-19 17:33:40 +01:00
|
|
|
return;
|
|
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
string = g_string_new ("");
|
|
|
|
|
for (i = 0; i < vlans->len; i++) {
|
|
|
|
|
gs_free char *vlan_str = NULL;
|
2019-03-19 17:33:40 +01:00
|
|
|
|
2019-04-15 15:14:33 +02:00
|
|
|
vlan = vlans->pdata[i];
|
|
|
|
|
vlan_str = nm_bridge_vlan_to_str (vlan, NULL);
|
|
|
|
|
if (!vlan_str)
|
|
|
|
|
continue;
|
|
|
|
|
if (string->len > 0)
|
|
|
|
|
g_string_append (string, ",");
|
2019-04-17 14:40:11 +02:00
|
|
|
nm_utils_escaped_tokens_escape_gstr_assert (vlan_str, ",", string);
|
2019-03-19 17:33:40 +01:00
|
|
|
}
|
2019-04-15 15:14:33 +02:00
|
|
|
|
|
|
|
|
nm_keyfile_plugin_kf_set_string (info->keyfile,
|
|
|
|
|
nm_setting_get_name (setting),
|
|
|
|
|
"vlans",
|
|
|
|
|
string->str);
|
|
|
|
|
|
|
|
|
|
g_string_free (string, TRUE);
|
2019-03-19 17:33:40 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
|
|
|
|
|
#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++) {
|
2019-04-24 09:24:15 +02:00
|
|
|
const char *opt_key;
|
|
|
|
|
const char *opt_val;
|
2019-04-24 12:03:10 +02:00
|
|
|
gs_free char *key_to_free = NULL;
|
|
|
|
|
|
2019-04-24 09:24:15 +02:00
|
|
|
nm_setting_wired_get_s390_option (s_wired, i, &opt_key, &opt_val);
|
2019-04-24 12:03:10 +02:00
|
|
|
nm_keyfile_plugin_kf_set_string (info->keyfile,
|
|
|
|
|
ETHERNET_S390_OPTIONS_GROUP_NAME,
|
2019-04-24 09:24:15 +02:00
|
|
|
nm_keyfile_key_encode (opt_key, &key_to_free),
|
|
|
|
|
opt_val);
|
2019-04-24 12:03:10 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-14 12:04:21 +01:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
static void
|
|
|
|
|
qdisc_writer (KeyfileWriterInfo *info,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
const char *key,
|
|
|
|
|
const GValue *value)
|
|
|
|
|
{
|
|
|
|
|
gsize i;
|
|
|
|
|
GPtrArray *array;
|
|
|
|
|
|
|
|
|
|
array = (GPtrArray *) g_value_get_boxed (value);
|
|
|
|
|
if (!array || !array->len)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < array->len; i++) {
|
|
|
|
|
NMTCQdisc *qdisc = array->pdata[i];
|
|
|
|
|
GString *key_name = g_string_sized_new (16);
|
|
|
|
|
GString *value_str = g_string_sized_new (60);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
g_string_free (key_name, TRUE);
|
|
|
|
|
g_string_free (value_str, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
tfilter_writer (KeyfileWriterInfo *info,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
const char *key,
|
|
|
|
|
const GValue *value)
|
|
|
|
|
{
|
|
|
|
|
gsize i;
|
|
|
|
|
GPtrArray *array;
|
|
|
|
|
|
|
|
|
|
array = (GPtrArray *) g_value_get_boxed (value);
|
|
|
|
|
if (!array || !array->len)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < array->len; i++) {
|
|
|
|
|
NMTCTfilter *tfilter = array->pdata[i];
|
|
|
|
|
GString *key_name = g_string_sized_new (16);
|
|
|
|
|
GString *value_str = g_string_sized_new (60);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
g_string_free (key_name, TRUE);
|
|
|
|
|
g_string_free (value_str, TRUE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2019-04-24 12:03:10 +02:00
|
|
|
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)));
|
|
|
|
|
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
/* Write VPN secrets out to a different group to keep them separate */
|
2019-01-02 09:09:37 +01:00
|
|
|
if ( NM_IS_SETTING_VPN (setting)
|
|
|
|
|
&& nm_streq (key, NM_SETTING_VPN_SECRETS)) {
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
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++) {
|
2019-01-02 12:39:05 +01:00
|
|
|
gs_free char *to_free = NULL;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
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;
|
|
|
|
|
|
2019-01-06 13:49:46 +01:00
|
|
|
if (!nm_setting_get_secret_flags (setting, property, &secret_flags, NULL))
|
|
|
|
|
nm_assert_not_reached ();
|
2019-01-02 12:39:05 +01:00
|
|
|
if (!_secret_flags_persist_secret (secret_flags))
|
|
|
|
|
continue;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-02 12:39:05 +01:00
|
|
|
data = g_hash_table_lookup (hash, property);
|
|
|
|
|
nm_keyfile_plugin_kf_set_string (file, group_name,
|
|
|
|
|
nm_keyfile_key_encode (property, &to_free),
|
|
|
|
|
data);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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,
|
|
|
|
|
NMKeyfileWriteTypeDataCert *cert_data)
|
|
|
|
|
{
|
|
|
|
|
const char *setting_name = nm_setting_get_name (NM_SETTING (cert_data->setting));
|
|
|
|
|
NMSetting8021xCKScheme scheme;
|
|
|
|
|
|
|
|
|
|
scheme = cert_data->vtable->scheme_func (cert_data->setting);
|
|
|
|
|
if (scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
|
2019-01-02 09:09:37 +01:00
|
|
|
gs_free char *path_free = NULL;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
gs_free char *base_dir = NULL;
|
2019-01-02 09:09:37 +01:00
|
|
|
gs_free char *tmp = NULL;
|
|
|
|
|
const char *path;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
|
|
|
|
path = cert_data->vtable->path_func (cert_data->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 ();
|
2019-01-02 09:09:37 +01:00
|
|
|
path_free = g_strconcat (base_dir, "/", path, NULL);
|
|
|
|
|
path = path_free;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
} 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)
|
|
|
|
|
g_clear_pointer (&tmp, g_free);
|
2019-01-02 09:09:37 +01:00
|
|
|
else {
|
|
|
|
|
tmp = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_PATH, path, NULL);
|
|
|
|
|
path = tmp;
|
|
|
|
|
}
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
|
|
|
|
/* Path contains at least a '/', hence it cannot be recognized as the old
|
|
|
|
|
* binary format consisting of a list of integers. */
|
|
|
|
|
|
|
|
|
|
nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, path);
|
|
|
|
|
} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_BLOB) {
|
|
|
|
|
GBytes *blob;
|
|
|
|
|
const guint8 *blob_data;
|
|
|
|
|
gsize blob_len;
|
2019-01-02 09:09:37 +01:00
|
|
|
gs_free char *blob_base64 = NULL;
|
|
|
|
|
gs_free char *val = NULL;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
|
|
|
|
blob = cert_data->vtable->blob_func (cert_data->setting);
|
|
|
|
|
g_assert (blob);
|
|
|
|
|
blob_data = g_bytes_get_data (blob, &blob_len);
|
|
|
|
|
|
|
|
|
|
blob_base64 = g_base64_encode (blob_data, blob_len);
|
|
|
|
|
val = g_strconcat (NM_KEYFILE_CERT_SCHEME_PREFIX_BLOB, blob_base64, NULL);
|
|
|
|
|
|
|
|
|
|
nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key, val);
|
|
|
|
|
} else if (scheme == NM_SETTING_802_1X_CK_SCHEME_PKCS11) {
|
|
|
|
|
nm_keyfile_plugin_kf_set_string (file, setting_name, cert_data->vtable->setting_key,
|
|
|
|
|
cert_data->vtable->uri_func (cert_data->setting));
|
|
|
|
|
} else {
|
|
|
|
|
/* scheme_func() returns UNKNOWN in all other cases. The only valid case
|
|
|
|
|
* where a scheme is allowed to be UNKNOWN, is unsetting the value. In this
|
|
|
|
|
* 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 *objtype = NULL;
|
|
|
|
|
guint i;
|
|
|
|
|
NMKeyfileWriteTypeDataCert type_data = { 0 };
|
|
|
|
|
|
|
|
|
|
for (i = 0; nm_setting_8021x_scheme_vtable[i].setting_key; i++) {
|
2019-01-02 09:09:37 +01:00
|
|
|
if (nm_streq0 (nm_setting_8021x_scheme_vtable[i].setting_key, key)) {
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
objtype = &nm_setting_8021x_scheme_vtable[i];
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!objtype)
|
|
|
|
|
g_return_if_reached ();
|
|
|
|
|
|
|
|
|
|
type_data.setting = NM_SETTING_802_1X (setting);
|
|
|
|
|
type_data.vtable = objtype;
|
|
|
|
|
|
|
|
|
|
if (info->handler) {
|
|
|
|
|
if (info->handler (info->connection,
|
|
|
|
|
info->keyfile,
|
|
|
|
|
NM_KEYFILE_WRITE_TYPE_CERT,
|
|
|
|
|
&type_data,
|
|
|
|
|
info->user_data,
|
|
|
|
|
&info->error))
|
|
|
|
|
return;
|
|
|
|
|
if (info->error)
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
cert_writer_default (info->connection, info->keyfile, &type_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-03-22 15:16:48 +01:00
|
|
|
struct _ParseInfoProperty {
|
2018-04-14 20:46:47 +02:00
|
|
|
const char *property_name;
|
2019-03-22 15:16:48 +01:00
|
|
|
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);
|
|
|
|
|
};
|
2019-03-22 15:16:48 +01:00
|
|
|
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);
|
|
|
|
|
};
|
2018-04-16 15:12:38 +02:00
|
|
|
bool parser_skip;
|
2018-04-16 13:27:18 +02:00
|
|
|
bool parser_no_check_key:1;
|
2018-04-16 11:28:54 +02:00
|
|
|
bool writer_skip:1;
|
2019-03-22 15:16:48 +01:00
|
|
|
bool has_writer_full:1;
|
2019-03-22 15:16:48 +01:00
|
|
|
bool has_parser_full:1;
|
2018-04-16 12:20:59 +02:00
|
|
|
|
|
|
|
|
/* 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;
|
2019-03-22 15:16:48 +01:00
|
|
|
};
|
2018-04-14 20:46:47 +02:00
|
|
|
|
|
|
|
|
#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, \
|
|
|
|
|
})
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
2018-04-14 20:46:47 +02:00
|
|
|
typedef struct {
|
|
|
|
|
const ParseInfoProperty*const*properties;
|
|
|
|
|
} ParseInfoSetting;
|
|
|
|
|
|
2018-07-27 16:11:41 +02:00
|
|
|
#define PARSE_INFO_SETTING(setting_type, ...) \
|
|
|
|
|
[setting_type] = (&((const ParseInfoSetting) { \
|
2018-04-14 20:46:47 +02:00
|
|
|
__VA_ARGS__ \
|
2018-07-27 16:11:41 +02:00
|
|
|
}))
|
2018-04-14 20:46:47 +02:00
|
|
|
|
2018-07-27 16:11:41 +02:00
|
|
|
static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = {
|
|
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_WIRELESS,
|
2018-04-14 20:46:47 +02:00
|
|
|
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,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_802_1X,
|
2018-04-14 20:46:47 +02:00
|
|
|
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,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_WIRED,
|
2018-04-14 20:46:47 +02:00
|
|
|
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,
|
|
|
|
|
),
|
2019-04-24 12:03:10 +02:00
|
|
|
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,
|
|
|
|
|
),
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_BLUETOOTH,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_BLUETOOTH_BDADDR,
|
|
|
|
|
.parser = mac_address_parser_ETHER,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_BOND,
|
2018-04-16 14:44:58 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_BOND_OPTIONS,
|
|
|
|
|
.parser_no_check_key = TRUE,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_BRIDGE,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_BRIDGE_MAC_ADDRESS,
|
|
|
|
|
.parser = mac_address_parser_ETHER,
|
|
|
|
|
),
|
2019-03-19 17:33:40 +01:00
|
|
|
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,
|
|
|
|
|
),
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_CONNECTION,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
2018-04-16 12:38:02 +02:00
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_CONNECTION_READ_ONLY,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 12:38:02 +02:00
|
|
|
.writer_skip = TRUE,
|
|
|
|
|
),
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_CONNECTION_TYPE,
|
|
|
|
|
.parser = setting_alias_parser,
|
|
|
|
|
.writer = setting_alias_writer,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_INFINIBAND,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_INFINIBAND_MAC_ADDRESS,
|
|
|
|
|
.parser = mac_address_parser_INFINIBAND,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_IP4_CONFIG,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ADDRESSES,
|
2018-04-16 13:27:18 +02:00
|
|
|
.parser_no_check_key = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
.parser = ip_address_or_route_parser,
|
|
|
|
|
.writer = addr_writer,
|
|
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_DNS,
|
2018-04-16 13:27:18 +02:00
|
|
|
.parser_no_check_key = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
.parser = ip_dns_parser,
|
|
|
|
|
.writer = dns_writer,
|
|
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_GATEWAY,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ROUTES,
|
2018-04-16 13:27:18 +02:00
|
|
|
.parser_no_check_key = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
.parser = ip_address_or_route_parser,
|
|
|
|
|
.writer = route_writer,
|
|
|
|
|
),
|
2019-03-14 12:04:21 +01:00
|
|
|
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,
|
|
|
|
|
),
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_IP6_CONFIG,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_IP6_CONFIG_ADDR_GEN_MODE,
|
2018-04-16 13:27:18 +02:00
|
|
|
.parser_no_check_key = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
.parser = ip6_addr_gen_mode_parser,
|
|
|
|
|
.writer = ip6_addr_gen_mode_writer,
|
2018-04-16 12:20:59 +02:00
|
|
|
.writer_persist_default = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ADDRESSES,
|
2018-04-16 13:27:18 +02:00
|
|
|
.parser_no_check_key = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
.parser = ip_address_or_route_parser,
|
|
|
|
|
.writer = addr_writer,
|
|
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_DNS,
|
2018-04-16 13:27:18 +02:00
|
|
|
.parser_no_check_key = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
.parser = ip_dns_parser,
|
|
|
|
|
.writer = dns_writer,
|
|
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_GATEWAY,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_IP_CONFIG_ROUTES,
|
2018-04-16 13:27:18 +02:00
|
|
|
.parser_no_check_key = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
.parser = ip_address_or_route_parser,
|
|
|
|
|
.writer = route_writer,
|
|
|
|
|
),
|
2019-03-14 12:04:21 +01:00
|
|
|
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,
|
|
|
|
|
),
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_SERIAL,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_SERIAL_PARITY,
|
|
|
|
|
.parser = parity_parser,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_SRIOV,
|
2018-05-25 12:05:24 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_SRIOV_VFS,
|
|
|
|
|
.parser_no_check_key = TRUE,
|
|
|
|
|
.parser = sriov_vfs_parser,
|
|
|
|
|
.writer = sriov_vfs_writer,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_TC_CONFIG,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TC_CONFIG_QDISCS,
|
2018-04-16 13:27:18 +02:00
|
|
|
.parser_no_check_key = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
.parser = qdisc_parser,
|
|
|
|
|
.writer = qdisc_writer,
|
|
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TC_CONFIG_TFILTERS,
|
2018-04-16 13:27:18 +02:00
|
|
|
.parser_no_check_key = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
.parser = tfilter_parser,
|
|
|
|
|
.writer = tfilter_writer,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_TEAM,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_CONFIG,
|
|
|
|
|
.parser = team_config_parser,
|
|
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_LINK_WATCHERS,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_MCAST_REJOIN_COUNT,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_NOTIFY_PEERS_COUNT,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_ACTIVE,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_FAST_RATE,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_HWADDR_POLICY,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_MIN_PORTS,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_SYS_PRIO,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_TX_BALANCER,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_RUNNER_TX_HASH,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_TEAM_PORT,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_CONFIG,
|
|
|
|
|
.parser = team_config_parser,
|
|
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_LACP_KEY,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_LACP_PRIO,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_LINK_WATCHERS,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_PRIO,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_QUEUE_ID,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_TEAM_PORT_STICKY,
|
2018-04-16 15:12:38 +02:00
|
|
|
.parser_skip = TRUE,
|
2018-04-16 11:28:54 +02:00
|
|
|
.writer_skip = TRUE,
|
2018-04-14 20:46:47 +02:00
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_USER,
|
2018-04-16 14:44:58 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_USER_DATA,
|
|
|
|
|
.parser_no_check_key = TRUE,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_VLAN,
|
2018-04-16 12:20:59 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_VLAN_FLAGS,
|
|
|
|
|
.writer_persist_default = TRUE,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_VPN,
|
2018-04-16 14:44:58 +02:00
|
|
|
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,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2018-07-27 16:11:41 +02:00
|
|
|
PARSE_INFO_SETTING (NM_META_SETTING_TYPE_WIMAX,
|
2018-04-14 20:46:47 +02:00
|
|
|
PARSE_INFO_PROPERTIES (
|
|
|
|
|
PARSE_INFO_PROPERTY (NM_SETTING_WIMAX_MAC_ADDRESS,
|
|
|
|
|
.parser = mac_address_parser_ETHER,
|
|
|
|
|
),
|
|
|
|
|
),
|
|
|
|
|
),
|
2015-02-18 19:59:28 +01:00
|
|
|
};
|
|
|
|
|
|
2019-08-25 13:54:42 +02:00
|
|
|
static void
|
2018-07-27 16:11:41 +02:00
|
|
|
_parse_info_find (NMSetting *setting,
|
|
|
|
|
const char *property_name,
|
2019-08-25 13:54:42 +02:00
|
|
|
const NMMetaSettingInfo **out_setting_info,
|
|
|
|
|
const ParseInfoSetting **out_parse_info_setting,
|
|
|
|
|
const ParseInfoProperty **out_parse_info_property)
|
2018-04-14 20:46:47 +02:00
|
|
|
{
|
2018-07-27 16:11:41 +02:00
|
|
|
const NMMetaSettingInfo *setting_info;
|
|
|
|
|
const ParseInfoSetting *pis;
|
2019-08-25 13:54:42 +02:00
|
|
|
const ParseInfoProperty *pip;
|
2018-04-14 20:46:47 +02:00
|
|
|
|
2018-07-27 16:11:41 +02:00
|
|
|
#if NM_MORE_ASSERTS > 10
|
2018-04-14 20:46:47 +02:00
|
|
|
{
|
|
|
|
|
guint i, j;
|
2019-08-25 13:54:42 +02:00
|
|
|
static int asserted = FALSE;
|
2018-04-14 20:46:47 +02:00
|
|
|
|
2019-08-25 13:54:42 +02:00
|
|
|
if (!asserted) {
|
|
|
|
|
for (i = 0; i < G_N_ELEMENTS (parse_infos); i++) {
|
|
|
|
|
pis = parse_infos[i];
|
2018-07-27 16:11:41 +02:00
|
|
|
|
2019-08-25 13:54:42 +02:00
|
|
|
if (!pis)
|
|
|
|
|
continue;
|
2019-08-25 13:29:41 +02:00
|
|
|
if (!pis->properties)
|
|
|
|
|
continue;
|
2018-04-14 20:46:47 +02:00
|
|
|
|
2019-08-25 13:54:42 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2018-07-27 16:11:41 +02:00
|
|
|
}
|
2018-04-14 20:46:47 +02:00
|
|
|
}
|
2019-08-25 13:54:42 +02:00
|
|
|
asserted = TRUE;
|
2018-04-14 20:46:47 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
#endif
|
|
|
|
|
|
2018-07-27 16:11:41 +02:00
|
|
|
if ( !NM_IS_SETTING (setting)
|
|
|
|
|
|| !(setting_info = NM_SETTING_GET_CLASS (setting)->setting_info)) {
|
|
|
|
|
/* handle invalid setting objects gracefully. */
|
2019-08-25 13:54:42 +02:00
|
|
|
NM_SET_OUT (out_setting_info, NULL);
|
|
|
|
|
NM_SET_OUT (out_parse_info_setting, NULL);
|
|
|
|
|
NM_SET_OUT (out_parse_info_property, NULL);
|
|
|
|
|
return;
|
2018-07-27 16:11:41 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_assert (setting_info->setting_name);
|
2019-08-25 13:54:42 +02:00
|
|
|
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];
|
2019-03-22 15:10:41 +01:00
|
|
|
|
2019-08-25 13:54:42 +02:00
|
|
|
pip = NULL;
|
|
|
|
|
if ( pis
|
|
|
|
|
&& property_name) {
|
|
|
|
|
gssize idx;
|
2018-04-14 20:46:47 +02:00
|
|
|
|
2018-06-28 09:36:27 +02:00
|
|
|
G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (ParseInfoProperty, property_name) == 0);
|
2019-08-25 13:54:42 +02:00
|
|
|
|
2018-08-01 11:03:02 +02:00
|
|
|
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);
|
2018-04-14 20:46:47 +02:00
|
|
|
if (idx >= 0)
|
2019-08-25 13:54:42 +02:00
|
|
|
pip = pis->properties[idx];
|
2018-04-14 20:46:47 +02:00
|
|
|
}
|
|
|
|
|
|
2019-08-25 13:54:42 +02:00
|
|
|
NM_SET_OUT (out_setting_info, setting_info);
|
|
|
|
|
NM_SET_OUT (out_parse_info_setting, pis);
|
|
|
|
|
NM_SET_OUT (out_parse_info_property, pip);
|
2018-04-14 20:46:47 +02:00
|
|
|
}
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
static void
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
read_one_setting_value (KeyfileReaderInfo *info,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
const NMSettInfoProperty *property_info)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
2015-02-18 18:59:35 +01:00
|
|
|
GKeyFile *keyfile = info->keyfile;
|
|
|
|
|
gs_free_error GError *err = NULL;
|
2019-03-22 15:10:41 +01:00
|
|
|
const NMMetaSettingInfo *setting_info;
|
2018-04-14 20:46:47 +02:00
|
|
|
const ParseInfoProperty *pip;
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
gs_free char *tmp_str = NULL;
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
const char *key;
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
GType type;
|
|
|
|
|
guint64 u64;
|
|
|
|
|
gint64 i64;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
nm_assert (!info->error);
|
2019-03-22 15:16:48 +01:00
|
|
|
nm_assert ( !property_info->param_spec
|
|
|
|
|
|| nm_streq (property_info->param_spec->name, property_info->name));
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-03-22 15:16:48 +01:00
|
|
|
key = property_info->name;
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
|
2019-08-25 13:54:42 +02:00
|
|
|
_parse_info_find (setting, key, &setting_info, NULL, &pip);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_assert (setting_info);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-03-22 15:16:48 +01:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-12-08 08:28:24 +01:00
|
|
|
|
2019-03-22 15:16:48 +01:00
|
|
|
nm_assert (property_info->param_spec);
|
|
|
|
|
nm_assert ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) == G_PARAM_WRITABLE);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
/* 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.
|
|
|
|
|
*/
|
2018-04-16 14:44:58 +02:00
|
|
|
if ( (!pip || !pip->parser_no_check_key)
|
2019-03-22 15:10:41 +01:00
|
|
|
&& !nm_keyfile_plugin_kf_has_key (keyfile, setting_info->setting_name, key, &err)) {
|
2018-09-15 07:20:54 -04:00
|
|
|
/* Key doesn't exist or an error occurred, thus nothing to do. */
|
2015-02-18 19:59:28 +01:00
|
|
|
if (err) {
|
2015-02-18 18:59:35 +01:00
|
|
|
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("error loading setting value: %s"),
|
|
|
|
|
err->message))
|
2018-04-16 12:54:04 +02:00
|
|
|
return;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 15:16:48 +01:00
|
|
|
if ( pip
|
|
|
|
|
&& pip->parser) {
|
2018-04-14 20:46:47 +02:00
|
|
|
pip->parser (info, setting, key);
|
2015-02-18 19:59:28 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
type = G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
if (type == G_TYPE_STRING) {
|
2018-04-16 12:54:04 +02:00
|
|
|
gs_free char *str_val = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-03-22 15:10:41 +01:00
|
|
|
str_val = nm_keyfile_plugin_kf_get_string (keyfile, setting_info->setting_name, key, &err);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
if (!err)
|
|
|
|
|
nm_g_object_set_property_string_take (G_OBJECT (setting), key, g_steal_pointer (&str_val), &err);
|
2015-02-18 19:59:28 +01:00
|
|
|
} else if (type == G_TYPE_UINT) {
|
2019-03-22 15:10:41 +01:00
|
|
|
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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);
|
2015-02-18 18:59:35 +01:00
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
} else if (type == G_TYPE_INT) {
|
2019-03-22 15:10:41 +01:00
|
|
|
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
} else if (type == G_TYPE_BOOLEAN) {
|
|
|
|
|
gboolean bool_val;
|
|
|
|
|
|
2019-03-22 15:10:41 +01:00
|
|
|
bool_val = nm_keyfile_plugin_kf_get_boolean (keyfile, setting_info->setting_name, key, &err);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
if (!err)
|
|
|
|
|
nm_g_object_set_property_boolean (G_OBJECT (setting), key, bool_val, &err);
|
2015-02-18 19:59:28 +01:00
|
|
|
} else if (type == G_TYPE_CHAR) {
|
2019-03-22 15:10:41 +01:00
|
|
|
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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);
|
2015-02-18 18:59:35 +01:00
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
} else if (type == G_TYPE_UINT64) {
|
2019-03-22 15:10:41 +01:00
|
|
|
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
} else if (type == G_TYPE_INT64) {
|
2019-03-22 15:10:41 +01:00
|
|
|
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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);
|
|
|
|
|
}
|
2015-02-18 18:59:35 +01:00
|
|
|
} else if (type == G_TYPE_BYTES) {
|
2019-01-02 09:09:37 +01:00
|
|
|
gs_free int *tmp = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
GByteArray *array;
|
|
|
|
|
GBytes *bytes;
|
|
|
|
|
gsize length;
|
|
|
|
|
int i;
|
2015-02-18 18:59:35 +01:00
|
|
|
gboolean already_warned = FALSE;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2019-03-22 15:10:41 +01:00
|
|
|
tmp = nm_keyfile_plugin_kf_get_integer_list (keyfile, setting_info->setting_name, key, &length, NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
array = g_byte_array_sized_new (length);
|
|
|
|
|
for (i = 0; i < length; i++) {
|
2019-01-02 09:09:37 +01:00
|
|
|
const int val = tmp[i];
|
2015-02-18 19:59:28 +01:00
|
|
|
unsigned char v = (unsigned char) (val & 0xFF);
|
|
|
|
|
|
|
|
|
|
if (val < 0 || val > 255) {
|
2015-02-18 18:59:35 +01:00
|
|
|
if ( !already_warned
|
|
|
|
|
&& !handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("ignoring invalid byte element '%d' (not between 0 and 255 inclusive)"),
|
|
|
|
|
val)) {
|
|
|
|
|
g_byte_array_unref (array);
|
2018-04-16 12:54:04 +02:00
|
|
|
return;
|
2015-02-18 18:59:35 +01:00
|
|
|
}
|
|
|
|
|
already_warned = TRUE;
|
2015-02-18 19:59:28 +01:00
|
|
|
} else
|
|
|
|
|
g_byte_array_append (array, (const unsigned char *) &v, sizeof (v));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bytes = g_byte_array_free_to_bytes (array);
|
|
|
|
|
g_object_set (setting, key, bytes, NULL);
|
|
|
|
|
g_bytes_unref (bytes);
|
|
|
|
|
} else if (type == G_TYPE_STRV) {
|
2019-01-02 09:09:37 +01:00
|
|
|
gs_strfreev char **sa = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
gsize length;
|
|
|
|
|
|
2019-03-22 15:10:41 +01:00
|
|
|
sa = nm_keyfile_plugin_kf_get_string_list (keyfile, setting_info->setting_name, key, &length, NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
g_object_set (setting, key, sa, NULL);
|
|
|
|
|
} else if (type == G_TYPE_HASH_TABLE) {
|
2015-02-18 18:59:35 +01:00
|
|
|
read_hash_of_string (keyfile, setting, key);
|
2015-02-18 19:59:28 +01:00
|
|
|
} else if (type == G_TYPE_ARRAY) {
|
2015-02-18 18:59:35 +01:00
|
|
|
read_array_of_uint (keyfile, setting, key);
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
} else if (G_TYPE_IS_FLAGS (type)) {
|
2019-03-22 15:10:41 +01:00
|
|
|
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err);
|
2015-02-18 19:59:28 +01:00
|
|
|
if (!err) {
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
} else if (G_TYPE_IS_ENUM (type)) {
|
2019-03-22 15:10:41 +01:00
|
|
|
tmp_str = nm_keyfile_plugin_kf_get_value (keyfile, setting_info->setting_name, key, &err);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
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 ();
|
2015-02-18 19:59:28 +01:00
|
|
|
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
if (err) {
|
|
|
|
|
if ( err->domain == G_KEY_FILE_ERROR
|
|
|
|
|
&& NM_IN_SET (err->code, G_KEY_FILE_ERROR_GROUP_NOT_FOUND,
|
|
|
|
|
G_KEY_FILE_ERROR_KEY_NOT_FOUND)) {
|
|
|
|
|
/* ignore such errors. The key is not present. */
|
|
|
|
|
} else {
|
|
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("invalid setting: %s"), err->message);
|
|
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
static void
|
|
|
|
|
_read_setting (KeyfileReaderInfo *info)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
const NMSettInfoSetting *sett_info;
|
|
|
|
|
gs_unref_object NMSetting *setting = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
const char *alias;
|
|
|
|
|
GType type;
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
guint i;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
alias = nm_keyfile_plugin_get_setting_name_for_alias (info->group);
|
|
|
|
|
if (!alias)
|
|
|
|
|
alias = info->group;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
type = nm_setting_lookup_type (alias);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (!type) {
|
2015-02-18 18:59:35 +01:00
|
|
|
handle_warn (info, NULL, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("invalid setting name '%s'"), info->group);
|
2019-01-02 09:09:37 +01:00
|
|
|
return;
|
2015-02-18 18:59:35 +01:00
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
setting = g_object_new (type, NULL);
|
|
|
|
|
|
|
|
|
|
info->setting = setting;
|
|
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
|
|
|
|
if (sett_info->detail.gendata_info) {
|
|
|
|
|
gs_free char **keys = NULL;
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
gsize k, n_keys;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
|
|
|
|
keys = g_key_file_get_keys (info->keyfile, info->group, &n_keys, NULL);
|
2018-12-30 16:08:06 +01:00
|
|
|
if (!keys)
|
|
|
|
|
n_keys = 0;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
if (n_keys > 0) {
|
|
|
|
|
GHashTable *h = _nm_setting_gendata_hash (setting, TRUE);
|
|
|
|
|
|
|
|
|
|
nm_utils_strv_sort (keys, n_keys);
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
for (k = 0; k < n_keys; k++) {
|
|
|
|
|
gs_free char *key = keys[k];
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
gs_free_error GError *local = NULL;
|
|
|
|
|
const GVariantType *variant_type;
|
|
|
|
|
GVariant *variant;
|
|
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
/* a GKeyFile can return duplicate keys, there is just no API to make sense
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
* of them. Skip them. */
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
if ( k + 1 < n_keys
|
|
|
|
|
&& nm_streq (key, keys[k + 1]))
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
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, 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, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("key '%s.%s' is not boolean"),
|
|
|
|
|
info->group, key))
|
|
|
|
|
break;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
variant = g_variant_new_boolean (v);
|
|
|
|
|
} else {
|
|
|
|
|
nm_assert_not_reached ();
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_hash_table_insert (h,
|
|
|
|
|
g_steal_pointer (&key),
|
|
|
|
|
g_variant_take_ref (variant));
|
|
|
|
|
}
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
for (; k < n_keys; k++)
|
|
|
|
|
g_free (keys[k]);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
2019-01-02 09:09:37 +01:00
|
|
|
}
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
for (i = 0; i < sett_info->property_infos_len; i++) {
|
2019-03-22 15:16:48 +01:00
|
|
|
read_one_setting_value (info,
|
|
|
|
|
setting,
|
|
|
|
|
&sett_info->property_infos[i]);
|
|
|
|
|
if (info->error)
|
|
|
|
|
goto out;
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
}
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
out:
|
|
|
|
|
info->setting = NULL;
|
|
|
|
|
if (!info->error)
|
|
|
|
|
nm_connection_add_setting (info->connection, g_steal_pointer (&setting));
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
2019-01-30 12:36:13 +01:00
|
|
|
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)];
|
2019-03-02 17:10:25 +01:00
|
|
|
if ( !nm_utils_base64secret_normalize (cstr, NM_WIREGUARD_PUBLIC_KEY_LEN, &str)
|
2019-01-30 12:36:13 +01:00
|
|
|
|| !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_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("invalid peer public key in section '%s'"),
|
|
|
|
|
info->group);
|
|
|
|
|
return;
|
|
|
|
|
}
|
2019-03-01 15:52:19 +01:00
|
|
|
nm_wireguard_peer_set_public_key (peer, cstr, TRUE);
|
2019-01-30 12:36:13 +01:00
|
|
|
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) {
|
2019-03-01 15:52:19 +01:00
|
|
|
if (!nm_wireguard_peer_set_preshared_key (peer, str, FALSE)) {
|
2019-01-30 12:36:13 +01:00
|
|
|
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
2019-03-18 10:03:43 +00:00
|
|
|
_("key '%s.%s' is not a valid 256 bit key in base64 encoding"),
|
2019-01-30 12:36:13 +01:00
|
|
|
info->group, key))
|
|
|
|
|
return;
|
2019-03-01 15:52:19 +01:00
|
|
|
}
|
2019-01-30 12:36:13 +01:00
|
|
|
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_KEYFILE_WARN_SEVERITY_WARN,
|
2019-03-18 10:03:43 +00:00
|
|
|
_("key '%s.%s' is not a valid secret flag"),
|
2019-01-30 12:36:13 +01:00
|
|
|
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_KEYFILE_WARN_SEVERITY_WARN,
|
2019-03-18 10:03:43 +00:00
|
|
|
_("key '%s.%s' is not a integer in range 0 to 2^32"),
|
2019-01-30 12:36:13 +01:00
|
|
|
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]) {
|
2019-03-01 15:52:19 +01:00
|
|
|
if (!nm_wireguard_peer_set_endpoint (peer, str, FALSE)) {
|
2019-01-30 12:36:13 +01:00
|
|
|
if (!handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
2019-03-18 10:03:43 +00:00
|
|
|
_("key '%s.%s' is not a valid endpoint"),
|
2019-01-30 12:36:13 +01:00
|
|
|
info->group, key))
|
|
|
|
|
return;
|
2019-03-01 15:52:19 +01:00
|
|
|
}
|
2019-01-30 12:36:13 +01:00
|
|
|
}
|
|
|
|
|
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_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("key '%s.%s' has invalid allowed-ips"),
|
|
|
|
|
info->group, key))
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
nm_clear_pointer (&sa, g_strfreev);
|
|
|
|
|
|
|
|
|
|
if (info->error)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!nm_wireguard_peer_is_valid (peer, TRUE, TRUE, &error)) {
|
2019-08-02 09:19:03 +02:00
|
|
|
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
|
|
|
|
|
_("peer '%s' is invalid: %s"),
|
|
|
|
|
info->group, error->message);
|
2019-01-30 12:36:13 +01:00
|
|
|
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)));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 19:59:28 +01:00
|
|
|
static void
|
2019-01-02 09:09:37 +01:00
|
|
|
_read_setting_vpn_secrets (KeyfileReaderInfo *info)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
2018-04-16 12:54:04 +02:00
|
|
|
gs_strfreev char **keys = NULL;
|
2018-12-30 16:08:06 +01:00
|
|
|
gsize i, n_keys;
|
2019-01-02 09:09:37 +01:00
|
|
|
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;
|
|
|
|
|
}
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2018-12-30 16:08:06 +01:00
|
|
|
keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, &n_keys, NULL);
|
|
|
|
|
for (i = 0; i < n_keys; i++) {
|
2019-01-02 09:09:37 +01:00
|
|
|
gs_free char *secret = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2018-12-30 16:08:06 +01:00
|
|
|
secret = nm_keyfile_plugin_kf_get_string (info->keyfile, NM_KEYFILE_GROUP_VPN_SECRETS, keys[i], NULL);
|
2019-01-02 09:09:37 +01:00
|
|
|
if (secret)
|
2018-12-30 16:08:06 +01:00
|
|
|
nm_setting_vpn_add_secret (s_vpn, keys[i], secret);
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-02 19:44:31 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
/**
|
|
|
|
|
* nm_keyfile_read:
|
|
|
|
|
* @keyfile: the keyfile from which to create the connection
|
|
|
|
|
* @base_dir: when reading certificates from files with relative name,
|
keyfile: split automatically setting ID/UUID for keyfile
keyfile already supports omitting the "connection.id" and
"connection.uuid". In that case, the ID would be taken from the
keyfile's name, and the UUID was generated by md5 hashing the
full filename.
No longer do this during nm_keyfile_read(), instead let all
callers call nm_keyfile_read_ensure_*() to their liking. This is done
for two reasons:
- a minor reason is, that one day we want to expose keyfile API
as public API. That means, we also want to read keyfiles from
stdin, where there is no filename available. The implementation
which parses stdio needs to define their own way of auto-generating
ID and UUID. Note how nm_keyfile_read()'s API no longer takes a
filename as argument, which would be awkward for the stdin case.
- Currently, we only support one keyfile directory, which (configurably)
is "/etc/NetworkManager/system-connections".
In the future, we want to support multiple keyfile dirctories, like
"/var/run/NetworkManager/profiles" or "/usr/lib/NetworkManager/profiles".
Here we want that a file "foo" (which does not specify a UUID) gets the
same UUID regardless of the directory it is in. That seems better, because
then the UUID won't change as you move the file between directories.
Yes, that means, that the same UUID will be provided by multiple
files, but NetworkManager must already cope with that situation anyway.
Unfortunately, the UUID generation scheme hashes the full path. That
means, we must hash the path name of the file "foo" inside the
original "system-connections" directory.
Refactor the code so that it accounds for a difference between the
filename of the keyfile, and the profile_dir used for generating
the UUID.
2018-10-02 19:53:54 +02:00
|
|
|
* the relative path is made absolute using @base_dir. This must
|
|
|
|
|
* be an absolute path.
|
2015-02-18 18:59:35 +01:00
|
|
|
* @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.
|
|
|
|
|
*/
|
2015-02-18 19:59:28 +01:00
|
|
|
NMConnection *
|
2015-02-18 18:59:35 +01:00
|
|
|
nm_keyfile_read (GKeyFile *keyfile,
|
|
|
|
|
const char *base_dir,
|
|
|
|
|
NMKeyfileReadHandler handler,
|
|
|
|
|
void *user_data,
|
|
|
|
|
GError **error)
|
2015-02-18 19:59:28 +01:00
|
|
|
{
|
2018-04-16 12:54:04 +02:00
|
|
|
gs_unref_object NMConnection *connection = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
NMSettingConnection *s_con;
|
2018-12-30 00:09:34 +01:00
|
|
|
gs_strfreev char **groups = NULL;
|
2019-01-02 09:09:37 +01:00
|
|
|
gsize n_groups;
|
keyfile: split automatically setting ID/UUID for keyfile
keyfile already supports omitting the "connection.id" and
"connection.uuid". In that case, the ID would be taken from the
keyfile's name, and the UUID was generated by md5 hashing the
full filename.
No longer do this during nm_keyfile_read(), instead let all
callers call nm_keyfile_read_ensure_*() to their liking. This is done
for two reasons:
- a minor reason is, that one day we want to expose keyfile API
as public API. That means, we also want to read keyfiles from
stdin, where there is no filename available. The implementation
which parses stdio needs to define their own way of auto-generating
ID and UUID. Note how nm_keyfile_read()'s API no longer takes a
filename as argument, which would be awkward for the stdin case.
- Currently, we only support one keyfile directory, which (configurably)
is "/etc/NetworkManager/system-connections".
In the future, we want to support multiple keyfile dirctories, like
"/var/run/NetworkManager/profiles" or "/usr/lib/NetworkManager/profiles".
Here we want that a file "foo" (which does not specify a UUID) gets the
same UUID regardless of the directory it is in. That seems better, because
then the UUID won't change as you move the file between directories.
Yes, that means, that the same UUID will be provided by multiple
files, but NetworkManager must already cope with that situation anyway.
Unfortunately, the UUID generation scheme hashes the full path. That
means, we must hash the path name of the file "foo" inside the
original "system-connections" directory.
Refactor the code so that it accounds for a difference between the
filename of the keyfile, and the profile_dir used for generating
the UUID.
2018-10-02 19:53:54 +02:00
|
|
|
gsize i;
|
2015-02-18 19:59:28 +01:00
|
|
|
gboolean vpn_secrets = FALSE;
|
2019-01-02 09:09:37 +01:00
|
|
|
KeyfileReaderInfo info;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
g_return_val_if_fail (keyfile, NULL);
|
|
|
|
|
g_return_val_if_fail (!error || !*error, NULL);
|
keyfile: split automatically setting ID/UUID for keyfile
keyfile already supports omitting the "connection.id" and
"connection.uuid". In that case, the ID would be taken from the
keyfile's name, and the UUID was generated by md5 hashing the
full filename.
No longer do this during nm_keyfile_read(), instead let all
callers call nm_keyfile_read_ensure_*() to their liking. This is done
for two reasons:
- a minor reason is, that one day we want to expose keyfile API
as public API. That means, we also want to read keyfiles from
stdin, where there is no filename available. The implementation
which parses stdio needs to define their own way of auto-generating
ID and UUID. Note how nm_keyfile_read()'s API no longer takes a
filename as argument, which would be awkward for the stdin case.
- Currently, we only support one keyfile directory, which (configurably)
is "/etc/NetworkManager/system-connections".
In the future, we want to support multiple keyfile dirctories, like
"/var/run/NetworkManager/profiles" or "/usr/lib/NetworkManager/profiles".
Here we want that a file "foo" (which does not specify a UUID) gets the
same UUID regardless of the directory it is in. That seems better, because
then the UUID won't change as you move the file between directories.
Yes, that means, that the same UUID will be provided by multiple
files, but NetworkManager must already cope with that situation anyway.
Unfortunately, the UUID generation scheme hashes the full path. That
means, we must hash the path name of the file "foo" inside the
original "system-connections" directory.
Refactor the code so that it accounds for a difference between the
filename of the keyfile, and the profile_dir used for generating
the UUID.
2018-10-02 19:53:54 +02:00
|
|
|
g_return_val_if_fail (base_dir && base_dir[0] == '/', NULL);
|
2015-02-18 19:59:28 +01:00
|
|
|
|
|
|
|
|
connection = nm_simple_connection_new ();
|
|
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
info = (KeyfileReaderInfo) {
|
|
|
|
|
.connection = connection,
|
|
|
|
|
.keyfile = keyfile,
|
|
|
|
|
.base_dir = base_dir,
|
|
|
|
|
.handler = handler,
|
|
|
|
|
.user_data = user_data,
|
|
|
|
|
};
|
2015-02-18 18:59:35 +01:00
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
groups = g_key_file_get_groups (keyfile, &n_groups);
|
2018-12-30 16:08:06 +01:00
|
|
|
if (!groups)
|
2019-01-02 09:09:37 +01:00
|
|
|
n_groups = 0;
|
2018-12-30 16:08:06 +01:00
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
for (i = 0; i < n_groups; i++) {
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
info.group = groups[i];
|
2019-01-02 09:09:37 +01:00
|
|
|
|
|
|
|
|
if (nm_streq (groups[i], NM_KEYFILE_GROUP_VPN_SECRETS)) {
|
|
|
|
|
/* Only read out secrets when needed */
|
|
|
|
|
vpn_secrets = TRUE;
|
2019-01-30 12:36:13 +01:00
|
|
|
} else if (NM_STR_HAS_PREFIX (groups[i], NM_KEYFILE_GROUPPREFIX_WIREGUARD_PEER))
|
|
|
|
|
_read_setting_wireguard_peer (&info);
|
settings: rework tracking settings connections and settings plugins
Completely rework how settings plugin handle connections and how
NMSettings tracks the list of connections.
Previously, settings plugins would return objects of (a subtype of) type
NMSettingsConnection. The NMSettingsConnection was tightly coupled with
the settings plugin. That has a lot of downsides.
Change that. When changing this basic relation how settings connections
are tracked, everything falls appart. That's why this is a huge change.
Also, since I have to largely rewrite the settings plugins, I also
added support for multiple keyfile directories, handle in-memory
connections only by keyfile plugin and (partly) use copy-on-write NMConnection
instances. I don't want to spend effort rewriting large parts while
preserving the old way, that anyway should change. E.g. while rewriting ifcfg-rh,
I don't want to let it handle in-memory connections because that's not right
long-term.
--
If the settings plugins themself create subtypes of NMSettingsConnection
instances, then a lot of knowledge about tracking connections moves
to the plugins.
Just try to follow the code what happend during nm_settings_add_connection().
Note how the logic is spread out:
- nm_settings_add_connection() calls plugin's add_connection()
- add_connection() creates a NMSettingsConnection subtype
- the plugin has to know that it's called during add-connection and
not emit NM_SETTINGS_PLUGIN_CONNECTION_ADDED signal
- NMSettings calls claim_connection() which hocks up the new
NMSettingsConnection instance and configures the instance
(like calling nm_settings_connection_added()).
This summary does not sound like a lot, but try to follow that code. The logic
is all over the place.
Instead, settings plugins should have a very simple API for adding, modifying,
deleting, loading and reloading connections. All the plugin does is to return a
NMSettingsStorage handle. The storage instance is a handle to identify a profile
in storage (e.g. a particular file). The settings plugin is free to subtype
NMSettingsStorage, but it's not necessary.
There are no more events raised, and the settings plugin implements the small
API in a straightforward manner.
NMSettings now drives all of this. Even NMSettingsConnection has now
very little concern about how it's tracked and delegates only to NMSettings.
This should make settings plugins simpler. Currently settings plugins
are so cumbersome to implement, that we avoid having them. It should not be
like that and it should be easy, beneficial and lightweight to create a new
settings plugin.
Note also how the settings plugins no longer care about duplicate UUIDs.
Duplicated UUIDs are a fact of life and NMSettings must handle them. No
need to overly concern settings plugins with that.
--
NMSettingsConnection is exposed directly on D-Bus (being a subtype of
NMDBusObject) but it was also a GObject type provided by the settings
plugin. Hence, it was not possible to migrate a profile from one plugin to
another.
However that would be useful when one profile does not support a
connection type (like ifcfg-rh not supporting VPN). Currently such
migration is not implemented except for migrating them to/from keyfile's
run directory. The problem is that migrating profiles in general is
complicated but in some cases it is important to do.
For example checkpoint rollback should recreate the profile in the right
settings plugin, not just add it to persistent storage. This is not yet
properly implemented.
--
Previously, both keyfile and ifcfg-rh plugin implemented in-memory (unsaved)
profiles, while ifupdown plugin cannot handle them. That meant duplication of code
and a ifupdown profile could not be modified or made unsaved.
This is now unified and only keyfile plugin handles in-memory profiles (bgo #744711).
Also, NMSettings is aware of such profiles and treats them specially.
In particular, NMSettings drives the migration between persistent and non-persistent
storage.
Note that a settings plugins may create truly generated, in-memory profiles.
The settings plugin is free to generate and persist the profiles in any way it
wishes. But the concept of "unsaved" profiles is now something explicitly handled
by keyfile plugin. Also, these "unsaved" keyfile profiles are persisted to file system
too, to the /run directory. This is great for two reasons: first of all, all
profiles from keyfile storage in fact have a backing file -- even the
unsaved ones. It also means you can create "unsaved" profiles in /run
and load them with `nmcli connection load`, meaning there is a file
based API for creating unsaved profiles.
The other advantage is that these profiles now survive restarting
NetworkManager. It's paramount that restarting the daemon is as
non-disruptive as possible. Persisting unsaved files to /run improves
here significantly.
--
In the past, NMSettingsConnection also implemented NMConnection interface.
That was already changed a while ago and instead users call now
nm_settings_connection_get_connection() to delegate to a
NMSimpleConnection. What however still happened was that the NMConnection
instance gets never swapped but instead the instance was modified with
nm_connection_replace_settings_from_connection(), clear-secrets, etc.
Change that and treat the NMConnection instance immutable. Instead of modifying
it, reference/clone a new instance. This changes that previously when somebody
wanted to keep a reference to an NMConnection, then the profile would be cloned.
Now, it is supposed to be safe to reference the instance directly and everybody
must ensure not to modify the instance. nmtst_connection_assert_unchanging()
should help with that.
The point is that the settings plugins may keep references to the
NMConnection instance, and so does the NMSettingsConnection. We want
to avoid cloning the instances as long as they are the same.
Likewise, the device's applied connection can now also be referenced
instead of cloning it. This is not yet done, and possibly there are
further improvements possible.
--
Also implement multiple keyfile directores /usr/lib, /etc, /run (rh #1674545,
bgo #772414).
It was always the case that multiple files could provide the same UUID
(both in case of keyfile and ifcfg-rh). For keyfile plugin, if a profile in
read-only storage in /usr/lib gets modified, then it gets actually stored in
/etc (or /run, if the profile is unsaved).
--
While at it, make /etc/network/interfaces profiles for ifupdown plugin reloadable.
--
https://bugzilla.gnome.org/show_bug.cgi?id=772414
https://bugzilla.gnome.org/show_bug.cgi?id=744711
https://bugzilla.redhat.com/show_bug.cgi?id=1674545
2019-06-13 17:12:20 +02:00
|
|
|
else if (nm_streq (groups[i], NM_KEYFILE_GROUP_NMMETA)) {
|
|
|
|
|
/* pass */
|
|
|
|
|
} else
|
2019-01-02 09:09:37 +01:00
|
|
|
_read_setting (&info);
|
|
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
info.group = NULL;
|
2019-01-02 09:09:37 +01:00
|
|
|
|
|
|
|
|
if (info.error)
|
|
|
|
|
goto out_with_info_error;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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)) {
|
2019-01-02 09:09:37 +01:00
|
|
|
gs_free char *interface_name = NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
|
2015-02-18 18:59:35 +01:00
|
|
|
interface_name = g_key_file_get_string (keyfile,
|
2015-02-18 19:59:28 +01:00
|
|
|
nm_setting_connection_get_connection_type (s_con),
|
|
|
|
|
"interface-name",
|
|
|
|
|
NULL);
|
2019-01-02 09:09:37 +01:00
|
|
|
if (interface_name)
|
2015-02-18 19:59:28 +01:00
|
|
|
g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (vpn_secrets) {
|
2019-01-02 09:09:37 +01:00
|
|
|
info.group = NM_KEYFILE_GROUP_VPN_SECRETS;
|
|
|
|
|
_read_setting_vpn_secrets (&info);
|
|
|
|
|
info.group = NULL;;
|
|
|
|
|
if (info.error)
|
|
|
|
|
goto out_with_info_error;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
|
|
|
|
|
2018-04-16 12:54:04 +02:00
|
|
|
return g_steal_pointer (&connection);
|
2019-01-02 09:09:37 +01:00
|
|
|
|
|
|
|
|
out_with_info_error:
|
|
|
|
|
g_propagate_error (error, info.error);
|
|
|
|
|
return NULL;
|
2015-02-18 19:59:28 +01:00
|
|
|
}
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
write_setting_value (KeyfileWriterInfo *info,
|
|
|
|
|
NMSetting *setting,
|
|
|
|
|
const NMSettInfoProperty *property_info)
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
{
|
2019-03-22 15:10:41 +01:00
|
|
|
const NMMetaSettingInfo *setting_info;
|
2018-04-14 20:46:47 +02:00
|
|
|
const ParseInfoProperty *pip;
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
const char *key;
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
char numstr[64];
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
GValue value;
|
|
|
|
|
GType type;
|
|
|
|
|
|
|
|
|
|
nm_assert (!info->error);
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_assert ( !property_info->param_spec
|
|
|
|
|
|| nm_streq (property_info->param_spec->name, property_info->name));
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
2019-03-22 15:16:48 +01:00
|
|
|
key = property_info->name;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
2019-08-25 13:54:42 +02:00
|
|
|
_parse_info_find (setting, key, &setting_info, NULL, &pip);
|
2018-07-27 16:11:41 +02:00
|
|
|
|
2019-03-22 15:16:48 +01:00
|
|
|
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;
|
2018-07-27 16:11:41 +02:00
|
|
|
}
|
2018-04-16 15:12:38 +02:00
|
|
|
|
2019-03-22 15:16:48 +01:00
|
|
|
nm_assert (property_info->param_spec);
|
2018-04-16 15:12:38 +02:00
|
|
|
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
/* 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.
|
|
|
|
|
*/
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
if ( (property_info->param_spec->flags & NM_SETTING_PARAM_SECRET)
|
2018-04-16 12:20:59 +02:00
|
|
|
&& !NM_IS_SETTING_VPN (setting)) {
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
|
|
|
|
|
|
if (!nm_setting_get_secret_flags (setting, key, &secret_flags, NULL))
|
2019-01-02 12:39:05 +01:00
|
|
|
g_return_if_reached ();
|
|
|
|
|
if (!_secret_flags_persist_secret (secret_flags))
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
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);
|
|
|
|
|
|
2018-04-16 12:20:59 +02:00
|
|
|
if ( (!pip || !pip->writer_persist_default)
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
&& g_param_value_defaults (property_info->param_spec, &value)) {
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_assert (!g_key_file_has_key (info->keyfile, setting_info->setting_name, key, NULL));
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
goto out_unset_value;
|
2018-04-16 12:20:59 +02:00
|
|
|
}
|
|
|
|
|
|
2019-03-22 15:10:41 +01:00
|
|
|
if ( pip
|
|
|
|
|
&& pip->writer) {
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
pip->writer (info, setting, key, &value);
|
|
|
|
|
goto out_unset_value;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
}
|
|
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
type = G_VALUE_TYPE (&value);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
if (type == G_TYPE_STRING) {
|
|
|
|
|
const char *str;
|
|
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
str = g_value_get_string (&value);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
if (str)
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_string (info->keyfile, setting_info->setting_name, key, str);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
} else if (type == G_TYPE_UINT) {
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
nm_sprintf_buf (numstr, "%u", g_value_get_uint (&value));
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
} else if (type == G_TYPE_INT) {
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
nm_sprintf_buf (numstr, "%d", g_value_get_int (&value));
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
} else if (type == G_TYPE_UINT64) {
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
nm_sprintf_buf (numstr, "%" G_GUINT64_FORMAT, g_value_get_uint64 (&value));
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
} else if (type == G_TYPE_INT64) {
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
nm_sprintf_buf (numstr, "%" G_GINT64_FORMAT, g_value_get_int64 (&value));
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
} else if (type == G_TYPE_BOOLEAN) {
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key,
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
g_value_get_boolean (&value)
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
? "true"
|
|
|
|
|
: "false");
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
} else if (type == G_TYPE_CHAR) {
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
nm_sprintf_buf (numstr, "%d", (int) g_value_get_schar (&value));
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
} else if (type == G_TYPE_BYTES) {
|
|
|
|
|
GBytes *bytes;
|
|
|
|
|
const guint8 *data;
|
|
|
|
|
gsize len = 0;
|
|
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
bytes = g_value_get_boxed (&value);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
data = bytes ? g_bytes_get_data (bytes, &len) : NULL;
|
|
|
|
|
|
|
|
|
|
if (data != NULL && len > 0)
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_integer_list_uint8 (info->keyfile, setting_info->setting_name, key, data, len);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
} else if (type == G_TYPE_STRV) {
|
|
|
|
|
char **array;
|
|
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
array = (char **) g_value_get_boxed (&value);
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_string_list (info->keyfile, setting_info->setting_name, key, (const char **const) array, g_strv_length (array));
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
} else if (type == G_TYPE_HASH_TABLE) {
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
write_hash_of_string (info->keyfile, setting, key, &value);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
} else if (type == G_TYPE_ARRAY) {
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
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));
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr);
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
} else if (G_VALUE_HOLDS_ENUM (&value)) {
|
|
|
|
|
nm_sprintf_buf (numstr, "%d", g_value_get_enum (&value));
|
2019-03-22 15:10:41 +01:00
|
|
|
nm_keyfile_plugin_kf_set_value (info->keyfile, setting_info->setting_name, key, numstr);
|
keyfile: rework handling of GObject properties from keyfile
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
2019-01-03 09:26:54 +01:00
|
|
|
} else
|
|
|
|
|
g_return_if_reached ();
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
|
|
|
|
|
out_unset_value:
|
|
|
|
|
g_value_unset (&value);
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
}
|
|
|
|
|
|
2019-01-30 12:36:13 +01:00
|
|
|
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, "");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
GKeyFile *
|
|
|
|
|
nm_keyfile_write (NMConnection *connection,
|
|
|
|
|
NMKeyfileWriteHandler handler,
|
|
|
|
|
void *user_data,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
2019-01-02 09:09:37 +01:00
|
|
|
gs_unref_keyfile GKeyFile *keyfile = NULL;
|
|
|
|
|
KeyfileWriterInfo info;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
gs_free NMSetting **settings = NULL;
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
guint i, j, n_settings = 0;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
|
|
|
|
|
g_return_val_if_fail (!error || !*error, NULL);
|
|
|
|
|
|
|
|
|
|
if (!nm_connection_verify (connection, error))
|
|
|
|
|
return NULL;
|
|
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
keyfile = g_key_file_new ();
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
info = (KeyfileWriterInfo) {
|
|
|
|
|
.connection = connection,
|
|
|
|
|
.keyfile = keyfile,
|
|
|
|
|
.error = NULL,
|
|
|
|
|
.handler = handler,
|
|
|
|
|
.user_data = user_data,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
settings = nm_connection_get_settings (connection, &n_settings);
|
|
|
|
|
for (i = 0; i < n_settings; i++) {
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
const NMSettInfoSetting *sett_info;
|
|
|
|
|
NMSetting *setting = settings[i];
|
2019-08-25 13:29:41 +02:00
|
|
|
const char *setting_name;
|
|
|
|
|
const char *setting_alias;
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
2019-01-10 19:44:30 +01:00
|
|
|
sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
2019-08-25 13:29:41 +02:00
|
|
|
setting_name = sett_info->setting_class->setting_info->setting_name;
|
|
|
|
|
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
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_gendata_get_all (setting, &keys, NULL);
|
|
|
|
|
|
|
|
|
|
if (n_keys > 0) {
|
|
|
|
|
GHashTable *h = _nm_setting_gendata_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 {
|
|
|
|
|
/* 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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-01-02 09:09:37 +01:00
|
|
|
}
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
for (j = 0; j < sett_info->property_infos_len; j++) {
|
|
|
|
|
const NMSettInfoProperty *property_info = _nm_sett_info_property_info_get_sorted (sett_info, j);
|
2019-01-02 09:09:37 +01:00
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
write_setting_value (&info, setting, property_info);
|
|
|
|
|
if (info.error)
|
|
|
|
|
goto out_with_info_error;
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-25 13:29:41 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-02 13:15:06 +02:00
|
|
|
if (NM_IS_SETTING_WIREGUARD (setting)) {
|
|
|
|
|
_write_setting_wireguard (setting, &info);
|
|
|
|
|
if (info.error)
|
|
|
|
|
goto out_with_info_error;
|
|
|
|
|
}
|
|
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
nm_assert (!info.error);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
}
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
|
libnm/keyfile: don't use nm_setting_enumerate_values() in keyfile reader/writer
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
2019-01-04 16:14:07 +01:00
|
|
|
nm_assert (!info.error);
|
libnm: add generic-data for implementing NMSetting
Add a new way how NMSetting subclasses can be implemented.
Currently, most NMSetting implementations realize all their properties
via GObject properties. That has some downsides:
- the biggest one, is the large effort to add new properties.
Most of them are implemented on a one-by-one basis and they come
with additional API (like native getter functions).
It makes it cumbersome to add more properties.
- for certain properties, it's hard to encode them entirely in
a GObject property. That results in unusable API like
NM_SETTING_IP_CONFIG_ADDRESSES, NM_SETTING_BOND_OPTIONS,
NM_SETTING_USER_DATA. These complex valued properties only
exist, because we currently always need GObject properties
to even implement simple functionality. For example,
nm_setting_duplicate() is entirely implemented via
nm_setting_enumerate_values(), which can only iterate
GObject properies. There is no reason why this is necessary.
Note also how nmcli badly handles bond options and VPN
data. That is only a shortcoming of nmcli and wouldn't
need to be that way. But it happend, because we didn't
keep an open mind that settings might be more than just
accessing GObject properties.
- a major point of NMSetting is to convert to/from a GVariant
from the D-Bus API. As NMSetting needs to squeeze all values
into the static GObject structure, there is no place to
encode invalid or unknown properties. Optimally,
_nm_setting_new_from_dbus() does not loose any information
and a subsequent _nm_setting_to_dbus() can restore the original
variant. That is interesting, because we want that an older
libnm client can talk to a newer NetworkManager version. The
client needs to handle unknown properties gracefully to stay
forward compatible. However, it also should not just drop the
properties on the floor.
Note however, optimally we want that nm_setting_verify() still
can reject settings that have such unknown/invalid values. So,
it should be possible to create an NMSetting instance without
error or loosing information. But verify() should be usable to
identify such settings as invalid.
They also have a few upsides.
- libnm is heavily oriented around GObject. So, we generate
our nm-settings manual based on the gtk-doc. Note however,
how we fail to generate a useful manual for bond.options.
Also note, that there is no reason we couldn't generate
great documentation, even if the properties are not GObject
properties.
- GObject properties do give some functionality like meta-data,
data binding and notification. However, the meta-data is not
sufficient on its own. Note how keyfile and nmcli need extensive
descriptor tables on top of GObject properties, to make this
useful. Note how GObject notifications for NMSetting instances
are usually not useful, aside for data binding like nmtui does.
Also note how NMSettingBond already follows a different paradigm
than using GObject properties. Nowdays, NMSettingBond is considered
a mistake (related bug rh#1032808). Many ideas of NMSettingBond
are flawed, like exposing an inferiour API that reduces everything
to a string hash. Also, it only implemented the options hash inside
NMSettingBond. That means, if we would consider this a good style,
we would have to duplicate this approach in each new setting
implementation.
Add a new style to track data for NMSetting subclasses. It keeps
an internal hash table with all GVariant properies. Also, the
functionality is hooked into NMSetting base class, so all future
subclasses that follow this way, can benefit from this. This approach
has a few similiarties with NMSettingBond, but avoids its flaws.
With this, we also no longer need GObject properties (if we would
also implement generating useful documentation based on non-gkt-doc).
They may be added as accessors if they are useful, but there is no
need for them.
Also, handling the properties as a hash of variants invites for a
more generic approach when handling them. While we still could add
accessors that operate on a one-by-one bases, this leads to a more
generic usage where we apply common functionality to a set of properties.
Also, this is for the moment entirely internal and an implementation
detail. It's entirely up to the NMSetting subclass to make use of this
new style. Also, there are little hooks for the subclass available.
If they turn out to be necessary, they might be added. However, for
the moment, the functionality is restricted to what is useful and
necessary.
2018-07-27 10:05:40 +02:00
|
|
|
|
2019-01-02 09:09:37 +01:00
|
|
|
return g_steal_pointer (&keyfile);
|
|
|
|
|
|
|
|
|
|
out_with_info_error:
|
|
|
|
|
g_propagate_error (error, info.error);
|
|
|
|
|
return NULL;
|
libnm/keyfile: merge keyfile sources (pt2, merge nm-keyfile-writer.c)
Splitting keyfile handling in two "reader.c" and "writer.c" files
is not helpful. What is most interesting, is to see how property XYZ
is serialized to keyfile, and to verify that the parser does the
inverse. For that, it's easier if both the write_xzy() and parse_xyz()
function are beside each other, and not split accross files.
The more important reason is, that both reader and writer have their
separate handler arrays, for special handling of certain properties:
@key_parsers and @key_writers. These two should not be separate but will
be merged. Since they reference static functions, these functions must
all be in the same source file (unless, we put them into headers, which
would be unnecessary complex).
No code was changed, only moved.
2018-04-13 22:32:59 +02:00
|
|
|
}
|
2018-10-19 12:21:18 +02:00
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
nm_assert (path);
|
2018-10-19 12:21:18 +02:00
|
|
|
|
|
|
|
|
/* Matches *.[a-zA-Z0-9]{6} suffix of mkstemp()'s temporary files */
|
|
|
|
|
ptr = strrchr (path, '.');
|
2018-10-21 19:29:35 +02:00
|
|
|
if ( ptr
|
|
|
|
|
&& strspn (&ptr[1], temp_letters) == 6
|
|
|
|
|
&& ptr[7] == '\0')
|
2018-10-19 12:21:18 +02:00
|
|
|
return TRUE;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2018-10-21 19:29:35 +02:00
|
|
|
_check_suffix_impl (const char *base, const char *tag, gsize tag_len)
|
2018-10-19 12:21:18 +02:00
|
|
|
{
|
2018-10-21 19:29:35 +02:00
|
|
|
gsize len;
|
2018-10-19 12:21:18 +02:00
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
nm_assert (base);
|
|
|
|
|
nm_assert (tag);
|
|
|
|
|
nm_assert (strlen (tag) == tag_len);
|
2018-10-19 12:21:18 +02:00
|
|
|
|
|
|
|
|
len = strlen (base);
|
2018-10-21 19:29:35 +02:00
|
|
|
if ( len > tag_len
|
|
|
|
|
&& !g_ascii_strcasecmp (base + len - tag_len, tag))
|
2018-10-19 12:21:18 +02:00
|
|
|
return TRUE;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2018-10-21 19:29:35 +02:00
|
|
|
#define check_suffix(base, tag) _check_suffix_impl ((base), ""tag"", NM_STRLEN (tag))
|
2018-10-19 12:21:18 +02:00
|
|
|
|
|
|
|
|
#define SWP_TAG ".swp"
|
|
|
|
|
#define SWPX_TAG ".swpx"
|
|
|
|
|
#define PEM_TAG ".pem"
|
|
|
|
|
#define DER_TAG ".der"
|
|
|
|
|
|
|
|
|
|
gboolean
|
2018-10-19 12:25:43 +02:00
|
|
|
nm_keyfile_utils_ignore_filename (const char *filename, gboolean require_extension)
|
2018-10-19 12:21:18 +02:00
|
|
|
{
|
2018-10-21 19:29:35 +02:00
|
|
|
const char *base;
|
|
|
|
|
gsize l;
|
2018-10-19 12:21:18 +02:00
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
/* ignore_filename() must mirror nm_keyfile_utils_create_filename() */
|
2018-10-19 12:21:18 +02:00
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
g_return_val_if_fail (filename, TRUE);
|
2018-10-19 12:21:18 +02:00
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
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. */
|
2018-10-19 12:21:18 +02:00
|
|
|
return TRUE;
|
2018-10-21 19:29:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (base[0] == '.') {
|
|
|
|
|
/* don't allow hidden files */
|
2018-10-19 12:21:18 +02:00
|
|
|
return TRUE;
|
2018-10-21 19:29:35 +02:00
|
|
|
}
|
2018-10-19 12:21:18 +02:00
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
l = strlen (base);
|
2018-10-19 12:21:18 +02:00
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
if (require_extension) {
|
2018-10-19 12:25:43 +02:00
|
|
|
if ( l <= NM_STRLEN (NM_KEYFILE_PATH_SUFFIX_NMCONNECTION)
|
2019-07-15 16:53:58 +02:00
|
|
|
|| !NM_STR_HAS_SUFFIX (base, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION))
|
2018-10-19 12:21:18 +02:00
|
|
|
return TRUE;
|
2018-10-21 19:29:35 +02:00
|
|
|
return FALSE;
|
2018-10-19 12:21:18 +02:00
|
|
|
}
|
|
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
/* Ignore backup files */
|
|
|
|
|
if (base[l - 1] == '~')
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2019-07-15 16:53:58 +02:00
|
|
|
/* Ignore temporary files
|
|
|
|
|
*
|
|
|
|
|
* This check is also important to ignore .nmload files (see
|
|
|
|
|
* %NM_KEYFILE_PATH_SUFFIX_NMMETA). */
|
2018-10-21 19:29:35 +02:00
|
|
|
if (check_mkstemp_suffix (base))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
|
|
/* Ignore 802.1x certificates and keys */
|
|
|
|
|
if ( check_suffix (base, PEM_TAG)
|
|
|
|
|
|| check_suffix (base, DER_TAG))
|
|
|
|
|
return TRUE;
|
|
|
|
|
|
2018-10-19 12:21:18 +02:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char *
|
2018-10-19 12:25:43 +02:00
|
|
|
nm_keyfile_utils_create_filename (const char *name,
|
|
|
|
|
gboolean with_extension)
|
2018-10-19 12:21:18 +02:00
|
|
|
{
|
|
|
|
|
GString *str;
|
2018-10-19 12:25:43 +02:00
|
|
|
const char *f = name;
|
2018-10-19 12:21:18 +02:00
|
|
|
/* 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 = '_';
|
|
|
|
|
|
2018-10-19 12:25:43 +02:00
|
|
|
g_return_val_if_fail (name && name[0], NULL);
|
2018-10-19 12:21:18 +02:00
|
|
|
|
|
|
|
|
str = g_string_sized_new (60);
|
|
|
|
|
|
|
|
|
|
/* Convert '/' to ESCAPE_CHAR */
|
2018-10-19 12:25:43 +02:00
|
|
|
for (f = name; f[0]; f++) {
|
2018-10-19 12:21:18 +02:00
|
|
|
if (f[0] == '/')
|
|
|
|
|
g_string_append_c (str, ESCAPE_CHAR);
|
|
|
|
|
else
|
|
|
|
|
g_string_append_c (str, f[0]);
|
|
|
|
|
}
|
|
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
/* nm_keyfile_utils_create_filename() must avoid anything that ignore_filename() would reject.
|
2018-10-19 12:21:18 +02:00
|
|
|
* We can escape here more aggressivly then what we would read back. */
|
2018-10-21 19:29:35 +02:00
|
|
|
if (str->str[0] == '.')
|
2018-10-19 12:21:18 +02:00
|
|
|
str->str[0] = ESCAPE_CHAR2;
|
2018-10-21 19:29:35 +02:00
|
|
|
if (str->str[str->len - 1] == '~')
|
2018-10-19 12:21:18 +02:00
|
|
|
str->str[str->len - 1] = ESCAPE_CHAR2;
|
|
|
|
|
if ( check_mkstemp_suffix (str->str)
|
|
|
|
|
|| check_suffix (str->str, PEM_TAG)
|
|
|
|
|
|| check_suffix (str->str, DER_TAG))
|
|
|
|
|
g_string_append_c (str, ESCAPE_CHAR2);
|
|
|
|
|
|
|
|
|
|
if (with_extension)
|
2018-10-19 12:25:43 +02:00
|
|
|
g_string_append (str, NM_KEYFILE_PATH_SUFFIX_NMCONNECTION);
|
2018-10-19 12:21:18 +02:00
|
|
|
|
2018-10-21 19:29:35 +02:00
|
|
|
/* nm_keyfile_utils_create_filename() must mirror ignore_filename() */
|
|
|
|
|
nm_assert (!strchr (str->str, '/'));
|
|
|
|
|
nm_assert (!nm_keyfile_utils_ignore_filename (str->str, with_extension));
|
|
|
|
|
|
2018-10-19 12:21:18 +02:00
|
|
|
return g_string_free (str, FALSE);;
|
|
|
|
|
}
|