NetworkManager/src/vpn-manager/nm-vpn-manager.c
Dan Winship da8d79f1c5 core: drop all remaining core-internal error domains
A number of classes in core had their own error domains that aren't
really necessary.

In the case of NMDcbError, NMDhcpManagerError, NMDnsManagerError,
NMDnsmasqManagerError, NMPppManagerError, and NMSessionMonitorError,
most of the codes they defined weren't even being used, and at any
rate, the errors were always returned into contexts where they would
just have their message extracted and then get thrown away without
anyone ever looking at the domain or code. So all uses of those
domains can just be replaced with NM_MANAGER_ERROR_FAILED without any
loss of information.

NMAuthManagerError only had 1 error code, and it just indicated
"something went wrong", so it can be replaced with
NM_MANAGER_ERROR_FAILED without loss of information.
(nm-auth-manager.c has also been fixed to return
NM_MANAGER_ERROR_FAILED when the CheckAuthorization D-Bus call fails,
rather than returning whatever error domain/code the D-Bus call
returned.)

NMVpnManagerError used 2 of its 4 error codes, and they could actually
end up getting returned across D-Bus in some cases. But there are
NMManagerError codes that are semantically similar enough to make the
NMVpnManagerError ones unnecessary.
2014-10-22 08:29:10 -04:00

297 lines
8.8 KiB
C

