mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-03 06:45:26 +00:00
88071abb43
Our coding style recommends C style comments (/* */) instead of C++ (//). Also, systemd (which we partly fork) uses C style comments for the SPDX-License-Identifier. Unify the style. $ sed -i '1 s#// SPDX-License-Identifier: \([^ ]\+\)$#/* SPDX-License-Identifier: \1 */#' -- $(git ls-files -- '*.[hc]' '*.[hc]pp')
1234 lines
43 KiB
C
1234 lines
43 KiB
C
/* SPDX-License-Identifier: LGPL-2.1+ */
|
|
/*
|
|
* Copyright (C) 2007 - 2013 Red Hat, Inc.
|
|
* Copyright (C) 2007 - 2008 Novell, Inc.
|
|
*/
|
|
|
|
#include "nm-default.h"
|
|
|
|
#include "nm-setting-vpn.h"
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "nm-glib-aux/nm-secret-utils.h"
|
|
#include "nm-utils.h"
|
|
#include "nm-utils-private.h"
|
|
#include "nm-setting-private.h"
|
|
|
|
/**
|
|
* SECTION:nm-setting-vpn
|
|
* @short_description: Describes connection properties for Virtual Private Networks
|
|
*
|
|
* The #NMSettingVpn object is a #NMSetting subclass that describes properties
|
|
* necessary for connection to Virtual Private Networks. NetworkManager uses
|
|
* a plugin architecture to allow easier use of new VPN types, and this
|
|
* setting abstracts the configuration for those plugins. Since the configuration
|
|
* options are only known to the VPN plugins themselves, the VPN configuration
|
|
* options are stored as key/value pairs of strings rather than GObject
|
|
* properties.
|
|
**/
|
|
|
|
/*****************************************************************************/
|
|
|
|
NM_GOBJECT_PROPERTIES_DEFINE(NMSettingVpn,
|
|
PROP_SERVICE_TYPE,
|
|
PROP_USER_NAME,
|
|
PROP_PERSISTENT,
|
|
PROP_DATA,
|
|
PROP_SECRETS,
|
|
PROP_TIMEOUT, );
|
|
|
|
typedef struct {
|
|
char *service_type;
|
|
|
|
/* username of the user requesting this connection, thus
|
|
* it's really only valid for user connections, and it also
|
|
* should never be saved out to persistent config.
|
|
*/
|
|
char *user_name;
|
|
|
|
/* Whether the VPN stays up across link changes, until the user
|
|
* explicitly disconnects it.
|
|
*/
|
|
gboolean persistent;
|
|
|
|
/* The hash table is created at setting object
|
|
* init time and should not be replaced. It is
|
|
* a char * -> char * mapping, and both the key
|
|
* and value are owned by the hash table, and should
|
|
* be allocated with functions whose value can be
|
|
* freed with g_free(). Should not contain secrets.
|
|
*/
|
|
GHashTable *data;
|
|
|
|
/* The hash table is created at setting object
|
|
* init time and should not be replaced. It is
|
|
* a char * -> char * mapping, and both the key
|
|
* and value are owned by the hash table, and should
|
|
* be allocated with functions whose value can be
|
|
* freed with g_free(). Should contain secrets only.
|
|
*/
|
|
GHashTable *secrets;
|
|
|
|
/* Timeout for the VPN service to establish the connection */
|
|
guint32 timeout;
|
|
} NMSettingVpnPrivate;
|
|
|
|
G_DEFINE_TYPE(NMSettingVpn, nm_setting_vpn, NM_TYPE_SETTING)
|
|
|
|
#define NM_SETTING_VPN_GET_PRIVATE(o) \
|
|
(G_TYPE_INSTANCE_GET_PRIVATE((o), NM_TYPE_SETTING_VPN, NMSettingVpnPrivate))
|
|
|
|
/*****************************************************************************/
|
|
|
|
static GHashTable *
|
|
_ensure_strdict(GHashTable **p_hash, gboolean for_secrets)
|
|
{
|
|
if (!*p_hash) {
|
|
*p_hash = g_hash_table_new_full(nm_str_hash,
|
|
g_str_equal,
|
|
g_free,
|
|
for_secrets ? (GDestroyNotify) nm_free_secret : g_free);
|
|
}
|
|
return *p_hash;
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
/**
|
|
* nm_setting_vpn_get_service_type:
|
|
* @setting: the #NMSettingVpn
|
|
*
|
|
* Returns the service name of the VPN, which identifies the specific VPN
|
|
* plugin that should be used to connect to this VPN.
|
|
*
|
|
* Returns: the VPN plugin's service name
|
|
**/
|
|
const char *
|
|
nm_setting_vpn_get_service_type(NMSettingVpn *setting)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
|
|
|
|
return NM_SETTING_VPN_GET_PRIVATE(setting)->service_type;
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_get_user_name:
|
|
* @setting: the #NMSettingVpn
|
|
*
|
|
* Returns: the #NMSettingVpn:user-name property of the setting
|
|
**/
|
|
const char *
|
|
nm_setting_vpn_get_user_name(NMSettingVpn *setting)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
|
|
|
|
return NM_SETTING_VPN_GET_PRIVATE(setting)->user_name;
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_get_persistent:
|
|
* @setting: the #NMSettingVpn
|
|
*
|
|
* Returns: the #NMSettingVpn:persistent property of the setting
|
|
**/
|
|
gboolean
|
|
nm_setting_vpn_get_persistent(NMSettingVpn *setting)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), FALSE);
|
|
|
|
return NM_SETTING_VPN_GET_PRIVATE(setting)->persistent;
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_get_num_data_items:
|
|
* @setting: the #NMSettingVpn
|
|
*
|
|
* Gets number of key/value pairs of VPN configuration data.
|
|
*
|
|
* Returns: the number of VPN plugin specific configuration data items
|
|
**/
|
|
guint32
|
|
nm_setting_vpn_get_num_data_items(NMSettingVpn *setting)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), 0);
|
|
|
|
return nm_g_hash_table_size(NM_SETTING_VPN_GET_PRIVATE(setting)->data);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_add_data_item:
|
|
* @setting: the #NMSettingVpn
|
|
* @key: a name that uniquely identifies the given value @item
|
|
* @item: (allow-none): the value to be referenced by @key
|
|
*
|
|
* Establishes a relationship between @key and @item internally in the
|
|
* setting which may be retrieved later. Should not be used to store passwords
|
|
* or other secrets, which is what nm_setting_vpn_add_secret() is for.
|
|
*
|
|
* Before 1.24, @item must not be %NULL and not an empty string. Since 1.24,
|
|
* @item can be set to an empty string. It can also be set to %NULL to unset
|
|
* the key. In that case, the behavior is as if calling nm_setting_vpn_remove_data_item().
|
|
**/
|
|
void
|
|
nm_setting_vpn_add_data_item(NMSettingVpn *setting, const char *key, const char *item)
|
|
{
|
|
if (!item) {
|
|
nm_setting_vpn_remove_data_item(setting, key);
|
|
return;
|
|
}
|
|
|
|
g_return_if_fail(NM_IS_SETTING_VPN(setting));
|
|
g_return_if_fail(key && key[0]);
|
|
|
|
g_hash_table_insert(_ensure_strdict(&NM_SETTING_VPN_GET_PRIVATE(setting)->data, FALSE),
|
|
g_strdup(key),
|
|
g_strdup(item));
|
|
_notify(setting, PROP_DATA);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_get_data_item:
|
|
* @setting: the #NMSettingVpn
|
|
* @key: the name of the data item to retrieve
|
|
*
|
|
* Retrieves the data item of a key/value relationship previously established
|
|
* by nm_setting_vpn_add_data_item().
|
|
*
|
|
* Returns: the data item, if any
|
|
**/
|
|
const char *
|
|
nm_setting_vpn_get_data_item(NMSettingVpn *setting, const char *key)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
|
|
g_return_val_if_fail(key && key[0], NULL);
|
|
|
|
return nm_g_hash_table_lookup(NM_SETTING_VPN_GET_PRIVATE(setting)->data, key);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_get_data_keys:
|
|
* @setting: the #NMSettingVpn
|
|
* @out_length: (allow-none) (out): the length of the returned array
|
|
*
|
|
* Retrieves every data key inside @setting, as an array.
|
|
*
|
|
* Returns: (array length=out_length) (transfer container): a
|
|
* %NULL-terminated array containing each data key or %NULL if
|
|
* there are no data items.
|
|
*
|
|
* Since: 1.12
|
|
*/
|
|
const char **
|
|
nm_setting_vpn_get_data_keys(NMSettingVpn *setting, guint *out_length)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
|
|
|
|
return nm_utils_strdict_get_keys(NM_SETTING_VPN_GET_PRIVATE(setting)->data, TRUE, out_length);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_remove_data_item:
|
|
* @setting: the #NMSettingVpn
|
|
* @key: the name of the data item to remove
|
|
*
|
|
* Deletes a key/value relationship previously established by
|
|
* nm_setting_vpn_add_data_item().
|
|
*
|
|
* Returns: %TRUE if the data item was found and removed from the internal list,
|
|
* %FALSE if it was not.
|
|
**/
|
|
gboolean
|
|
nm_setting_vpn_remove_data_item(NMSettingVpn *setting, const char *key)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), FALSE);
|
|
g_return_val_if_fail(key && key[0], FALSE);
|
|
|
|
if (nm_g_hash_table_remove(NM_SETTING_VPN_GET_PRIVATE(setting)->data, key)) {
|
|
_notify(setting, PROP_DATA);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
foreach_item_helper(NMSettingVpn *self, GHashTable **p_hash, NMVpnIterFunc func, gpointer user_data)
|
|
{
|
|
gs_unref_object NMSettingVpn *self_keep_alive = NULL;
|
|
gs_strfreev char ** keys = NULL;
|
|
guint i, len;
|
|
|
|
nm_assert(NM_IS_SETTING_VPN(self));
|
|
nm_assert(func);
|
|
|
|
keys = nm_utils_strv_make_deep_copied(nm_utils_strdict_get_keys(*p_hash, TRUE, &len));
|
|
if (len == 0u) {
|
|
nm_assert(!keys);
|
|
return;
|
|
}
|
|
|
|
if (len > 1u)
|
|
self_keep_alive = g_object_ref(self);
|
|
|
|
for (i = 0; i < len; i++) {
|
|
/* NOTE: note that we call the function with a clone of @key,
|
|
* not with the actual key from the dictionary.
|
|
*
|
|
* The @value on the other hand, is not cloned but retrieved before
|
|
* invoking @func(). That means, if @func() modifies the setting while
|
|
* being called, the values are as they currently are, but the
|
|
* keys (and their order) were pre-determined before starting to
|
|
* invoke the callbacks.
|
|
*
|
|
* The idea is to give some sensible, stable behavior in case the user
|
|
* modifies the settings. Whether this particular behavior is optimal
|
|
* is unclear. It's probably a bad idea to modify the settings while
|
|
* iterating the values. But at least, it's a safe thing to do and we
|
|
* do something sensible. */
|
|
func(keys[i], nm_g_hash_table_lookup(*p_hash, keys[i]), user_data);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_foreach_data_item:
|
|
* @setting: a #NMSettingVpn
|
|
* @func: (scope call): an user provided function
|
|
* @user_data: data to be passed to @func
|
|
*
|
|
* Iterates all data items stored in this setting. It is safe to add, remove,
|
|
* and modify data items inside @func, though any additions or removals made
|
|
* during iteration will not be part of the iteration.
|
|
*/
|
|
void
|
|
nm_setting_vpn_foreach_data_item(NMSettingVpn *setting, NMVpnIterFunc func, gpointer user_data)
|
|
{
|
|
g_return_if_fail(NM_IS_SETTING_VPN(setting));
|
|
g_return_if_fail(func);
|
|
|
|
foreach_item_helper(setting, &NM_SETTING_VPN_GET_PRIVATE(setting)->data, func, user_data);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_get_num_secrets:
|
|
* @setting: the #NMSettingVpn
|
|
*
|
|
* Gets number of VPN plugin specific secrets in the setting.
|
|
*
|
|
* Returns: the number of VPN plugin specific secrets
|
|
**/
|
|
guint32
|
|
nm_setting_vpn_get_num_secrets(NMSettingVpn *setting)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), 0);
|
|
|
|
return nm_g_hash_table_size(NM_SETTING_VPN_GET_PRIVATE(setting)->secrets);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_add_secret:
|
|
* @setting: the #NMSettingVpn
|
|
* @key: a name that uniquely identifies the given secret @secret
|
|
* @secret: (allow-none): the secret to be referenced by @key
|
|
*
|
|
* Establishes a relationship between @key and @secret internally in the
|
|
* setting which may be retrieved later.
|
|
*
|
|
* Before 1.24, @secret must not be %NULL and not an empty string. Since 1.24,
|
|
* @secret can be set to an empty string. It can also be set to %NULL to unset
|
|
* the key. In that case, the behavior is as if calling nm_setting_vpn_remove_secret().
|
|
**/
|
|
void
|
|
nm_setting_vpn_add_secret(NMSettingVpn *setting, const char *key, const char *secret)
|
|
{
|
|
if (!secret) {
|
|
nm_setting_vpn_remove_secret(setting, key);
|
|
return;
|
|
}
|
|
|
|
g_return_if_fail(NM_IS_SETTING_VPN(setting));
|
|
g_return_if_fail(key && key[0]);
|
|
|
|
g_hash_table_insert(_ensure_strdict(&NM_SETTING_VPN_GET_PRIVATE(setting)->secrets, TRUE),
|
|
g_strdup(key),
|
|
g_strdup(secret));
|
|
_notify(setting, PROP_SECRETS);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_get_secret:
|
|
* @setting: the #NMSettingVpn
|
|
* @key: the name of the secret to retrieve
|
|
*
|
|
* Retrieves the secret of a key/value relationship previously established
|
|
* by nm_setting_vpn_add_secret().
|
|
*
|
|
* Returns: the secret, if any
|
|
**/
|
|
const char *
|
|
nm_setting_vpn_get_secret(NMSettingVpn *setting, const char *key)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
|
|
g_return_val_if_fail(key && key[0], NULL);
|
|
|
|
return nm_g_hash_table_lookup(NM_SETTING_VPN_GET_PRIVATE(setting)->secrets, key);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_get_secret_keys:
|
|
* @setting: the #NMSettingVpn
|
|
* @out_length: (allow-none) (out): the length of the returned array
|
|
*
|
|
* Retrieves every secret key inside @setting, as an array.
|
|
*
|
|
* Returns: (array length=out_length) (transfer container): a
|
|
* %NULL-terminated array containing each secret key or %NULL if
|
|
* there are no secrets.
|
|
*
|
|
* Since: 1.12
|
|
*/
|
|
const char **
|
|
nm_setting_vpn_get_secret_keys(NMSettingVpn *setting, guint *out_length)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
|
|
|
|
return nm_utils_strdict_get_keys(NM_SETTING_VPN_GET_PRIVATE(setting)->secrets,
|
|
TRUE,
|
|
out_length);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_remove_secret:
|
|
* @setting: the #NMSettingVpn
|
|
* @key: the name of the secret to remove
|
|
*
|
|
* Deletes a key/value relationship previously established by
|
|
* nm_setting_vpn_add_secret().
|
|
*
|
|
* Returns: %TRUE if the secret was found and removed from the internal list,
|
|
* %FALSE if it was not.
|
|
**/
|
|
gboolean
|
|
nm_setting_vpn_remove_secret(NMSettingVpn *setting, const char *key)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), FALSE);
|
|
g_return_val_if_fail(key && key[0], FALSE);
|
|
|
|
if (nm_g_hash_table_remove(NM_SETTING_VPN_GET_PRIVATE(setting)->secrets, key)) {
|
|
_notify(setting, PROP_SECRETS);
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_foreach_secret:
|
|
* @setting: a #NMSettingVpn
|
|
* @func: (scope call): an user provided function
|
|
* @user_data: data to be passed to @func
|
|
*
|
|
* Iterates all secrets stored in this setting. It is safe to add, remove,
|
|
* and modify secrets inside @func, though any additions or removals made during
|
|
* iteration will not be part of the iteration.
|
|
*/
|
|
void
|
|
nm_setting_vpn_foreach_secret(NMSettingVpn *setting, NMVpnIterFunc func, gpointer user_data)
|
|
{
|
|
g_return_if_fail(NM_IS_SETTING_VPN(setting));
|
|
g_return_if_fail(func);
|
|
|
|
foreach_item_helper(setting, &NM_SETTING_VPN_GET_PRIVATE(setting)->secrets, func, user_data);
|
|
}
|
|
|
|
static gboolean
|
|
aggregate(NMSetting *setting, int type_i, gpointer arg)
|
|
{
|
|
NMSettingVpnPrivate * priv = NM_SETTING_VPN_GET_PRIVATE(setting);
|
|
NMConnectionAggregateType type = type_i;
|
|
NMSettingSecretFlags secret_flags;
|
|
const char * key_name;
|
|
GHashTableIter iter;
|
|
|
|
switch (type) {
|
|
case NM_CONNECTION_AGGREGATE_ANY_SECRETS:
|
|
if (nm_g_hash_table_size(priv->secrets) > 0u) {
|
|
*((gboolean *) arg) = TRUE;
|
|
return TRUE;
|
|
}
|
|
return FALSE;
|
|
|
|
case NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS:
|
|
|
|
if (priv->secrets) {
|
|
g_hash_table_iter_init(&iter, priv->secrets);
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) &key_name, NULL)) {
|
|
if (!nm_setting_get_secret_flags(NM_SETTING(setting),
|
|
key_name,
|
|
&secret_flags,
|
|
NULL))
|
|
nm_assert_not_reached();
|
|
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) {
|
|
*((gboolean *) arg) = TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* OK, we have no secrets with system-secret flags.
|
|
* But do we have any secret-flags (without secrets) that indicate system secrets? */
|
|
if (priv->data) {
|
|
g_hash_table_iter_init(&iter, priv->data);
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) &key_name, NULL)) {
|
|
gs_free char *secret_name = NULL;
|
|
|
|
if (!NM_STR_HAS_SUFFIX(key_name, "-flags"))
|
|
continue;
|
|
secret_name = g_strndup(key_name, strlen(key_name) - NM_STRLEN("-flags"));
|
|
if (secret_name[0] == '\0')
|
|
continue;
|
|
if (!nm_setting_get_secret_flags(NM_SETTING(setting),
|
|
secret_name,
|
|
&secret_flags,
|
|
NULL))
|
|
nm_assert_not_reached();
|
|
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE) {
|
|
*((gboolean *) arg) = TRUE;
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
g_return_val_if_reached(FALSE);
|
|
}
|
|
|
|
/**
|
|
* nm_setting_vpn_get_timeout:
|
|
* @setting: the #NMSettingVpn
|
|
*
|
|
* Returns: the #NMSettingVpn:timeout property of the setting
|
|
*
|
|
* Since: 1.2
|
|
**/
|
|
guint32
|
|
nm_setting_vpn_get_timeout(NMSettingVpn *setting)
|
|
{
|
|
g_return_val_if_fail(NM_IS_SETTING_VPN(setting), 0);
|
|
|
|
return NM_SETTING_VPN_GET_PRIVATE(setting)->timeout;
|
|
}
|
|
|
|
static gboolean
|
|
verify(NMSetting *setting, NMConnection *connection, GError **error)
|
|
{
|
|
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE(setting);
|
|
NMSettingConnection *s_con;
|
|
|
|
if (!priv->service_type) {
|
|
g_set_error_literal(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_MISSING_PROPERTY,
|
|
_("property is missing"));
|
|
g_prefix_error(error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, NM_SETTING_VPN_SERVICE_TYPE);
|
|
return FALSE;
|
|
}
|
|
if (!priv->service_type[0]) {
|
|
g_set_error_literal(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
_("property is empty"));
|
|
g_prefix_error(error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, NM_SETTING_VPN_SERVICE_TYPE);
|
|
return FALSE;
|
|
}
|
|
|
|
/* default username can be NULL, but can't be zero-length */
|
|
if (priv->user_name && !priv->user_name[0]) {
|
|
g_set_error_literal(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
_("property is empty"));
|
|
g_prefix_error(error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, NM_SETTING_VPN_USER_NAME);
|
|
return FALSE;
|
|
}
|
|
|
|
if (connection && (s_con = nm_connection_get_setting_connection(connection))
|
|
&& nm_setting_connection_get_multi_connect(s_con) != NM_CONNECTION_MULTI_CONNECT_DEFAULT) {
|
|
g_set_error_literal(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
_("cannot set connection.multi-connect for VPN setting"));
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static NMSettingUpdateSecretResult
|
|
update_secret_string(NMSetting *setting, const char *key, const char *value, GError **error)
|
|
{
|
|
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE(setting);
|
|
|
|
g_return_val_if_fail(key && key[0], NM_SETTING_UPDATE_SECRET_ERROR);
|
|
g_return_val_if_fail(value, NM_SETTING_UPDATE_SECRET_ERROR);
|
|
|
|
if (nm_streq0(nm_g_hash_table_lookup(priv->secrets, key), value))
|
|
return NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
|
|
|
|
g_hash_table_insert(_ensure_strdict(&priv->secrets, TRUE), g_strdup(key), g_strdup(value));
|
|
return NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
|
|
}
|
|
|
|
static NMSettingUpdateSecretResult
|
|
update_secret_dict(NMSetting *setting, GVariant *secrets, GError **error)
|
|
{
|
|
NMSettingVpnPrivate * priv = NM_SETTING_VPN_GET_PRIVATE(setting);
|
|
GVariantIter iter;
|
|
const char * name, *value;
|
|
NMSettingUpdateSecretResult result = NM_SETTING_UPDATE_SECRET_SUCCESS_UNCHANGED;
|
|
|
|
g_return_val_if_fail(secrets != NULL, NM_SETTING_UPDATE_SECRET_ERROR);
|
|
|
|
/* Make sure the items are valid */
|
|
g_variant_iter_init(&iter, secrets);
|
|
while (g_variant_iter_next(&iter, "{&s&s}", &name, &value)) {
|
|
if (!name[0]) {
|
|
g_set_error_literal(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_SETTING,
|
|
_("setting contained a secret with an empty name"));
|
|
g_prefix_error(error, "%s: ", NM_SETTING_VPN_SETTING_NAME);
|
|
return NM_SETTING_UPDATE_SECRET_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Now add the items to the settings' secrets list */
|
|
g_variant_iter_init(&iter, secrets);
|
|
while (g_variant_iter_next(&iter, "{&s&s}", &name, &value)) {
|
|
if (nm_streq0(nm_g_hash_table_lookup(priv->secrets, name), value))
|
|
continue;
|
|
|
|
g_hash_table_insert(_ensure_strdict(&priv->secrets, TRUE), g_strdup(name), g_strdup(value));
|
|
result = NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
static int
|
|
update_one_secret(NMSetting *setting, const char *key, GVariant *value, GError **error)
|
|
{
|
|
NMSettingUpdateSecretResult success = NM_SETTING_UPDATE_SECRET_ERROR;
|
|
|
|
g_return_val_if_fail(key != NULL, NM_SETTING_UPDATE_SECRET_ERROR);
|
|
g_return_val_if_fail(value != NULL, NM_SETTING_UPDATE_SECRET_ERROR);
|
|
|
|
if (g_variant_is_of_type(value, G_VARIANT_TYPE_STRING)) {
|
|
/* Passing the string properties individually isn't correct, and won't
|
|
* produce the correct result, but for some reason that's how it used
|
|
* to be done. So even though it's not correct, keep the code around
|
|
* for compatibility's sake.
|
|
*/
|
|
success = update_secret_string(setting, key, g_variant_get_string(value, NULL), error);
|
|
} else if (g_variant_is_of_type(value, G_VARIANT_TYPE("a{ss}"))) {
|
|
if (!nm_streq(key, NM_SETTING_VPN_SECRETS)) {
|
|
g_set_error_literal(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
|
|
_("not a secret property"));
|
|
g_prefix_error(error, "%s.%s ", NM_SETTING_VPN_SETTING_NAME, key);
|
|
} else
|
|
success = update_secret_dict(setting, value, error);
|
|
} else {
|
|
g_set_error_literal(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
_("secret is not of correct type"));
|
|
g_prefix_error(error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, key);
|
|
}
|
|
|
|
if (success == NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED)
|
|
_notify(NM_SETTING_VPN(setting), PROP_SECRETS);
|
|
|
|
return success;
|
|
}
|
|
|
|
static void
|
|
for_each_secret(NMSetting * setting,
|
|
const char * secret_name,
|
|
GVariant * val,
|
|
gboolean remove_non_secrets,
|
|
_NMConnectionForEachSecretFunc callback,
|
|
gpointer callback_data,
|
|
GVariantBuilder * setting_builder)
|
|
{
|
|
GVariantBuilder vpn_secrets_builder;
|
|
GVariantIter vpn_secrets_iter;
|
|
const char * vpn_secret_name;
|
|
const char * secret;
|
|
|
|
if (!nm_streq(secret_name, NM_SETTING_VPN_SECRETS)) {
|
|
NM_SETTING_CLASS(nm_setting_vpn_parent_class)
|
|
->for_each_secret(setting,
|
|
secret_name,
|
|
val,
|
|
remove_non_secrets,
|
|
callback,
|
|
callback_data,
|
|
setting_builder);
|
|
return;
|
|
}
|
|
|
|
if (!g_variant_is_of_type(val, G_VARIANT_TYPE("a{ss}"))) {
|
|
/* invalid type. Silently ignore the secrets as we cannot find out the
|
|
* secret-flags. */
|
|
return;
|
|
}
|
|
|
|
/* Iterate through each secret from the VPN dict in the overall secrets dict */
|
|
g_variant_builder_init(&vpn_secrets_builder, G_VARIANT_TYPE("a{ss}"));
|
|
g_variant_iter_init(&vpn_secrets_iter, val);
|
|
while (g_variant_iter_next(&vpn_secrets_iter, "{&s&s}", &vpn_secret_name, &secret)) {
|
|
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
/* we ignore the return value of get_secret_flags. The function may determine
|
|
* that this is not a secret, based on having not secret-flags and no secrets.
|
|
* But we have the secret at hand. We know it would be a valid secret, if we
|
|
* only add it to the VPN settings. */
|
|
nm_setting_get_secret_flags(setting, vpn_secret_name, &secret_flags, NULL);
|
|
|
|
if (callback(secret_flags, callback_data))
|
|
g_variant_builder_add(&vpn_secrets_builder, "{ss}", vpn_secret_name, secret);
|
|
}
|
|
|
|
g_variant_builder_add(setting_builder,
|
|
"{sv}",
|
|
secret_name,
|
|
g_variant_builder_end(&vpn_secrets_builder));
|
|
}
|
|
|
|
static gboolean
|
|
get_secret_flags(NMSetting * setting,
|
|
const char * secret_name,
|
|
NMSettingSecretFlags *out_flags,
|
|
GError ** error)
|
|
{
|
|
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE(setting);
|
|
gs_free char * flags_key_free = NULL;
|
|
const char * flags_key;
|
|
const char * flags_val;
|
|
gint64 i64;
|
|
|
|
nm_assert(secret_name);
|
|
|
|
if (!secret_name[0]) {
|
|
g_set_error(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
|
|
_("secret name cannot be empty"));
|
|
return FALSE;
|
|
}
|
|
|
|
flags_key = nm_construct_name_a("%s-flags", secret_name, &flags_key_free);
|
|
|
|
if (!priv->data
|
|
|| !g_hash_table_lookup_extended(priv->data, flags_key, NULL, (gpointer *) &flags_val)) {
|
|
NM_SET_OUT(out_flags, NM_SETTING_SECRET_FLAG_NONE);
|
|
|
|
/* having no secret flag for the secret is fine, as long as there
|
|
* is the secret itself... */
|
|
if (!nm_g_hash_table_lookup(priv->secrets, secret_name)) {
|
|
g_set_error_literal(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
|
|
_("secret flags property not found"));
|
|
g_prefix_error(error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, flags_key);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
i64 = _nm_utils_ascii_str_to_int64(flags_val, 10, 0, NM_SETTING_SECRET_FLAG_ALL, -1);
|
|
if (i64 == -1 || !_nm_setting_secret_flags_valid(i64)) {
|
|
/* The flags keys is set to an unexpected value. That is a configuration
|
|
* error. Note that keys named "*-flags" are reserved for secrets. The user
|
|
* must not use this for anything but secret flags. Hence, we cannot fail
|
|
* to read the secret, we pretend that the secret flag is set to the default
|
|
* NM_SETTING_SECRET_FLAG_NONE. */
|
|
NM_SET_OUT(out_flags, NM_SETTING_SECRET_FLAG_NONE);
|
|
return TRUE;
|
|
}
|
|
|
|
NM_SET_OUT(out_flags, (NMSettingSecretFlags) i64);
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
set_secret_flags(NMSetting * setting,
|
|
const char * secret_name,
|
|
NMSettingSecretFlags flags,
|
|
GError ** error)
|
|
{
|
|
nm_assert(secret_name);
|
|
|
|
if (!secret_name[0]) {
|
|
g_set_error(error,
|
|
NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_PROPERTY_NOT_SECRET,
|
|
_("secret name cannot be empty"));
|
|
return FALSE;
|
|
}
|
|
|
|
g_hash_table_insert(_ensure_strdict(&NM_SETTING_VPN_GET_PRIVATE(setting)->data, FALSE),
|
|
g_strdup_printf("%s-flags", secret_name),
|
|
g_strdup_printf("%u", flags));
|
|
_notify(NM_SETTING_VPN(setting), PROP_SECRETS);
|
|
return TRUE;
|
|
}
|
|
|
|
static GPtrArray *
|
|
need_secrets(NMSetting *setting)
|
|
{
|
|
/* Assume that VPN connections need secrets since they almost always will */
|
|
return g_ptr_array_sized_new(1);
|
|
}
|
|
|
|
static NMTernary
|
|
compare_property_secrets(NMSettingVpn *a, NMSettingVpn *b, NMSettingCompareFlags flags)
|
|
{
|
|
GHashTableIter iter;
|
|
const char * key, *val;
|
|
int run;
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_FUZZY))
|
|
return NM_TERNARY_DEFAULT;
|
|
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS))
|
|
return NM_TERNARY_DEFAULT;
|
|
|
|
if (!b)
|
|
return TRUE;
|
|
|
|
for (run = 0; run < 2; run++) {
|
|
NMSettingVpn * current_a = (run == 0) ? a : b;
|
|
NMSettingVpn * current_b = (run == 0) ? b : a;
|
|
NMSettingVpnPrivate *priv_a = NM_SETTING_VPN_GET_PRIVATE(current_a);
|
|
|
|
if (!priv_a->secrets)
|
|
continue;
|
|
|
|
g_hash_table_iter_init(&iter, priv_a->secrets);
|
|
while (g_hash_table_iter_next(&iter, (gpointer) &key, (gpointer) &val)) {
|
|
if (nm_streq0(val, nm_setting_vpn_get_secret(current_b, key)))
|
|
continue;
|
|
if (!_nm_setting_should_compare_secret_property(NM_SETTING(current_a),
|
|
NM_SETTING(current_b),
|
|
key,
|
|
flags))
|
|
continue;
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static NMTernary
|
|
compare_property(const NMSettInfoSetting *sett_info,
|
|
guint property_idx,
|
|
NMConnection * con_a,
|
|
NMSetting * set_a,
|
|
NMConnection * con_b,
|
|
NMSetting * set_b,
|
|
NMSettingCompareFlags flags)
|
|
{
|
|
if (nm_streq(sett_info->property_infos[property_idx].name, NM_SETTING_VPN_SECRETS)) {
|
|
if (NM_FLAGS_HAS(flags, NM_SETTING_COMPARE_FLAG_INFERRABLE))
|
|
return NM_TERNARY_DEFAULT;
|
|
return compare_property_secrets(NM_SETTING_VPN(set_a), NM_SETTING_VPN(set_b), flags);
|
|
}
|
|
|
|
return NM_SETTING_CLASS(nm_setting_vpn_parent_class)
|
|
->compare_property(sett_info, property_idx, con_a, set_a, con_b, set_b, flags);
|
|
}
|
|
|
|
static gboolean
|
|
clear_secrets(const NMSettInfoSetting * sett_info,
|
|
guint property_idx,
|
|
NMSetting * setting,
|
|
NMSettingClearSecretsWithFlagsFn func,
|
|
gpointer user_data)
|
|
{
|
|
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE(setting);
|
|
GParamSpec * prop_spec = sett_info->property_infos[property_idx].param_spec;
|
|
GHashTableIter iter;
|
|
const char * secret;
|
|
gboolean changed = TRUE;
|
|
|
|
if (!prop_spec || !NM_FLAGS_HAS(prop_spec->flags, NM_SETTING_PARAM_SECRET))
|
|
return FALSE;
|
|
|
|
nm_assert(nm_streq(prop_spec->name, NM_SETTING_VPN_SECRETS));
|
|
|
|
if (!priv->secrets)
|
|
return FALSE;
|
|
|
|
g_hash_table_iter_init(&iter, priv->secrets);
|
|
while (g_hash_table_iter_next(&iter, (gpointer) &secret, NULL)) {
|
|
if (func) {
|
|
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
if (!nm_setting_get_secret_flags(setting, secret, &flags, NULL))
|
|
nm_assert_not_reached();
|
|
|
|
if (!func(setting, secret, flags, user_data))
|
|
continue;
|
|
} else
|
|
nm_assert(nm_setting_get_secret_flags(setting, secret, NULL, NULL));
|
|
|
|
g_hash_table_iter_remove(&iter);
|
|
changed = TRUE;
|
|
}
|
|
|
|
if (changed)
|
|
_notify(NM_SETTING_VPN(setting), PROP_SECRETS);
|
|
|
|
return changed;
|
|
}
|
|
|
|
static gboolean
|
|
vpn_secrets_from_dbus(NMSetting * setting,
|
|
GVariant * connection_dict,
|
|
const char * property,
|
|
GVariant * value,
|
|
NMSettingParseFlags parse_flags,
|
|
GError ** error)
|
|
{
|
|
NMSettingVpn * self = NM_SETTING_VPN(setting);
|
|
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE(self);
|
|
gs_unref_hashtable GHashTable *hash_free = NULL;
|
|
GVariantIter iter;
|
|
const char * key;
|
|
const char * val;
|
|
|
|
hash_free = g_steal_pointer(&priv->secrets);
|
|
|
|
g_variant_iter_init(&iter, value);
|
|
while (g_variant_iter_next(&iter, "{&s&s}", &key, &val)) {
|
|
if (!key[0])
|
|
continue;
|
|
g_hash_table_insert(_ensure_strdict(&priv->secrets, TRUE), g_strdup(key), g_strdup(val));
|
|
}
|
|
|
|
_notify(self, PROP_SECRETS);
|
|
return TRUE;
|
|
}
|
|
|
|
static GVariant *
|
|
vpn_secrets_to_dbus(const NMSettInfoSetting * sett_info,
|
|
guint property_idx,
|
|
NMConnection * connection,
|
|
NMSetting * setting,
|
|
NMConnectionSerializationFlags flags,
|
|
const NMConnectionSerializationOptions *options)
|
|
{
|
|
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE(setting);
|
|
GVariantBuilder builder;
|
|
gs_free const char **keys = NULL;
|
|
guint i, len;
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_CONNECTION_SERIALIZE_NO_SECRETS))
|
|
return NULL;
|
|
|
|
g_variant_builder_init(&builder, G_VARIANT_TYPE("a{ss}"));
|
|
|
|
keys = nm_utils_strdict_get_keys(priv->secrets, TRUE, &len);
|
|
for (i = 0; i < len; i++) {
|
|
const char * key = keys[i];
|
|
NMSettingSecretFlags secret_flags;
|
|
|
|
if (NM_FLAGS_HAS(flags, NM_CONNECTION_SERIALIZE_WITH_SECRETS_AGENT_OWNED)) {
|
|
if (!nm_setting_get_secret_flags(setting, key, &secret_flags, NULL)
|
|
|| !NM_FLAGS_HAS(secret_flags, NM_SETTING_SECRET_FLAG_AGENT_OWNED))
|
|
continue;
|
|
}
|
|
g_variant_builder_add(&builder, "{ss}", key, g_hash_table_lookup(priv->secrets, key));
|
|
}
|
|
|
|
return g_variant_builder_end(&builder);
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|
{
|
|
NMSettingVpn * setting = NM_SETTING_VPN(object);
|
|
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE(setting);
|
|
|
|
switch (prop_id) {
|
|
case PROP_SERVICE_TYPE:
|
|
g_value_set_string(value, nm_setting_vpn_get_service_type(setting));
|
|
break;
|
|
case PROP_USER_NAME:
|
|
g_value_set_string(value, nm_setting_vpn_get_user_name(setting));
|
|
break;
|
|
case PROP_PERSISTENT:
|
|
g_value_set_boolean(value, priv->persistent);
|
|
break;
|
|
case PROP_DATA:
|
|
g_value_take_boxed(value, _nm_utils_copy_strdict(priv->data));
|
|
break;
|
|
case PROP_SECRETS:
|
|
g_value_take_boxed(value, _nm_utils_copy_strdict(priv->secrets));
|
|
break;
|
|
case PROP_TIMEOUT:
|
|
g_value_set_uint(value, nm_setting_vpn_get_timeout(setting));
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
|
{
|
|
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE(object);
|
|
|
|
switch (prop_id) {
|
|
case PROP_SERVICE_TYPE:
|
|
g_free(priv->service_type);
|
|
priv->service_type = g_value_dup_string(value);
|
|
break;
|
|
case PROP_USER_NAME:
|
|
g_free(priv->user_name);
|
|
priv->user_name = g_value_dup_string(value);
|
|
break;
|
|
case PROP_PERSISTENT:
|
|
priv->persistent = g_value_get_boolean(value);
|
|
break;
|
|
case PROP_DATA:
|
|
case PROP_SECRETS:
|
|
{
|
|
gs_unref_hashtable GHashTable *hash_free = NULL;
|
|
GHashTable * src_hash = g_value_get_boxed(value);
|
|
GHashTable ** p_hash;
|
|
const gboolean is_secrets = (prop_id == PROP_SECRETS);
|
|
|
|
if (is_secrets)
|
|
p_hash = &priv->secrets;
|
|
else
|
|
p_hash = &priv->data;
|
|
|
|
hash_free = g_steal_pointer(p_hash);
|
|
|
|
if (src_hash && g_hash_table_size(src_hash) > 0) {
|
|
GHashTableIter iter;
|
|
const char * key;
|
|
const char * val;
|
|
|
|
g_hash_table_iter_init(&iter, src_hash);
|
|
while (g_hash_table_iter_next(&iter, (gpointer *) &key, (gpointer *) &val)) {
|
|
if (!key || !key[0] || !val) {
|
|
/* NULL keys/values and empty key are not allowed. Usually, we would reject them in verify(), but
|
|
* then our nm_setting_vpn_remove_data_item() also doesn't allow empty keys. So, if we failed
|
|
* it in verify(), it would be only fixable by setting PROP_DATA again. Instead,
|
|
* silently ignore them. */
|
|
continue;
|
|
}
|
|
g_hash_table_insert(_ensure_strdict(p_hash, is_secrets),
|
|
g_strdup(key),
|
|
g_strdup(val));
|
|
}
|
|
}
|
|
} break;
|
|
case PROP_TIMEOUT:
|
|
priv->timeout = g_value_get_uint(value);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*****************************************************************************/
|
|
|
|
static void
|
|
nm_setting_vpn_init(NMSettingVpn *setting)
|
|
{}
|
|
|
|
/**
|
|
* nm_setting_vpn_new:
|
|
*
|
|
* Creates a new #NMSettingVpn object with default values.
|
|
*
|
|
* Returns: (transfer full): the new empty #NMSettingVpn object
|
|
**/
|
|
NMSetting *
|
|
nm_setting_vpn_new(void)
|
|
{
|
|
return (NMSetting *) g_object_new(NM_TYPE_SETTING_VPN, NULL);
|
|
}
|
|
|
|
static void
|
|
finalize(GObject *object)
|
|
{
|
|
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE(object);
|
|
|
|
g_free(priv->service_type);
|
|
g_free(priv->user_name);
|
|
if (priv->data)
|
|
g_hash_table_unref(priv->data);
|
|
if (priv->secrets)
|
|
g_hash_table_unref(priv->secrets);
|
|
|
|
G_OBJECT_CLASS(nm_setting_vpn_parent_class)->finalize(object);
|
|
}
|
|
|
|
static void
|
|
nm_setting_vpn_class_init(NMSettingVpnClass *klass)
|
|
{
|
|
GObjectClass * object_class = G_OBJECT_CLASS(klass);
|
|
NMSettingClass *setting_class = NM_SETTING_CLASS(klass);
|
|
GArray * properties_override = _nm_sett_info_property_override_create_array();
|
|
|
|
g_type_class_add_private(klass, sizeof(NMSettingVpnPrivate));
|
|
|
|
object_class->get_property = get_property;
|
|
object_class->set_property = set_property;
|
|
object_class->finalize = finalize;
|
|
|
|
setting_class->verify = verify;
|
|
setting_class->update_one_secret = update_one_secret;
|
|
setting_class->for_each_secret = for_each_secret;
|
|
setting_class->get_secret_flags = get_secret_flags;
|
|
setting_class->set_secret_flags = set_secret_flags;
|
|
setting_class->need_secrets = need_secrets;
|
|
setting_class->compare_property = compare_property;
|
|
setting_class->clear_secrets = clear_secrets;
|
|
setting_class->aggregate = aggregate;
|
|
|
|
/**
|
|
* NMSettingVpn:service-type:
|
|
*
|
|
* D-Bus service name of the VPN plugin that this setting uses to connect to
|
|
* its network. i.e. org.freedesktop.NetworkManager.vpnc for the vpnc
|
|
* plugin.
|
|
**/
|
|
obj_properties[PROP_SERVICE_TYPE] =
|
|
g_param_spec_string(NM_SETTING_VPN_SERVICE_TYPE,
|
|
"",
|
|
"",
|
|
NULL,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
* NMSettingVpn:user-name:
|
|
*
|
|
* If the VPN connection requires a user name for authentication, that name
|
|
* should be provided here. If the connection is available to more than one
|
|
* user, and the VPN requires each user to supply a different name, then
|
|
* leave this property empty. If this property is empty, NetworkManager
|
|
* will automatically supply the username of the user which requested the
|
|
* VPN connection.
|
|
**/
|
|
obj_properties[PROP_USER_NAME] =
|
|
g_param_spec_string(NM_SETTING_VPN_USER_NAME,
|
|
"",
|
|
"",
|
|
NULL,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
* NMSettingVpn:persistent:
|
|
*
|
|
* If the VPN service supports persistence, and this property is %TRUE,
|
|
* the VPN will attempt to stay connected across link changes and outages,
|
|
* until explicitly disconnected.
|
|
**/
|
|
obj_properties[PROP_PERSISTENT] =
|
|
g_param_spec_boolean(NM_SETTING_VPN_PERSISTENT,
|
|
"",
|
|
"",
|
|
FALSE,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
|
|
|
/**
|
|
* NMSettingVpn:data: (type GHashTable(utf8,utf8)):
|
|
*
|
|
* Dictionary of key/value pairs of VPN plugin specific data. Both keys and
|
|
* values must be strings.
|
|
**/
|
|
/* ---keyfile---
|
|
* property: data
|
|
* variable: separate variables named after keys of the dictionary
|
|
* description: The keys of the data dictionary are used as variable names directly
|
|
* under [vpn] section.
|
|
* example: remote=ovpn.corp.com cipher=AES-256-CBC username=joe
|
|
* ---end---
|
|
*/
|
|
obj_properties[PROP_DATA] = g_param_spec_boxed(NM_SETTING_VPN_DATA,
|
|
"",
|
|
"",
|
|
G_TYPE_HASH_TABLE,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
|
_nm_properties_override_gobj(properties_override,
|
|
obj_properties[PROP_DATA],
|
|
&nm_sett_info_propert_type_strdict);
|
|
|
|
/**
|
|
* NMSettingVpn:secrets: (type GHashTable(utf8,utf8)):
|
|
*
|
|
* Dictionary of key/value pairs of VPN plugin specific secrets like
|
|
* passwords or private keys. Both keys and values must be strings.
|
|
**/
|
|
/* ---keyfile---
|
|
* property: secrets
|
|
* variable: separate variables named after keys of the dictionary
|
|
* description: The keys of the secrets dictionary are used as variable names directly
|
|
* under [vpn-secrets] section.
|
|
* example: password=Popocatepetl
|
|
* ---end---
|
|
*/
|
|
obj_properties[PROP_SECRETS] =
|
|
g_param_spec_boxed(NM_SETTING_VPN_SECRETS,
|
|
"",
|
|
"",
|
|
G_TYPE_HASH_TABLE,
|
|
G_PARAM_READWRITE | NM_SETTING_PARAM_SECRET
|
|
| NM_SETTING_PARAM_TO_DBUS_IGNORE_FLAGS | G_PARAM_STATIC_STRINGS);
|
|
_nm_properties_override_gobj(
|
|
properties_override,
|
|
obj_properties[PROP_SECRETS],
|
|
NM_SETT_INFO_PROPERT_TYPE(.dbus_type = NM_G_VARIANT_TYPE("a{ss}"),
|
|
.to_dbus_fcn = vpn_secrets_to_dbus,
|
|
.from_dbus_fcn = vpn_secrets_from_dbus, ));
|
|
|
|
/**
|
|
* NMSettingVpn:timeout:
|
|
*
|
|
* Timeout for the VPN service to establish the connection. Some services
|
|
* may take quite a long time to connect.
|
|
* Value of 0 means a default timeout, which is 60 seconds (unless overridden
|
|
* by vpn.timeout in configuration file). Values greater than zero mean
|
|
* timeout in seconds.
|
|
*
|
|
* Since: 1.2
|
|
**/
|
|
obj_properties[PROP_TIMEOUT] = g_param_spec_uint(NM_SETTING_VPN_TIMEOUT,
|
|
"",
|
|
"",
|
|
0,
|
|
G_MAXUINT32,
|
|
0,
|
|
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
|
|
|
g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
|
|
|
_nm_setting_class_commit_full(setting_class,
|
|
NM_META_SETTING_TYPE_VPN,
|
|
NULL,
|
|
properties_override);
|
|
}
|