mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-09-20 00:21:29 +00:00
839 lines
25 KiB
C
839 lines
25 KiB
C
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
/*
|
|
* Dan Williams <dcbw@redhat.com>
|
|
* Tambet Ingo <tambet@gmail.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
* Boston, MA 02110-1301 USA.
|
|
*
|
|
* (C) Copyright 2007 - 2012 Red Hat, Inc.
|
|
* (C) Copyright 2007 - 2008 Novell, Inc.
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <stdlib.h>
|
|
#include <dbus/dbus-glib.h>
|
|
#include "nm-setting-vpn.h"
|
|
#include "nm-param-spec-specialized.h"
|
|
#include "nm-utils.h"
|
|
#include "nm-dbus-glib-types.h"
|
|
#include "nm-setting-private.h"
|
|
|
|
/**
|
|
* SECTION:nm-setting-vpn
|
|
* @short_description: Describes connection properties for Virtual Private Networks
|
|
* @include: nm-setting-vpn.h
|
|
*
|
|
* 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_setting_vpn_error_quark:
|
|
*
|
|
* Registers an error quark for #NMSettingVPN if necessary.
|
|
*
|
|
* Returns: the error quark used for #NMSettingVPN errors.
|
|
**/
|
|
GQuark
|
|
nm_setting_vpn_error_quark (void)
|
|
{
|
|
static GQuark quark;
|
|
|
|
if (G_UNLIKELY (!quark))
|
|
quark = g_quark_from_static_string ("nm-setting-vpn-error-quark");
|
|
return quark;
|
|
}
|
|
|
|
/* This should really be standard. */
|
|
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
|
|
|
|
GType
|
|
nm_setting_vpn_error_get_type (void)
|
|
{
|
|
static GType etype = 0;
|
|
|
|
if (etype == 0) {
|
|
static const GEnumValue values[] = {
|
|
/* Unknown error. */
|
|
ENUM_ENTRY (NM_SETTING_VPN_ERROR_UNKNOWN, "UnknownError"),
|
|
/* The specified property was invalid. */
|
|
ENUM_ENTRY (NM_SETTING_VPN_ERROR_INVALID_PROPERTY, "InvalidProperty"),
|
|
/* The specified property was missing and is required. */
|
|
ENUM_ENTRY (NM_SETTING_VPN_ERROR_MISSING_PROPERTY, "MissingProperty"),
|
|
{ 0, 0, 0 }
|
|
};
|
|
etype = g_enum_register_static ("NMSettingVpnError", values);
|
|
}
|
|
return etype;
|
|
}
|
|
|
|
|
|
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))
|
|
|
|
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;
|
|
|
|
/* 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;
|
|
} NMSettingVPNPrivate;
|
|
|
|
enum {
|
|
PROP_0,
|
|
PROP_SERVICE_TYPE,
|
|
PROP_USER_NAME,
|
|
PROP_DATA,
|
|
PROP_SECRETS,
|
|
|
|
LAST_PROP
|
|
};
|
|
|
|
/**
|
|
* 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);
|
|
}
|
|
|
|
/**
|
|
* 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_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 != NULL);
|
|
g_return_if_fail (strlen (key) > 0);
|
|
g_return_if_fail (item != NULL);
|
|
g_return_if_fail (strlen (item) > 0);
|
|
|
|
g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->data,
|
|
g_strdup (key), g_strdup (item));
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
|
|
return (const char *) g_hash_table_lookup (NM_SETTING_VPN_GET_PRIVATE (setting)->data, key);
|
|
}
|
|
|
|
/**
|
|
* 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().
|
|
**/
|
|
void
|
|
nm_setting_vpn_remove_data_item (NMSettingVPN *setting, const char *key)
|
|
{
|
|
g_return_if_fail (NM_IS_SETTING_VPN (setting));
|
|
|
|
g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->data, key);
|
|
}
|
|
|
|
static void
|
|
foreach_item_helper (GHashTable *hash,
|
|
NMVPNIterFunc func,
|
|
gpointer user_data)
|
|
{
|
|
GList *keys, *liter;
|
|
GSList *copied = NULL, *siter;
|
|
|
|
g_return_if_fail (hash != NULL);
|
|
|
|
/* Grab keys and copy them so that the callback func can modify
|
|
* the hash table items if it wants to.
|
|
*/
|
|
keys = g_hash_table_get_keys (hash);
|
|
for (liter = keys; liter; liter = g_list_next (liter))
|
|
copied = g_slist_prepend (copied, g_strdup (liter->data));
|
|
copied = g_slist_reverse (copied);
|
|
g_list_free (keys);
|
|
|
|
for (siter = copied; siter; siter = g_slist_next (siter)) {
|
|
gpointer value;
|
|
|
|
value = g_hash_table_lookup (hash, siter->data);
|
|
func (siter->data, value, user_data);
|
|
}
|
|
|
|
g_slist_foreach (copied, (GFunc) g_free, NULL);
|
|
g_slist_free (copied);
|
|
}
|
|
|
|
/**
|
|
* 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 (setting != NULL);
|
|
g_return_if_fail (NM_IS_SETTING_VPN (setting));
|
|
|
|
foreach_item_helper (NM_SETTING_VPN_GET_PRIVATE (setting)->data, func, user_data);
|
|
}
|
|
|
|
/**
|
|
* 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 != NULL);
|
|
g_return_if_fail (strlen (key) > 0);
|
|
g_return_if_fail (secret != NULL);
|
|
g_return_if_fail (strlen (secret) > 0);
|
|
|
|
g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets,
|
|
g_strdup (key), g_strdup (secret));
|
|
}
|
|
|
|
/**
|
|
* 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);
|
|
|
|
return (const char *) g_hash_table_lookup (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, key);
|
|
}
|
|
|
|
/**
|
|
* 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().
|
|
**/
|
|
void
|
|
nm_setting_vpn_remove_secret (NMSettingVPN *setting, const char *key)
|
|
{
|
|
g_return_if_fail (NM_IS_SETTING_VPN (setting));
|
|
|
|
g_hash_table_remove (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, key);
|
|
}
|
|
|
|
/**
|
|
* 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 (setting != NULL);
|
|
g_return_if_fail (NM_IS_SETTING_VPN (setting));
|
|
|
|
foreach_item_helper (NM_SETTING_VPN_GET_PRIVATE (setting)->secrets, func, user_data);
|
|
}
|
|
|
|
static gboolean
|
|
verify (NMSetting *setting, GSList *all_settings, GError **error)
|
|
{
|
|
NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
|
|
|
|
if (!priv->service_type) {
|
|
g_set_error (error,
|
|
NM_SETTING_VPN_ERROR,
|
|
NM_SETTING_VPN_ERROR_MISSING_PROPERTY,
|
|
NM_SETTING_VPN_SERVICE_TYPE);
|
|
return FALSE;
|
|
}
|
|
|
|
if (!strlen (priv->service_type)) {
|
|
g_set_error (error,
|
|
NM_SETTING_VPN_ERROR,
|
|
NM_SETTING_VPN_ERROR_INVALID_PROPERTY,
|
|
NM_SETTING_VPN_SERVICE_TYPE);
|
|
return FALSE;
|
|
}
|
|
|
|
/* default username can be NULL, but can't be zero-length */
|
|
if (priv->user_name && !strlen (priv->user_name)) {
|
|
g_set_error (error,
|
|
NM_SETTING_VPN_ERROR,
|
|
NM_SETTING_VPN_ERROR_INVALID_PROPERTY,
|
|
NM_SETTING_VPN_USER_NAME);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
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 != NULL, FALSE);
|
|
g_return_val_if_fail (value != NULL, FALSE);
|
|
|
|
if (!value || !strlen (value)) {
|
|
g_set_error (error, NM_SETTING_ERROR,
|
|
NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH,
|
|
"Secret %s was empty", key);
|
|
return FALSE;
|
|
}
|
|
|
|
g_hash_table_insert (priv->secrets, g_strdup (key), g_strdup (value));
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
update_secret_hash (NMSetting *setting,
|
|
GHashTable *secrets,
|
|
GError **error)
|
|
{
|
|
NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
|
|
GHashTableIter iter;
|
|
const char *name, *value;
|
|
|
|
g_return_val_if_fail (secrets != NULL, FALSE);
|
|
|
|
/* Make sure the items are valid */
|
|
g_hash_table_iter_init (&iter, secrets);
|
|
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &value)) {
|
|
if (!name || !strlen (name)) {
|
|
g_set_error_literal (error, NM_SETTING_ERROR,
|
|
NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH,
|
|
"Secret name was empty");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!value || !strlen (value)) {
|
|
g_set_error (error, NM_SETTING_ERROR,
|
|
NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH,
|
|
"Secret %s value was empty", name);
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/* Now add the items to the settings' secrets list */
|
|
g_hash_table_iter_init (&iter, secrets);
|
|
while (g_hash_table_iter_next (&iter, (gpointer *) &name, (gpointer *) &value)) {
|
|
if (value == NULL) {
|
|
g_warn_if_fail (value != NULL);
|
|
continue;
|
|
}
|
|
if (strlen (value) == 0) {
|
|
g_warn_if_fail (strlen (value) > 0);
|
|
continue;
|
|
}
|
|
|
|
g_hash_table_insert (priv->secrets, g_strdup (name), g_strdup (value));
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
update_one_secret (NMSetting *setting, const char *key, GValue *value, GError **error)
|
|
{
|
|
gboolean success = FALSE;
|
|
|
|
g_return_val_if_fail (key != NULL, FALSE);
|
|
g_return_val_if_fail (value != NULL, FALSE);
|
|
|
|
if (G_VALUE_HOLDS_STRING (value)) {
|
|
/* 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_value_get_string (value), error);
|
|
} else if (G_VALUE_HOLDS (value, DBUS_TYPE_G_MAP_OF_STRING)) {
|
|
if (strcmp (key, NM_SETTING_VPN_SECRETS) != 0) {
|
|
g_set_error (error, NM_SETTING_ERROR, NM_SETTING_ERROR_PROPERTY_NOT_SECRET,
|
|
"Property %s not a secret property", key);
|
|
} else
|
|
success = update_secret_hash (setting, g_value_get_boxed (value), error);
|
|
} else
|
|
g_set_error_literal (error, NM_SETTING_ERROR, NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH, key);
|
|
|
|
return success;
|
|
}
|
|
|
|
static gboolean
|
|
get_secret_flags (NMSetting *setting,
|
|
const char *secret_name,
|
|
gboolean verify_secret,
|
|
NMSettingSecretFlags *out_flags,
|
|
GError **error)
|
|
{
|
|
NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
|
|
gboolean success = FALSE;
|
|
char *flags_key;
|
|
gpointer val;
|
|
unsigned long tmp;
|
|
|
|
flags_key = g_strdup_printf ("%s-flags", secret_name);
|
|
if (g_hash_table_lookup_extended (priv->data, flags_key, NULL, &val)) {
|
|
errno = 0;
|
|
tmp = strtoul ((const char *) val, NULL, 10);
|
|
if ((errno == 0) && (tmp <= NM_SETTING_SECRET_FLAGS_ALL)) {
|
|
if (out_flags)
|
|
*out_flags = (guint32) tmp;
|
|
success = TRUE;
|
|
} else {
|
|
g_set_error (error,
|
|
NM_SETTING_ERROR,
|
|
NM_SETTING_ERROR_PROPERTY_TYPE_MISMATCH,
|
|
"Failed to convert '%s' value '%s' to uint",
|
|
flags_key, (const char *) val);
|
|
}
|
|
} else {
|
|
g_set_error (error,
|
|
NM_SETTING_ERROR,
|
|
NM_SETTING_ERROR_PROPERTY_NOT_FOUND,
|
|
"Secret flags property '%s' not found", flags_key);
|
|
}
|
|
g_free (flags_key);
|
|
return success;
|
|
}
|
|
|
|
static gboolean
|
|
set_secret_flags (NMSetting *setting,
|
|
const char *secret_name,
|
|
gboolean verify_secret,
|
|
NMSettingSecretFlags flags,
|
|
GError **error)
|
|
{
|
|
g_hash_table_insert (NM_SETTING_VPN_GET_PRIVATE (setting)->data,
|
|
g_strdup_printf ("%s-flags", secret_name),
|
|
g_strdup_printf ("%u", flags));
|
|
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 gboolean
|
|
compare_one_secret (NMSettingVPN *a,
|
|
NMSettingVPN *b,
|
|
NMSettingCompareFlags flags)
|
|
{
|
|
GHashTable *a_secrets, *b_secrets;
|
|
GHashTableIter iter;
|
|
const char *key, *val;
|
|
|
|
a_secrets = NM_SETTING_VPN_GET_PRIVATE (a)->secrets;
|
|
b_secrets = NM_SETTING_VPN_GET_PRIVATE (b)->secrets;
|
|
|
|
g_hash_table_iter_init (&iter, a_secrets);
|
|
while (g_hash_table_iter_next (&iter, (gpointer) &key, (gpointer) &val)) {
|
|
NMSettingSecretFlags a_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
NMSettingSecretFlags b_secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
nm_setting_get_secret_flags (NM_SETTING (a), key, &a_secret_flags, NULL);
|
|
nm_setting_get_secret_flags (NM_SETTING (b), key, &b_secret_flags, NULL);
|
|
|
|
/* If the secret flags aren't the same, the settings aren't the same */
|
|
if (a_secret_flags != b_secret_flags)
|
|
return FALSE;
|
|
|
|
if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS)
|
|
&& (a_secret_flags & NM_SETTING_SECRET_FLAG_AGENT_OWNED))
|
|
continue;
|
|
|
|
if ( (flags & NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)
|
|
&& (a_secret_flags & NM_SETTING_SECRET_FLAG_NOT_SAVED))
|
|
continue;
|
|
|
|
/* Now compare the values themselves */
|
|
if (g_strcmp0 (val, nm_setting_vpn_get_secret (b, key)) != 0)
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
static gboolean
|
|
compare_property (NMSetting *setting,
|
|
NMSetting *other,
|
|
const GParamSpec *prop_spec,
|
|
NMSettingCompareFlags flags)
|
|
{
|
|
gboolean same;
|
|
|
|
/* We only need to treat the 'secrets' property specially */
|
|
if (g_strcmp0 (prop_spec->name, NM_SETTING_VPN_SECRETS) != 0)
|
|
return NM_SETTING_CLASS (nm_setting_vpn_parent_class)->compare_property (setting, other, prop_spec, flags);
|
|
|
|
/* Compare A to B to ensure everything in A is found in B */
|
|
same = compare_one_secret (NM_SETTING_VPN (setting), NM_SETTING_VPN (other), flags);
|
|
if (same) {
|
|
/* And then B to A to ensure everything in B is also found in A */
|
|
same = compare_one_secret (NM_SETTING_VPN (other), NM_SETTING_VPN (setting), flags);
|
|
}
|
|
|
|
return same;
|
|
}
|
|
|
|
static void
|
|
clear_secrets_with_flags (NMSetting *setting,
|
|
GParamSpec *pspec,
|
|
NMSettingClearSecretsWithFlagsFn func,
|
|
gpointer user_data)
|
|
{
|
|
NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
|
|
GHashTableIter iter;
|
|
const char *secret;
|
|
|
|
if (priv->secrets == NULL)
|
|
return;
|
|
|
|
/* Iterate through secrets hash and check each entry */
|
|
g_hash_table_iter_init (&iter, priv->secrets);
|
|
while (g_hash_table_iter_next (&iter, (gpointer) &secret, NULL)) {
|
|
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
nm_setting_get_secret_flags (setting, secret, &flags, NULL);
|
|
if (func (setting, pspec->name, flags, user_data) == TRUE)
|
|
g_hash_table_iter_remove (&iter);
|
|
}
|
|
}
|
|
|
|
static void
|
|
destroy_one_secret (gpointer data)
|
|
{
|
|
char *secret = (char *) data;
|
|
|
|
/* Don't leave the secret lying around in memory */
|
|
memset (secret, 0, strlen (secret));
|
|
g_free (secret);
|
|
}
|
|
|
|
static void
|
|
nm_setting_vpn_init (NMSettingVPN *setting)
|
|
{
|
|
NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
|
|
|
|
g_object_set (setting, NM_SETTING_NAME, NM_SETTING_VPN_SETTING_NAME, NULL);
|
|
priv->data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
|
|
priv->secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, destroy_one_secret);
|
|
}
|
|
|
|
static void
|
|
finalize (GObject *object)
|
|
{
|
|
NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (object);
|
|
|
|
g_free (priv->service_type);
|
|
g_free (priv->user_name);
|
|
g_hash_table_destroy (priv->data);
|
|
g_hash_table_destroy (priv->secrets);
|
|
|
|
G_OBJECT_CLASS (nm_setting_vpn_parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
copy_hash (gpointer key, gpointer value, gpointer user_data)
|
|
{
|
|
g_return_if_fail (value != NULL);
|
|
g_return_if_fail (strlen (value));
|
|
g_hash_table_insert ((GHashTable *) user_data, g_strdup (key), g_strdup (value));
|
|
}
|
|
|
|
static void
|
|
set_property (GObject *object, guint prop_id,
|
|
const GValue *value, GParamSpec *pspec)
|
|
{
|
|
NMSettingVPNPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (object);
|
|
GHashTable *new_hash;
|
|
|
|
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_DATA:
|
|
/* Must make a deep copy of the hash table here... */
|
|
g_hash_table_remove_all (priv->data);
|
|
new_hash = g_value_get_boxed (value);
|
|
if (new_hash)
|
|
g_hash_table_foreach (new_hash, copy_hash, priv->data);
|
|
break;
|
|
case PROP_SECRETS:
|
|
/* Must make a deep copy of the hash table here... */
|
|
g_hash_table_remove_all (priv->secrets);
|
|
new_hash = g_value_get_boxed (value);
|
|
if (new_hash)
|
|
g_hash_table_foreach (new_hash, copy_hash, priv->secrets);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
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_DATA:
|
|
g_value_set_boxed (value, priv->data);
|
|
break;
|
|
case PROP_SECRETS:
|
|
g_value_set_boxed (value, priv->secrets);
|
|
break;
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
nm_setting_vpn_class_init (NMSettingVPNClass *setting_class)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (setting_class);
|
|
NMSettingClass *parent_class = NM_SETTING_CLASS (setting_class);
|
|
|
|
g_type_class_add_private (setting_class, sizeof (NMSettingVPNPrivate));
|
|
|
|
/* virtual methods */
|
|
object_class->set_property = set_property;
|
|
object_class->get_property = get_property;
|
|
object_class->finalize = finalize;
|
|
|
|
parent_class->verify = verify;
|
|
parent_class->update_one_secret = update_one_secret;
|
|
parent_class->get_secret_flags = get_secret_flags;
|
|
parent_class->set_secret_flags = set_secret_flags;
|
|
parent_class->need_secrets = need_secrets;
|
|
parent_class->compare_property = compare_property;
|
|
parent_class->clear_secrets_with_flags = clear_secrets_with_flags;
|
|
|
|
/* Properties */
|
|
/**
|
|
* 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.
|
|
**/
|
|
g_object_class_install_property
|
|
(object_class, PROP_SERVICE_TYPE,
|
|
g_param_spec_string (NM_SETTING_VPN_SERVICE_TYPE,
|
|
"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.",
|
|
NULL,
|
|
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
|
|
|
|
/**
|
|
* 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.
|
|
**/
|
|
g_object_class_install_property
|
|
(object_class, PROP_USER_NAME,
|
|
g_param_spec_string (NM_SETTING_VPN_USER_NAME,
|
|
"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.",
|
|
NULL,
|
|
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
|
|
|
|
/**
|
|
* NMSettingVPN:data:
|
|
*
|
|
* Dictionary of key/value pairs of VPN plugin specific data. Both keys
|
|
* and values must be strings.
|
|
**/
|
|
g_object_class_install_property
|
|
(object_class, PROP_DATA,
|
|
_nm_param_spec_specialized (NM_SETTING_VPN_DATA,
|
|
"Data",
|
|
"Dictionary of key/value pairs of VPN plugin "
|
|
"specific data. Both keys and values must be "
|
|
"strings.",
|
|
DBUS_TYPE_G_MAP_OF_STRING,
|
|
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE));
|
|
|
|
/**
|
|
* NMSettingVPN:secrets:
|
|
*
|
|
* Dictionary of key/value pairs of VPN plugin specific secrets like
|
|
* passwords or private keys. Both keys and values must be strings.
|
|
**/
|
|
g_object_class_install_property
|
|
(object_class, PROP_SECRETS,
|
|
_nm_param_spec_specialized (NM_SETTING_VPN_SECRETS,
|
|
"Secrets",
|
|
"Dictionary of key/value pairs of VPN plugin "
|
|
"specific secrets like passwords or private keys."
|
|
" Both keys and values must be strings.",
|
|
DBUS_TYPE_G_MAP_OF_STRING,
|
|
G_PARAM_READWRITE | NM_SETTING_PARAM_SERIALIZE | NM_SETTING_PARAM_SECRET));
|
|
}
|
|
|