|
Packit Service |
87a54e |
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
Packit |
5756e2 |
/*
|
|
Packit |
5756e2 |
* Copyright (C) 2017 Red Hat, Inc.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
|
|
Packit Service |
2bceb2 |
#include "libnm-core/nm-default-libnm-core.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "nm-setting-user.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#include "nm-setting.h"
|
|
Packit |
5756e2 |
#include "nm-setting-private.h"
|
|
Packit |
5756e2 |
#include "nm-utils-private.h"
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* SECTION:nm-setting-user
|
|
Packit |
5756e2 |
* @short_description: Describes user properties
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* The #NMSettingUser object is a #NMSetting subclass that allow to attach
|
|
Packit |
5756e2 |
* arbitrary user data to #NMConnection objects.
|
|
Packit |
5756e2 |
**/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#define MAX_NUM_KEYS 256
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
NM_GOBJECT_PROPERTIES_DEFINE(NMSettingUser, PROP_DATA, );
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
typedef struct {
|
|
Packit Service |
a1bd4f |
GHashTable * data;
|
|
Packit Service |
a1bd4f |
GHashTable * data_invalid;
|
|
Packit Service |
a1bd4f |
const char **keys;
|
|
Packit |
5756e2 |
} NMSettingUserPrivate;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* NMSettingUser:
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* General User Profile Settings
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
struct _NMSettingUser {
|
|
Packit Service |
a1bd4f |
NMSetting parent;
|
|
Packit Service |
a1bd4f |
NMSettingUserPrivate _priv;
|
|
Packit |
5756e2 |
};
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
struct _NMSettingUserClass {
|
|
Packit Service |
a1bd4f |
NMSettingClass parent;
|
|
Packit |
5756e2 |
};
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
G_DEFINE_TYPE(NMSettingUser, nm_setting_user, NM_TYPE_SETTING)
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
#define NM_SETTING_USER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMSettingUser, NM_IS_SETTING_USER)
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
_key_char_is_regular(char ch)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
/* allow words of printable characters, plus some
|
|
Packit Service |
a1bd4f |
* special characters, for example to support base64 encoding. */
|
|
Packit Service |
a1bd4f |
return (ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z') || (ch >= '0' && ch <= '9')
|
|
Packit Service |
a1bd4f |
|| NM_IN_SET(ch, '-', '_', '+', '/', '=');
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nm_setting_user_check_key:
|
|
Packit |
5756e2 |
* @key: the key to check
|
|
Packit |
5756e2 |
* @error: a #GError, %NULL to ignore.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Checks whether @key is a valid user data key. This means,
|
|
Packit |
5756e2 |
* key is not %NULL, not too large and valid ASCII. Also,
|
|
Packit |
5756e2 |
* only digits and numbers are allowed with a few special
|
|
Packit |
5756e2 |
* characters. The key must contain at least one '.' and
|
|
Packit |
5756e2 |
* look like a fully qualified DNS name.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Since: 1.8
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: %TRUE if @key is a valid user data key.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nm_setting_user_check_key(const char *key, GError **error)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gsize len;
|
|
Packit Service |
a1bd4f |
gboolean has_dot;
|
|
Packit Service |
a1bd4f |
char ch;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(!error || !*error, FALSE);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!key || !key[0]) {
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("missing key"));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
len = strlen(key);
|
|
Packit Service |
a1bd4f |
if (len > 255) {
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("key is too long"));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (!g_utf8_validate(key, len, NULL)) {
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("key must be UTF8"));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
has_dot = FALSE;
|
|
Packit Service |
a1bd4f |
while (TRUE) {
|
|
Packit Service |
a1bd4f |
ch = (key++)[0];
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/* Allow something that looks like a FQN, separating namespaces by a single '.'
|
|
Packit Service |
a1bd4f |
* We want to print the keys nicely in nmcli requiring escaping.
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* If a user really has to encode special values in the name, he may base64 encode it. */
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!_key_char_is_regular(ch))
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
while (_key_char_is_regular(key[0]))
|
|
Packit Service |
a1bd4f |
key++;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
ch = key[0];
|
|
Packit Service |
a1bd4f |
if (ch == '\0') {
|
|
Packit Service |
a1bd4f |
if (!has_dot) {
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("key requires a '.' for a namespace"));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (ch != '.')
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
has_dot = TRUE;
|
|
Packit Service |
a1bd4f |
ch = (++key)[0];
|
|
Packit Service |
a1bd4f |
if (ch == '.') {
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("key cannot contain \"..\""));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("key contains invalid characters"));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nm_setting_user_check_val:
|
|
Packit |
5756e2 |
* @val: the value to check
|
|
Packit |
5756e2 |
* @error: a #GError, %NULL to ignore.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Checks whether @val is a valid user data value. This means,
|
|
Packit |
5756e2 |
* value is not %NULL, not too large and valid UTF-8.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Since: 1.8
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: %TRUE if @val is a valid user data value.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nm_setting_user_check_val(const char *val, GError **error)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
gsize len;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(!error || !*error, FALSE);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!val) {
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("value is missing"));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
len = strlen(val);
|
|
Packit Service |
a1bd4f |
if (len > 8 * 1024) {
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("value is too large"));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!g_utf8_validate(val, len, NULL)) {
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("value is not valid UTF8"));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static GHashTable *
|
|
Packit Service |
a1bd4f |
_create_data_hash(void)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
return g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nm_setting_user_get_keys:
|
|
Packit |
5756e2 |
* @setting: the #NMSettingUser
|
|
Packit |
5756e2 |
* @out_len: (out): the length of the returned array
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: (array length=out_len) (transfer none): a
|
|
Packit |
5756e2 |
* %NULL-terminated array containing each key from the table.
|
|
Packit |
5756e2 |
**/
|
|
Packit Service |
a1bd4f |
const char *const *
|
|
Packit Service |
a1bd4f |
nm_setting_user_get_keys(NMSettingUser *setting, guint *out_len)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMSettingUser * self = setting;
|
|
Packit Service |
a1bd4f |
NMSettingUserPrivate *priv;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(NM_IS_SETTING_USER(self), NULL);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
priv = NM_SETTING_USER_GET_PRIVATE(self);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
if (priv->keys) {
|
|
Packit Service |
a1bd4f |
NM_SET_OUT(out_len, g_hash_table_size(priv->data));
|
|
Packit Service |
a1bd4f |
return priv->keys;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
priv->keys = nm_utils_strdict_get_keys(priv->data, TRUE, out_len);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
/* don't return %NULL, but hijack the @keys fields as a pseudo
|
|
Packit Service |
a1bd4f |
* empty strv array. */
|
|
Packit Service |
a1bd4f |
return priv->keys ?: ((const char **) &priv->keys);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nm_setting_user_get_data:
|
|
Packit |
5756e2 |
* @setting: the #NMSettingUser instance
|
|
Packit |
5756e2 |
* @key: the key to lookup
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Since: 1.8
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: (transfer none): the value associated with @key or %NULL if no such
|
|
Packit |
5756e2 |
* value exists.
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
const char *
|
|
Packit Service |
a1bd4f |
nm_setting_user_get_data(NMSettingUser *setting, const char *key)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMSettingUser * self = setting;
|
|
Packit Service |
a1bd4f |
NMSettingUserPrivate *priv;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(NM_IS_SETTING_USER(self), NULL);
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(key, NULL);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
priv = NM_SETTING_USER_GET_PRIVATE(self);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
if (!priv->data)
|
|
Packit Service |
a1bd4f |
return NULL;
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
return g_hash_table_lookup(priv->data, key);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nm_setting_user_set_data:
|
|
Packit |
5756e2 |
* @setting: the #NMSettingUser instance
|
|
Packit |
5756e2 |
* @key: the key to set
|
|
Packit |
5756e2 |
* @val: (allow-none): the value to set or %NULL to clear a key.
|
|
Packit |
5756e2 |
* @error: (allow-none): optional error argument
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Since: 1.8
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: %TRUE if the operation was successful. The operation
|
|
Packit |
5756e2 |
* can fail if @key or @val are not valid strings according
|
|
Packit |
5756e2 |
* to nm_setting_user_check_key() and nm_setting_user_check_val().
|
|
Packit |
5756e2 |
*/
|
|
Packit |
5756e2 |
gboolean
|
|
Packit Service |
a1bd4f |
nm_setting_user_set_data(NMSettingUser *setting, const char *key, const char *val, GError **error)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMSettingUser * self = setting;
|
|
Packit Service |
a1bd4f |
NMSettingUserPrivate *priv;
|
|
Packit Service |
a1bd4f |
gboolean changed = FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(NM_IS_SETTING_USER(self), FALSE);
|
|
Packit Service |
a1bd4f |
g_return_val_if_fail(!error || !*error, FALSE);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!nm_setting_user_check_key(key, error))
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (val && !nm_setting_user_check_val(val, error))
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
priv = NM_SETTING_USER_GET_PRIVATE(self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!val) {
|
|
Packit Service |
a1bd4f |
if (priv->data && g_hash_table_remove(priv->data, key)) {
|
|
Packit Service |
a1bd4f |
nm_clear_g_free(&priv->keys);
|
|
Packit Service |
a1bd4f |
changed = TRUE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
goto out;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (priv->data) {
|
|
Packit Service |
a1bd4f |
const char *key2, *val2;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (g_hash_table_lookup_extended(priv->data, key, (gpointer *) &key2, (gpointer *) &val2)) {
|
|
Packit Service |
a1bd4f |
if (nm_streq(val, val2))
|
|
Packit Service |
a1bd4f |
goto out;
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
if (g_hash_table_size(priv->data) >= MAX_NUM_KEYS) {
|
|
Packit Service |
a1bd4f |
/* limit the number of valid keys */
|
|
Packit Service |
a1bd4f |
g_set_error_literal(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("maximum number of user data entries reached"));
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
nm_clear_g_free(&priv->keys);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
} else
|
|
Packit Service |
a1bd4f |
priv->data = _create_data_hash();
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_hash_table_insert(priv->data, g_strdup(key), g_strdup(val));
|
|
Packit Service |
a1bd4f |
changed = TRUE;
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
out:
|
|
Packit Service |
a1bd4f |
if (priv->data_invalid) {
|
|
Packit Service |
a1bd4f |
/* setting a value purges all invalid values that were set
|
|
Packit Service |
a1bd4f |
* via GObject property. */
|
|
Packit Service |
a1bd4f |
changed = TRUE;
|
|
Packit Service |
a1bd4f |
nm_clear_pointer(&priv->data_invalid, g_hash_table_unref);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (changed)
|
|
Packit Service |
a1bd4f |
_notify(self, PROP_DATA);
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static gboolean
|
|
Packit Service |
a1bd4f |
verify(NMSetting *setting, NMConnection *connection, GError **error)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMSettingUser * self = NM_SETTING_USER(setting);
|
|
Packit Service |
a1bd4f |
NMSettingUserPrivate *priv = NM_SETTING_USER_GET_PRIVATE(self);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (priv->data_invalid) {
|
|
Packit Service |
a1bd4f |
const char * key, *val;
|
|
Packit Service |
a1bd4f |
GHashTableIter iter;
|
|
Packit Service |
a1bd4f |
gs_free_error GError *local = NULL;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_hash_table_iter_init(&iter, priv->data_invalid);
|
|
Packit Service |
a1bd4f |
while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) {
|
|
Packit Service |
a1bd4f |
if (!nm_setting_user_check_key(key, &local)) {
|
|
Packit Service |
a1bd4f |
g_set_error(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_FAILED,
|
|
Packit Service |
a1bd4f |
_("invalid key \"%s\": %s"),
|
|
Packit Service |
a1bd4f |
key,
|
|
Packit Service |
a1bd4f |
local->message);
|
|
Packit Service |
a1bd4f |
} else if (!nm_setting_user_check_val(val, &local)) {
|
|
Packit Service |
a1bd4f |
g_set_error(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_FAILED,
|
|
Packit Service |
a1bd4f |
_("invalid value for \"%s\": %s"),
|
|
Packit Service |
a1bd4f |
key,
|
|
Packit Service |
a1bd4f |
local->message);
|
|
Packit Service |
a1bd4f |
} else {
|
|
Packit Service |
a1bd4f |
nm_assert_not_reached();
|
|
Packit Service |
a1bd4f |
continue;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
g_prefix_error(error, "%s.%s: ", NM_SETTING_USER_SETTING_NAME, NM_SETTING_USER_DATA);
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
nm_assert_not_reached();
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (priv->data && g_hash_table_size(priv->data) > MAX_NUM_KEYS) {
|
|
Packit Service |
a1bd4f |
g_set_error(error,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR,
|
|
Packit Service |
a1bd4f |
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
Packit Service |
a1bd4f |
_("maximum number of user data entries reached (%u instead of %u)"),
|
|
Packit Service |
a1bd4f |
g_hash_table_size(priv->data),
|
|
Packit Service |
a1bd4f |
(unsigned) MAX_NUM_KEYS);
|
|
Packit Service |
a1bd4f |
g_prefix_error(error, "%s.%s: ", NM_SETTING_USER_SETTING_NAME, NM_SETTING_USER_DATA);
|
|
Packit Service |
a1bd4f |
return FALSE;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static NMTernary
|
|
Packit Service |
a1bd4f |
compare_property(const NMSettInfoSetting *sett_info,
|
|
Packit Service |
a1bd4f |
guint property_idx,
|
|
Packit Service |
a1bd4f |
NMConnection * con_a,
|
|
Packit Service |
a1bd4f |
NMSetting * set_a,
|
|
Packit Service |
a1bd4f |
NMConnection * con_b,
|
|
Packit Service |
a1bd4f |
NMSetting * set_b,
|
|
Packit Service |
a1bd4f |
NMSettingCompareFlags flags)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMSettingUserPrivate *priv, *pri2;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (nm_streq(sett_info->property_infos[property_idx].name, NM_SETTING_USER_DATA)) {
|
|
Packit Service |
a1bd4f |
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
|
|
Packit Service |
a1bd4f |
return NM_TERNARY_DEFAULT;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (!set_b)
|
|
Packit Service |
a1bd4f |
return TRUE;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
priv = NM_SETTING_USER_GET_PRIVATE(NM_SETTING_USER(set_a));
|
|
Packit Service |
a1bd4f |
pri2 = NM_SETTING_USER_GET_PRIVATE(NM_SETTING_USER(set_b));
|
|
Packit Service |
a1bd4f |
return nm_utils_hashtable_equal(priv->data, pri2->data, TRUE, g_str_equal)
|
|
Packit Service |
a1bd4f |
&& nm_utils_hashtable_equal(priv->data_invalid,
|
|
Packit Service |
a1bd4f |
pri2->data_invalid,
|
|
Packit Service |
a1bd4f |
TRUE,
|
|
Packit Service |
a1bd4f |
g_str_equal);
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
return NM_SETTING_CLASS(nm_setting_user_parent_class)
|
|
Packit Service |
a1bd4f |
->compare_property(sett_info, property_idx, con_a, set_a, con_b, set_b, flags);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMSettingUser * self = NM_SETTING_USER(object);
|
|
Packit Service |
a1bd4f |
NMSettingUserPrivate *priv = NM_SETTING_USER_GET_PRIVATE(self);
|
|
Packit Service |
a1bd4f |
GHashTableIter iter;
|
|
Packit Service |
a1bd4f |
GHashTable * data;
|
|
Packit Service |
a1bd4f |
const char * key, *val;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
switch (prop_id) {
|
|
Packit Service |
a1bd4f |
case PROP_DATA:
|
|
Packit Service |
a1bd4f |
data = _create_data_hash();
|
|
Packit Service |
a1bd4f |
if (priv->data) {
|
|
Packit Service |
a1bd4f |
g_hash_table_iter_init(&iter, priv->data);
|
|
Packit Service |
a1bd4f |
while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val))
|
|
Packit Service |
a1bd4f |
g_hash_table_insert(data, g_strdup(key), g_strdup(val));
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (priv->data_invalid) {
|
|
Packit Service |
a1bd4f |
g_hash_table_iter_init(&iter, priv->data_invalid);
|
|
Packit Service |
a1bd4f |
while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val))
|
|
Packit Service |
a1bd4f |
g_hash_table_insert(data, g_strdup(key), g_strdup(val));
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
g_value_take_boxed(value, data);
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
default:
|
|
Packit Service |
a1bd4f |
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMSettingUser * self = NM_SETTING_USER(object);
|
|
Packit Service |
a1bd4f |
NMSettingUserPrivate *priv = NM_SETTING_USER_GET_PRIVATE(self);
|
|
Packit Service |
a1bd4f |
GHashTableIter iter;
|
|
Packit Service |
a1bd4f |
GHashTable * data;
|
|
Packit Service |
a1bd4f |
const char * key, *val;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
switch (prop_id) {
|
|
Packit Service |
a1bd4f |
case PROP_DATA:
|
|
Packit Service |
a1bd4f |
nm_clear_g_free(&priv->keys);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
data = g_value_get_boxed(value);
|
|
Packit Service |
a1bd4f |
if (!data || !g_hash_table_size(data)) {
|
|
Packit Service |
a1bd4f |
nm_clear_pointer(&priv->data, g_hash_table_unref);
|
|
Packit Service |
a1bd4f |
nm_clear_pointer(&priv->data_invalid, g_hash_table_unref);
|
|
Packit Service |
a1bd4f |
return;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (priv->data)
|
|
Packit Service |
a1bd4f |
g_hash_table_remove_all(priv->data);
|
|
Packit Service |
a1bd4f |
else
|
|
Packit Service |
a1bd4f |
priv->data = _create_data_hash();
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
if (priv->data_invalid)
|
|
Packit Service |
a1bd4f |
g_hash_table_remove_all(priv->data_invalid);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_hash_table_iter_init(&iter, data);
|
|
Packit Service |
a1bd4f |
while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) {
|
|
Packit Service |
a1bd4f |
if (nm_setting_user_check_key(key, NULL) && nm_setting_user_check_val(val, NULL))
|
|
Packit Service |
a1bd4f |
g_hash_table_insert(priv->data, g_strdup(key), g_strdup(val));
|
|
Packit Service |
a1bd4f |
else {
|
|
Packit Service |
a1bd4f |
if (!priv->data_invalid)
|
|
Packit Service |
a1bd4f |
priv->data_invalid = _create_data_hash();
|
|
Packit Service |
a1bd4f |
g_hash_table_insert(priv->data_invalid, g_strdup(key), g_strdup(val));
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
}
|
|
Packit Service |
a1bd4f |
if (priv->data_invalid && !g_hash_table_size(priv->data_invalid))
|
|
Packit Service |
a1bd4f |
nm_clear_pointer(&priv->data_invalid, g_hash_table_unref);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
default:
|
|
Packit Service |
a1bd4f |
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
Packit Service |
a1bd4f |
break;
|
|
Packit Service |
a1bd4f |
}
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/*****************************************************************************/
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
nm_setting_user_init(NMSettingUser *self)
|
|
Packit Service |
a1bd4f |
{}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
/**
|
|
Packit |
5756e2 |
* nm_setting_user_new:
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Creates a new #NMSettingUser object with default values.
|
|
Packit |
5756e2 |
*
|
|
Packit |
5756e2 |
* Returns: the new empty #NMSettingUser object
|
|
Packit |
5756e2 |
**/
|
|
Packit Service |
a1bd4f |
NMSetting *
|
|
Packit Service |
a1bd4f |
nm_setting_user_new(void)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
return g_object_new(NM_TYPE_SETTING_USER, NULL);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
finalize(GObject *object)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
NMSettingUser * self = NM_SETTING_USER(object);
|
|
Packit Service |
a1bd4f |
NMSettingUserPrivate *priv = NM_SETTING_USER_GET_PRIVATE(self);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
g_free(priv->keys);
|
|
Packit Service |
a1bd4f |
if (priv->data)
|
|
Packit Service |
a1bd4f |
g_hash_table_unref(priv->data);
|
|
Packit Service |
a1bd4f |
if (priv->data_invalid)
|
|
Packit Service |
a1bd4f |
g_hash_table_unref(priv->data_invalid);
|
|
Packit |
5756e2 |
|
|
Packit Service |
a1bd4f |
G_OBJECT_CLASS(nm_setting_user_parent_class)->finalize(object);
|
|
Packit |
5756e2 |
}
|
|
Packit |
5756e2 |
|
|
Packit |
5756e2 |
static void
|
|
Packit Service |
a1bd4f |
nm_setting_user_class_init(NMSettingUserClass *klass)
|
|
Packit |
5756e2 |
{
|
|
Packit Service |
a1bd4f |
GObjectClass * object_class = G_OBJECT_CLASS(klass);
|
|
Packit Service |
a1bd4f |
NMSettingClass *setting_class = NM_SETTING_CLASS(klass);
|
|
Packit Service |
a1bd4f |
GArray * properties_override = _nm_sett_info_property_override_create_array();
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
object_class->get_property = get_property;
|
|
Packit Service |
a1bd4f |
object_class->set_property = set_property;
|
|
Packit Service |
a1bd4f |
object_class->finalize = finalize;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
setting_class->compare_property = compare_property;
|
|
Packit Service |
a1bd4f |
setting_class->verify = verify;
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
/**
|
|
Packit Service |
a1bd4f |
* NMSettingUser:data: (type GHashTable(utf8,utf8))
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* A dictionary of key/value pairs with user data. This data is ignored by NetworkManager
|
|
Packit Service |
a1bd4f |
* and can be used at the users discretion. The keys only support a strict ascii format,
|
|
Packit Service |
a1bd4f |
* but the values can be arbitrary UTF8 strings up to a certain length.
|
|
Packit Service |
a1bd4f |
*
|
|
Packit Service |
a1bd4f |
* Since: 1.8
|
|
Packit Service |
a1bd4f |
**/
|
|
Packit Service |
a1bd4f |
/* ---ifcfg-rh---
|
|
Packit Service |
a1bd4f |
* property: data
|
|
Packit Service |
a1bd4f |
* variable: NM_USER_*
|
|
Packit Service |
a1bd4f |
* description: each key/value pair is stored as a separate variable with
|
|
Packit Service |
a1bd4f |
* name composed by concatenating NM_USER_ with the encoded key. The key is
|
|
Packit Service |
a1bd4f |
* encoded by substituting lowercase letters with uppercase and prepending
|
|
Packit Service |
a1bd4f |
* uppercase letters with an underscore. A dot is encoded as a double
|
|
Packit Service |
a1bd4f |
* underscore. Remaining characters are encoded as underscore followed by a
|
|
Packit Service |
a1bd4f |
* 3 digit octal representation of the character.
|
|
Packit Service |
a1bd4f |
* example: NM_USER_FOO__BAR=something
|
|
Packit Service |
a1bd4f |
* ---end---
|
|
Packit Service |
a1bd4f |
*/
|
|
Packit Service |
a1bd4f |
obj_properties[PROP_DATA] = g_param_spec_boxed(NM_SETTING_USER_DATA,
|
|
Packit Service |
a1bd4f |
"",
|
|
Packit Service |
a1bd4f |
"",
|
|
Packit Service |
a1bd4f |
G_TYPE_HASH_TABLE,
|
|
Packit Service |
a1bd4f |
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
|
Packit Service |
a1bd4f |
_nm_properties_override_gobj(properties_override,
|
|
Packit Service |
a1bd4f |
obj_properties[PROP_DATA],
|
|
Packit Service |
a1bd4f |
&nm_sett_info_propert_type_strdict);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
|
Packit Service |
a1bd4f |
|
|
Packit Service |
a1bd4f |
_nm_setting_class_commit_full(setting_class,
|
|
Packit Service |
a1bd4f |
NM_META_SETTING_TYPE_USER,
|
|
Packit Service |
a1bd4f |
NULL,
|
|
Packit Service |
a1bd4f |
properties_override);
|
|
Packit |
5756e2 |
}
|