/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2005 - 2012 Red Hat, Inc.
* Copyright (C) 2006 - 2008 Novell, Inc.
*/
#include <string.h>
#include <gio/gio.h>
#include "nm-vpn-manager.h"
#include "nm-vpn-service.h"
#include "nm-vpn-connection.h"
#include "nm-setting-vpn.h"
#include "nm-dbus-manager.h"
#include "nm-vpn-dbus-interface.h"
#include "nm-enum-types.h"
#include "nm-logging.h"
#define VPN_NAME_FILES_DIR NMCONFDIR "/VPN"
G_DEFINE_TYPE (NMVpnManager, nm_vpn_manager, G_TYPE_OBJECT)
#define NM_VPN_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_MANAGER, NMVpnManagerPrivate))
typedef struct {
GHashTable *services;
GFileMonitor *monitor;
guint monitor_id;
} NMVpnManagerPrivate;
static NMVpnService *
get_service_by_namefile (NMVpnManager *self, const char *namefile)
{
NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
GHashTableIter iter;
gpointer data;
g_return_val_if_fail (namefile, NULL);
g_return_val_if_fail (g_path_is_absolute (namefile), NULL);
g_hash_table_iter_init (&iter, priv->services);
while (g_hash_table_iter_next (&iter, NULL, &data)) {
NMVpnService *candidate = NM_VPN_SERVICE (data);
const char *service_namefile;
service_namefile = nm_vpn_service_get_name_file (candidate);
if (!strcmp (namefile, service_namefile))
return candidate;
}
return NULL;
}
gboolean
nm_vpn_manager_activate_connection (NMVpnManager *manager,
NMVpnConnection *vpn,
GError **error)
{
NMConnection *connection;
NMSettingVpn *s_vpn;
NMVpnService *service;
const char *service_name;
NMDevice *device;
g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), FALSE);
g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE);
g_return_val_if_fail (error != NULL, FALSE);
g_return_val_if_fail (*error == NULL, FALSE);
device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
g_assert (device);
if ( nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED
&& nm_device_get_state (device) != NM_DEVICE_STATE_SECONDARIES) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
"The base device for the VPN connection was not active.");
return FALSE;
}
connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (vpn));
g_assert (connection);
s_vpn = nm_connection_get_setting_vpn (connection);
g_assert (s_vpn);
service_name = nm_setting_vpn_get_service_type (s_vpn);
g_assert (service_name);
service = g_hash_table_lookup (NM_VPN_MANAGER_GET_PRIVATE (manager)->services, service_name);
if (!service) {
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE,
"The VPN service '%s' was not installed.",
service_name);
return FALSE;
}
return nm_vpn_service_activate (service, vpn, error);
}
gboolean
nm_vpn_manager_deactivate_connection (NMVpnManager *self,
NMVpnConnection *connection,
NMVpnConnectionStateReason reason)
{
return nm_vpn_connection_deactivate (connection, reason, FALSE);
}
static void
try_add_service (NMVpnManager *self, const char *namefile)
{
NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
NMVpnService *service = NULL;
GHashTableIter iter;
GError *error = NULL;
const char *service_name;
g_return_if_fail (g_path_is_absolute (namefile));
/* Make sure we don't add dupes */
g_hash_table_iter_init (&iter, priv->services);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &service)) {
if (g_strcmp0 (namefile, nm_vpn_service_get_name_file (service)) == 0)
return;
}
/* New service */
service = nm_vpn_service_new (namefile, &error);
if (service) {
service_name = nm_vpn_service_get_dbus_service (service);
g_hash_table_insert (priv->services, (char *) service_name, service);
nm_log_info (LOGD_VPN, "VPN: loaded %s", service_name);
} else {
nm_log_warn (LOGD_VPN, "failed to load VPN service file %s: (%d) %s",
namefile,
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_clear_error (&error);
}
}
static void
vpn_dir_changed (GFileMonitor *monitor,
GFile *file,
GFile *other_file,
GFileMonitorEvent event_type,
gpointer user_data)
{
NMVpnManager *self = NM_VPN_MANAGER (user_data);
NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
NMVpnService *service;
char *path;
path = g_file_get_path (file);
if (!g_str_has_suffix (path, ".name")) {
g_free (path);
return;
}
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
nm_log_dbg (LOGD_VPN, "service file %s deleted", path);
service = get_service_by_namefile (self, path);
if (service) {
const char *service_name = nm_vpn_service_get_dbus_service (service);
/* Stop active VPN connections and destroy the service */
nm_vpn_service_stop_connections (service, FALSE,
NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED);
nm_log_info (LOGD_VPN, "VPN: unloaded %s", service_name);
g_hash_table_remove (priv->services, service_name);
}
break;
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
nm_log_dbg (LOGD_VPN, "service file %s created or modified", path);
try_add_service (self, path);
break;
default:
nm_log_dbg (LOGD_VPN, "service file %s change event %d", path, event_type);
break;
}
g_free (path);
}
/******************************************************************************/
NMVpnManager *
nm_vpn_manager_get (void)
{
static NMVpnManager *singleton = NULL;
if (!singleton)
singleton = NM_VPN_MANAGER (g_object_new (NM_TYPE_VPN_MANAGER, NULL));
else
g_object_ref (singleton);
g_assert (singleton);
return singleton;
}
static void
nm_vpn_manager_init (NMVpnManager *self)
{
NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
GFile *file;
GDir *dir;
const char *fn;
char *path;
priv->services = g_hash_table_new_full (g_str_hash, g_str_equal,
NULL, g_object_unref);
/* Watch the VPN directory for changes */
file = g_file_new_for_path (VPN_NAME_FILES_DIR "/");
priv->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (priv->monitor) {
priv->monitor_id = g_signal_connect (priv->monitor, "changed",
G_CALLBACK (vpn_dir_changed), self);
}
/* Load VPN service files */
dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL);
if (dir) {
while ((fn = g_dir_read_name (dir))) {
/* only parse filenames that end with .name */
if (g_str_has_suffix (fn, ".name")) {
path = g_build_filename (VPN_NAME_FILES_DIR, fn, NULL);
try_add_service (self, path);
g_free (path);
}
}
g_dir_close (dir);
}
}
static void
stop_all_services (NMVpnManager *self)
{
NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
GHashTableIter iter;
NMVpnService *service;
g_hash_table_iter_init (&iter, priv->services);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &service)) {
nm_vpn_service_stop_connections (service,
TRUE,
NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED);
}
}
static void
dispose (GObject *object)
{
NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (object);
if (priv->monitor) {
if (priv->monitor_id)
g_signal_handler_disconnect (priv->monitor, priv->monitor_id);
g_file_monitor_cancel (priv->monitor);
g_clear_object (&priv->monitor);
}
if (priv->services) {
stop_all_services (NM_VPN_MANAGER (object));
g_hash_table_destroy (priv->services);
priv->services = NULL;
}
G_OBJECT_CLASS (nm_vpn_manager_parent_class)->dispose (object);
}
static void
nm_vpn_manager_class_init (NMVpnManagerClass *manager_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (manager_class);
g_type_class_add_private (manager_class, sizeof (NMVpnManagerPrivate));
/* virtual methods */
object_class->dispose = dispose;
}