mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-30 16:40:13 +01:00
Also drop the g_warn_if_fail() from update_secret_dict(). We may get the variant from D-Bus, so avoiding this assertion (g_warn*() is an assertion!) would require us to prevalidate the variant. That would be very cumbersome, and we would probably not want to handle that as an error and silently ignore them anyway. Just shut up.
1244 lines
40 KiB
C
1244 lines
40 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: 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.
|
|
**/
|
|
void
|
|
nm_setting_vpn_add_data_item (NMSettingVpn *setting,
|
|
const char *key,
|
|
const char *item)
|
|
{
|
|
g_return_if_fail (NM_IS_SETTING_VPN (setting));
|
|
g_return_if_fail (key && key[0]);
|
|
g_return_if_fail (item && item[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: the secret to be referenced by @key
|
|
*
|
|
* Establishes a relationship between @key and @secret internally in the
|
|
* setting which may be retrieved later.
|
|
**/
|
|
void
|
|
nm_setting_vpn_add_secret (NMSettingVpn *setting,
|
|
const char *key,
|
|
const char *secret)
|
|
{
|
|
g_return_if_fail (NM_IS_SETTING_VPN (setting));
|
|
g_return_if_fail (key && key[0]);
|
|
g_return_if_fail (secret && secret[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 (!value[0]) {
|
|
g_set_error (error, NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
_("secret was empty"));
|
|
g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, key);
|
|
return 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;
|
|
}
|
|
|
|
if (!value[0]) {
|
|
g_set_error (error, NM_CONNECTION_ERROR,
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
_("secret value was empty"));
|
|
g_prefix_error (error, "%s.%s: ", NM_SETTING_VPN_SETTING_NAME, 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)
|
|
{
|
|
nm_auto_unset_gvalue GValue object_value = G_VALUE_INIT;
|
|
|
|
g_value_init (&object_value, G_TYPE_HASH_TABLE);
|
|
_nm_utils_strdict_from_dbus (value, &object_value);
|
|
return nm_g_object_set_property (G_OBJECT (setting), property, &object_value, error);
|
|
}
|
|
|
|
static GVariant *
|
|
vpn_secrets_to_dbus (const NMSettInfoSetting *sett_info,
|
|
guint property_idx,
|
|
NMConnection *connection,
|
|
NMSetting *setting,
|
|
NMConnectionSerializationFlags flags,
|
|
const NMConnectionSerializationOptions *options)
|
|
{
|
|
gs_unref_hashtable GHashTable *secrets = NULL;
|
|
const char *property_name = sett_info->property_infos[property_idx].name;
|
|
GVariantBuilder builder;
|
|
GHashTableIter iter;
|
|
const char *key, *value;
|
|
NMSettingSecretFlags secret_flags;
|
|
|
|
if (NM_FLAGS_HAS (flags, NM_CONNECTION_SERIALIZE_NO_SECRETS))
|
|
return NULL;
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
|
|
g_object_get (setting, property_name, &secrets, NULL);
|
|
|
|
if (secrets) {
|
|
g_hash_table_iter_init (&iter, secrets);
|
|
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) {
|
|
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, value);
|
|
}
|
|
}
|
|
|
|
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: {
|
|
_nm_unused gs_unref_hashtable GHashTable *data_free = g_steal_pointer (&priv->data);
|
|
GHashTable *hash = g_value_get_boxed (value);
|
|
|
|
if ( hash
|
|
&& g_hash_table_size (hash) > 0) {
|
|
priv->data = _nm_utils_copy_strdict (hash);
|
|
|
|
/* empty keys 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 drop it. */
|
|
g_hash_table_remove (priv->data, "");
|
|
}
|
|
}
|
|
break;
|
|
case PROP_SECRETS: {
|
|
_nm_unused gs_unref_hashtable GHashTable *secrets_free = g_steal_pointer (&priv->secrets);
|
|
GHashTable *hash = g_value_get_boxed (value);
|
|
|
|
if ( hash
|
|
&& g_hash_table_size (hash) > 0) {
|
|
priv->secrets = _nm_utils_copy_strdict (hash);
|
|
|
|
/* empty keys are not allowed. Usually, we would reject them in verify(), but then
|
|
* our nm_setting_vpn_remove_secret() 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 drop it. */
|
|
g_hash_table_remove (priv->secrets, "");
|
|
}
|
|
}
|
|
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);
|
|
}
|