mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-09-20 00:21:29 +00:00
firewall: merge branch 'th/firewall-callback-bgo755539'
https://bugzilla.gnome.org/show_bug.cgi?id=755539
This commit is contained in:
commit
19dd0574a7
|
@ -110,6 +110,39 @@ _nm_utils_set_testing (NMUtilsTestFlags flags)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error)
|
||||
|
||||
void
|
||||
nm_utils_error_set_cancelled (GError **error,
|
||||
gboolean is_disposing,
|
||||
const char *instance_name)
|
||||
{
|
||||
if (is_disposing) {
|
||||
g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING,
|
||||
"Disposing %s instance",
|
||||
instance_name && *instance_name ? instance_name : "source");
|
||||
} else {
|
||||
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
||||
"Request cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_utils_error_is_cancelled (GError *error,
|
||||
gboolean consider_is_disposing)
|
||||
{
|
||||
if (error) {
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return TRUE;
|
||||
if ( consider_is_disposing
|
||||
&& g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING))
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static GSList *_singletons = NULL;
|
||||
static gboolean _singletons_shutdown = FALSE;
|
||||
|
||||
|
|
|
@ -89,6 +89,31 @@ GETTER (void) \
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
/**
|
||||
* NMUtilsError:
|
||||
* @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error
|
||||
* @NM_UTILS_ERROR_CANCELLED_DISPOSING: when disposing an object that has
|
||||
* pending aynchronous operations, the operation is cancelled with this
|
||||
* error reason. Depending on the usage, this might indicate a bug because
|
||||
* usually the target object should stay alive as long as there are pending
|
||||
* operations.
|
||||
*/
|
||||
typedef enum {
|
||||
NM_UTILS_ERROR_UNKNOWN = 0, /*< nick=Unknown >*/
|
||||
NM_UTILS_ERROR_CANCELLED_DISPOSING, /*< nick=CancelledDisposing >*/
|
||||
} NMUtilsError;
|
||||
|
||||
#define NM_UTILS_ERROR (nm_utils_error_quark ())
|
||||
GQuark nm_utils_error_quark (void);
|
||||
|
||||
void nm_utils_error_set_cancelled (GError **error,
|
||||
gboolean is_disposing,
|
||||
const char *instance_name);
|
||||
gboolean nm_utils_error_is_cancelled (GError *error,
|
||||
gboolean consider_is_disposing);
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean nm_ethernet_address_is_valid (gconstpointer addr, gssize len);
|
||||
|
||||
in_addr_t nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen);
|
||||
|
|
|
@ -291,7 +291,7 @@ typedef struct {
|
|||
gulong dnsmasq_state_id;
|
||||
|
||||
/* Firewall */
|
||||
NMFirewallPendingCall fw_call;
|
||||
NMFirewallManagerCallId fw_call;
|
||||
|
||||
/* IPv4LL stuff */
|
||||
sd_ipv4ll * ipv4ll;
|
||||
|
@ -5527,19 +5527,24 @@ out:
|
|||
|
||||
|
||||
static void
|
||||
fw_change_zone_cb (GError *error, gpointer user_data)
|
||||
fw_change_zone_cb (NMFirewallManager *firewall_manager,
|
||||
NMFirewallManagerCallId call_id,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMDevice *self;
|
||||
NMDevice *self = user_data;
|
||||
NMDevicePrivate *priv;
|
||||
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
g_return_if_fail (NM_IS_DEVICE (self));
|
||||
|
||||
self = NM_DEVICE (user_data);
|
||||
priv = NM_DEVICE_GET_PRIVATE (self);
|
||||
|
||||
g_return_if_fail (priv->fw_call == call_id);
|
||||
priv->fw_call = NULL;
|
||||
|
||||
if (nm_utils_error_is_cancelled (error, FALSE))
|
||||
return;
|
||||
|
||||
if (error) {
|
||||
/* FIXME: fail the device activation? */
|
||||
}
|
||||
|
@ -8310,7 +8315,8 @@ _cancel_activation (NMDevice *self)
|
|||
|
||||
/* Clean up when device was deactivated during call to firewall */
|
||||
if (priv->fw_call) {
|
||||
nm_firewall_manager_cancel_call (nm_firewall_manager_get (), priv->fw_call);
|
||||
nm_firewall_manager_cancel_call (priv->fw_call);
|
||||
g_warn_if_fail (!priv->fw_call);
|
||||
priv->fw_call = NULL;
|
||||
}
|
||||
|
||||
|
@ -8334,6 +8340,8 @@ _cleanup_generic_pre (NMDevice *self, CleanupType cleanup_type)
|
|||
&& !nm_device_uses_assumed_connection (self)) {
|
||||
nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (),
|
||||
nm_device_get_ip_iface (self),
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
|
||||
|
|
|
@ -216,18 +216,7 @@ _do_cancel_secrets (NMActRequest *self, GetSecretsInfo *info, gboolean is_dispos
|
|||
if (info->callback) {
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
if (is_disposing) {
|
||||
/* Use a different error code. G_IO_ERROR_CANCELLED is only used synchronously
|
||||
* when the user calls nm_act_request_cancel_secrets(). Disposing the instance
|
||||
* with pending requests also cancels the requests, but with a different error
|
||||
* code. */
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Disposing NMActRequest instance");
|
||||
} else {
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
||||
"Request cancelled");
|
||||
}
|
||||
|
||||
nm_utils_error_set_cancelled (&error, is_disposing, "NMActRequest");
|
||||
info->callback (self, info, NULL, error, info->callback_data);
|
||||
}
|
||||
|
||||
|
|
|
@ -175,9 +175,8 @@ check_authorization_cb (GDBusProxy *proxy,
|
|||
value = _nm_dbus_proxy_call_finish (proxy, res, G_VARIANT_TYPE ("((bba{ss}))"), &error);
|
||||
if (value == NULL) {
|
||||
if (data->cancellation_id != NULL &&
|
||||
(!g_dbus_error_is_remote_error (error) &&
|
||||
error->domain == G_IO_ERROR &&
|
||||
error->code == G_IO_ERROR_CANCELLED)) {
|
||||
( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)
|
||||
&& !g_dbus_error_is_remote_error (error))) {
|
||||
_LOGD ("call[%u]: CheckAuthorization cancelled", data->call_id);
|
||||
g_dbus_proxy_call (priv->proxy,
|
||||
"CancelCheckAuthorization",
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
* Copyright (C) 2011 - 2015 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include "nm-default.h"
|
||||
#include "nm-firewall-manager.h"
|
||||
#include "gsystem-local-alloc.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
#define NM_FIREWALL_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
|
||||
|
@ -43,7 +44,7 @@ typedef struct {
|
|||
GDBusProxy * proxy;
|
||||
gboolean running;
|
||||
|
||||
GSList *pending_calls;
|
||||
GHashTable *pending_calls;
|
||||
} NMFirewallManagerPrivate;
|
||||
|
||||
enum {
|
||||
|
@ -54,190 +55,350 @@ enum {
|
|||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
NM_DEFINE_SINGLETON_GETTER (NMFirewallManager, nm_firewall_manager_get, NM_TYPE_FIREWALL_MANAGER);
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
#define PENDING_CALL_DUMMY ((NMFirewallPendingCall) GUINT_TO_POINTER(1))
|
||||
#define PENDING_CALL_FROM_INFO(info) ((NMFirewallPendingCall) info)
|
||||
typedef enum {
|
||||
CB_INFO_OPS_ADD = 1,
|
||||
CB_INFO_OPS_CHANGE,
|
||||
CB_INFO_OPS_REMOVE,
|
||||
} CBInfoOpsType;
|
||||
|
||||
typedef struct {
|
||||
typedef enum {
|
||||
CB_INFO_MODE_IDLE = 1,
|
||||
CB_INFO_MODE_DBUS,
|
||||
CB_INFO_MODE_DBUS_COMPLETED,
|
||||
} CBInfoMode;
|
||||
|
||||
struct _NMFirewallManagerCallId {
|
||||
NMFirewallManager *self;
|
||||
CBInfoOpsType ops_type;
|
||||
CBInfoMode mode;
|
||||
char *iface;
|
||||
FwAddToZoneFunc callback;
|
||||
NMFirewallManagerAddRemoveCallback callback;
|
||||
gpointer user_data;
|
||||
guint id;
|
||||
|
||||
guint idle_id;
|
||||
GCancellable *cancellable;
|
||||
} CBInfo;
|
||||
union {
|
||||
struct {
|
||||
GCancellable *cancellable;
|
||||
} dbus;
|
||||
struct {
|
||||
guint id;
|
||||
} idle;
|
||||
};
|
||||
};
|
||||
typedef struct _NMFirewallManagerCallId CBInfo;
|
||||
|
||||
static void
|
||||
_cb_info_complete_and_free (CBInfo *info,
|
||||
const char *tag,
|
||||
const char *debug_error_match,
|
||||
GError *error)
|
||||
/********************************************************************/
|
||||
|
||||
static const char *
|
||||
_ops_type_to_string (CBInfoOpsType ops_type)
|
||||
{
|
||||
gs_free_error GError *local = NULL;
|
||||
|
||||
g_return_if_fail (info != NULL);
|
||||
g_return_if_fail (tag != NULL);
|
||||
|
||||
/* A cancelled idle call won't set the error; catch that here */
|
||||
if (!error && g_cancellable_is_cancelled (info->cancellable)) {
|
||||
error = local = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
||||
"Operation was cancelled");
|
||||
switch (ops_type) {
|
||||
case CB_INFO_OPS_ADD: return "add";
|
||||
case CB_INFO_OPS_REMOVE: return "remove";
|
||||
case CB_INFO_OPS_CHANGE: return "change";
|
||||
default: g_return_val_if_reached ("unknown");
|
||||
}
|
||||
}
|
||||
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||
nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s call cancelled [%u]",
|
||||
info->iface, tag, info->id);
|
||||
} else if (error) {
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
if (!g_strcmp0 (error->message, debug_error_match)) {
|
||||
nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s failed [%u]: %s",
|
||||
info->iface, tag, info->id, error->message);
|
||||
} else {
|
||||
nm_log_warn (LOGD_FIREWALL, "(%s) firewall zone %s failed [%u]: %s",
|
||||
info->iface, tag, info->id, error->message);
|
||||
}
|
||||
} else {
|
||||
nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s succeeded [%u]",
|
||||
info->iface, tag, info->id);
|
||||
}
|
||||
#define _NMLOG_DOMAIN LOGD_FIREWALL
|
||||
#define _NMLOG_PREFIX_NAME "firewall"
|
||||
#define _NMLOG(level, info, ...) \
|
||||
G_STMT_START { \
|
||||
if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \
|
||||
CBInfo *__info = (info); \
|
||||
char __prefix_name[30]; \
|
||||
char __prefix_info[64]; \
|
||||
\
|
||||
_nm_log ((level), (_NMLOG_DOMAIN), 0, \
|
||||
"%s: %s" _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
||||
(self) != singleton_instance \
|
||||
? ({ \
|
||||
g_snprintf (__prefix_name, sizeof (__prefix_name), "%s[%p]", ""_NMLOG_PREFIX_NAME, (self)); \
|
||||
__prefix_name; \
|
||||
}) \
|
||||
: _NMLOG_PREFIX_NAME, \
|
||||
__info \
|
||||
? ({ \
|
||||
g_snprintf (__prefix_info, sizeof (__prefix_info), "[%p,%s%s:%s%s%s]: ", __info, \
|
||||
_ops_type_to_string (__info->ops_type), _cb_info_is_idle (__info) ? "*" : "", \
|
||||
NM_PRINT_FMT_QUOTE_STRING (__info->iface)); \
|
||||
__prefix_info; \
|
||||
}) \
|
||||
: "" \
|
||||
_NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
if (info->callback)
|
||||
info->callback (error, info->user_data);
|
||||
/********************************************************************/
|
||||
|
||||
g_free (info->iface);
|
||||
g_object_unref (info->cancellable);
|
||||
g_slice_free (CBInfo, info);
|
||||
static gboolean
|
||||
_cb_info_is_idle (CBInfo *info)
|
||||
{
|
||||
return info->mode == CB_INFO_MODE_IDLE;
|
||||
}
|
||||
|
||||
static CBInfo *
|
||||
_cb_info_create (NMFirewallManager *self, const char *iface, FwAddToZoneFunc callback, gpointer user_data)
|
||||
_cb_info_create (NMFirewallManager *self,
|
||||
CBInfoOpsType ops_type,
|
||||
const char *iface,
|
||||
NMFirewallManagerAddRemoveCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
|
||||
static guint id = 1;
|
||||
CBInfo *info;
|
||||
|
||||
info = g_slice_new0 (CBInfo);
|
||||
info->self = g_object_ref (self);
|
||||
info->id = id++;
|
||||
info->ops_type = ops_type;
|
||||
info->iface = g_strdup (iface);
|
||||
info->cancellable = g_cancellable_new ();
|
||||
info->callback = callback;
|
||||
info->user_data = user_data;
|
||||
|
||||
priv->pending_calls = g_slist_prepend (priv->pending_calls, info);
|
||||
if (priv->running) {
|
||||
info->mode = CB_INFO_MODE_DBUS;
|
||||
info->dbus.cancellable = g_cancellable_new ();
|
||||
} else
|
||||
info->mode = CB_INFO_MODE_IDLE;
|
||||
|
||||
if (!g_hash_table_add (priv->pending_calls, info))
|
||||
g_return_val_if_reached (NULL);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
add_or_change_idle_cb (gpointer user_data)
|
||||
static void
|
||||
_cb_info_free (CBInfo *info)
|
||||
{
|
||||
if (!_cb_info_is_idle (info))
|
||||
g_object_unref (info->dbus.cancellable);
|
||||
g_free (info->iface);
|
||||
if (info->self)
|
||||
g_object_unref (info->self);
|
||||
g_slice_free (CBInfo, info);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_info_callback (CBInfo *info,
|
||||
GError *error)
|
||||
{
|
||||
if (info->callback)
|
||||
info->callback (info->self, info, error, info->user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
_cb_info_complete_normal (CBInfo *info, GError *error)
|
||||
{
|
||||
NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (info->self);
|
||||
|
||||
if (!g_hash_table_remove (priv->pending_calls, info))
|
||||
g_return_if_reached ();
|
||||
|
||||
_cb_info_callback (info, error);
|
||||
_cb_info_free (info);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_handle_idle (gpointer user_data)
|
||||
{
|
||||
NMFirewallManager *self;
|
||||
CBInfo *info = user_data;
|
||||
|
||||
info->idle_id = 0;
|
||||
_cb_info_complete_and_free (info, "idle call", NULL, NULL);
|
||||
nm_assert (info && NM_IS_FIREWALL_MANAGER (info->self));
|
||||
|
||||
self = info->self;
|
||||
|
||||
_LOGD (info, "complete: fake success");
|
||||
|
||||
_cb_info_complete_normal (info, NULL);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static void
|
||||
add_or_change_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
|
||||
_handle_dbus (GObject *proxy, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
NMFirewallManager *self;
|
||||
CBInfo *info = user_data;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_unref_variant GVariant *ret = NULL;
|
||||
|
||||
if (info->mode != CB_INFO_MODE_DBUS) {
|
||||
_cb_info_free (info);
|
||||
return;
|
||||
}
|
||||
|
||||
self = info->self;
|
||||
|
||||
ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, &error);
|
||||
_cb_info_complete_and_free (info, "add/change", "ZONE_ALREADY_SET", error);
|
||||
|
||||
if (error) {
|
||||
const char *non_error = NULL;
|
||||
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
|
||||
switch (info->ops_type) {
|
||||
case CB_INFO_OPS_ADD:
|
||||
case CB_INFO_OPS_CHANGE:
|
||||
non_error = "ZONE_ALREADY_SET";
|
||||
break;
|
||||
case CB_INFO_OPS_REMOVE:
|
||||
non_error = "UNKNOWN_INTERFACE";
|
||||
break;
|
||||
}
|
||||
if (!g_strcmp0 (error->message, non_error)) {
|
||||
_LOGD (info, "complete: request failed with a non-error (%s)", error->message);
|
||||
|
||||
/* The operation failed with an error reason that we don't want
|
||||
* to propagate. Instead, signal success. */
|
||||
g_clear_error (&error);
|
||||
}
|
||||
else
|
||||
_LOGW (info, "complete: request failed (%s)", error->message);
|
||||
} else
|
||||
_LOGD (info, "complete: success");
|
||||
|
||||
_cb_info_complete_normal (info, error);
|
||||
}
|
||||
|
||||
NMFirewallPendingCall
|
||||
static NMFirewallManagerCallId
|
||||
_start_request (NMFirewallManager *self,
|
||||
CBInfoOpsType ops_type,
|
||||
const char *iface,
|
||||
const char *zone,
|
||||
NMFirewallManagerAddRemoveCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMFirewallManagerPrivate *priv;
|
||||
CBInfo *info;
|
||||
const char *dbus_method;
|
||||
|
||||
g_return_val_if_fail (NM_IS_FIREWALL_MANAGER (self), NULL);
|
||||
g_return_val_if_fail (iface && *iface, NULL);
|
||||
|
||||
priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
info = _cb_info_create (self, ops_type, iface, callback, user_data);
|
||||
|
||||
_LOGD (info, "firewall zone %s %s:%s%s%s%s",
|
||||
_ops_type_to_string (info->ops_type),
|
||||
iface,
|
||||
NM_PRINT_FMT_QUOTED (zone, "\"", zone, "\"", "default"),
|
||||
_cb_info_is_idle (info) ? " (not running, simulate success)" : "");
|
||||
|
||||
if (!_cb_info_is_idle (info)) {
|
||||
|
||||
switch (ops_type) {
|
||||
case CB_INFO_OPS_ADD:
|
||||
dbus_method = "addInterface";
|
||||
break;
|
||||
case CB_INFO_OPS_CHANGE:
|
||||
dbus_method = "changeZone";
|
||||
break;
|
||||
case CB_INFO_OPS_REMOVE:
|
||||
dbus_method = "removeInterface";
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
}
|
||||
|
||||
g_dbus_proxy_call (priv->proxy,
|
||||
dbus_method,
|
||||
g_variant_new ("(ss)", zone ? zone : "", iface),
|
||||
G_DBUS_CALL_FLAGS_NONE, 10000,
|
||||
info->dbus.cancellable,
|
||||
_handle_dbus,
|
||||
info);
|
||||
|
||||
if (!info->callback) {
|
||||
/* if the user did not provide a callback, the call_id is useless.
|
||||
* Especially, the user cannot use the call-id to cancel the request,
|
||||
* because he cannot know whether the request is still pending.
|
||||
*
|
||||
* Hence, returning %NULL doesn't mean that the request could not be started
|
||||
* (the request will always be started). */
|
||||
return NULL;
|
||||
}
|
||||
} else if (!info->callback) {
|
||||
/* if the user did not provide a callback and firewalld is not running,
|
||||
* there is no point in scheduling an idle-request to fake success. Just
|
||||
* return right away. */
|
||||
_LOGD (info, "complete: drop request simulating success");
|
||||
_cb_info_free (info);
|
||||
return NULL;
|
||||
} else
|
||||
info->idle.id = g_idle_add (_handle_idle, info);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
NMFirewallManagerCallId
|
||||
nm_firewall_manager_add_or_change_zone (NMFirewallManager *self,
|
||||
const char *iface,
|
||||
const char *zone,
|
||||
gboolean add, /* TRUE == add, FALSE == change */
|
||||
FwAddToZoneFunc callback,
|
||||
NMFirewallManagerAddRemoveCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
|
||||
CBInfo *info;
|
||||
|
||||
if (priv->running == FALSE) {
|
||||
if (callback) {
|
||||
info = _cb_info_create (self, iface, callback, user_data);
|
||||
info->idle_id = g_idle_add (add_or_change_idle_cb, info);
|
||||
nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s -> %s%s%s [%u] (not running, simulate success)", iface, add ? "add" : "change",
|
||||
zone?"\"":"", zone ? zone : "default", zone?"\"":"", info->id);
|
||||
return PENDING_CALL_FROM_INFO (info);
|
||||
} else {
|
||||
nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone add/change skipped (not running)", iface);
|
||||
return PENDING_CALL_DUMMY;
|
||||
}
|
||||
}
|
||||
|
||||
info = _cb_info_create (self, iface, callback, user_data);
|
||||
|
||||
nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone %s -> %s%s%s [%u]", iface, add ? "add" : "change",
|
||||
zone?"\"":"", zone ? zone : "default", zone?"\"":"", info->id);
|
||||
g_dbus_proxy_call (priv->proxy,
|
||||
add ? "addInterface" : "changeZone",
|
||||
g_variant_new ("(ss)", zone ? zone : "", iface),
|
||||
G_DBUS_CALL_FLAGS_NONE, 10000,
|
||||
info->cancellable,
|
||||
add_or_change_cb, info);
|
||||
return (NMFirewallPendingCall) info;
|
||||
return _start_request (self,
|
||||
add ? CB_INFO_OPS_ADD : CB_INFO_OPS_CHANGE,
|
||||
iface,
|
||||
zone,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_cb (GObject *proxy, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
CBInfo *info = user_data;
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_unref_variant GVariant *ret = NULL;
|
||||
|
||||
ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, &error);
|
||||
_cb_info_complete_and_free (info, "remove", "UNKNOWN_INTERFACE", error);
|
||||
}
|
||||
|
||||
NMFirewallPendingCall
|
||||
NMFirewallManagerCallId
|
||||
nm_firewall_manager_remove_from_zone (NMFirewallManager *self,
|
||||
const char *iface,
|
||||
const char *zone)
|
||||
const char *zone,
|
||||
NMFirewallManagerAddRemoveCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
|
||||
CBInfo *info;
|
||||
|
||||
if (priv->running == FALSE) {
|
||||
nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove skipped (not running)", iface);
|
||||
return PENDING_CALL_DUMMY;
|
||||
}
|
||||
|
||||
info = _cb_info_create (self, iface, NULL, NULL);
|
||||
|
||||
nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove -> %s%s%s [%u]", iface,
|
||||
zone?"\"":"", zone ? zone : "*", zone?"\"":"", info->id);
|
||||
g_dbus_proxy_call (priv->proxy,
|
||||
"removeInterface",
|
||||
g_variant_new ("(ss)", zone ? zone : "", iface),
|
||||
G_DBUS_CALL_FLAGS_NONE, 10000,
|
||||
info->cancellable,
|
||||
remove_cb, info);
|
||||
return (NMFirewallPendingCall) info;
|
||||
return _start_request (self,
|
||||
CB_INFO_OPS_REMOVE,
|
||||
iface,
|
||||
zone,
|
||||
callback,
|
||||
user_data);
|
||||
}
|
||||
|
||||
void
|
||||
nm_firewall_manager_cancel_call (NMFirewallManager *self, NMFirewallPendingCall call)
|
||||
nm_firewall_manager_cancel_call (NMFirewallManagerCallId call)
|
||||
{
|
||||
CBInfo *info = (CBInfo *) call;
|
||||
NMFirewallManager *self;
|
||||
NMFirewallManagerPrivate *priv;
|
||||
CBInfo *info = call;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
g_return_if_fail (NM_IS_FIREWALL_MANAGER (self));
|
||||
g_return_if_fail (info);
|
||||
g_return_if_fail (NM_IS_FIREWALL_MANAGER (info->self));
|
||||
|
||||
info->callback = NULL;
|
||||
info->idle_id = 0;
|
||||
g_cancellable_cancel (info->cancellable);
|
||||
self = info->self;
|
||||
priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
if (!g_hash_table_remove (priv->pending_calls, info))
|
||||
g_return_if_reached ();
|
||||
|
||||
nm_utils_error_set_cancelled (&error, FALSE, "NMFirewallManager");
|
||||
|
||||
_LOGD (info, "complete: cancel (%s)", error->message);
|
||||
|
||||
_cb_info_callback (info, error);
|
||||
|
||||
if (_cb_info_is_idle (info)) {
|
||||
g_source_remove (info->idle.id);
|
||||
_cb_info_free (info);
|
||||
} else {
|
||||
info->mode = CB_INFO_MODE_DBUS_COMPLETED;
|
||||
g_cancellable_cancel (info->dbus.cancellable);
|
||||
g_clear_object (&info->self);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
static void
|
||||
set_running (NMFirewallManager *self, gboolean now_running)
|
||||
{
|
||||
|
@ -259,25 +420,34 @@ name_owner_changed (GObject *object,
|
|||
|
||||
owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object));
|
||||
if (owner) {
|
||||
nm_log_dbg (LOGD_FIREWALL, "firewall started");
|
||||
_LOGD (NULL, "firewall started");
|
||||
set_running (self, TRUE);
|
||||
g_signal_emit (self, signals[STARTED], 0);
|
||||
} else {
|
||||
nm_log_dbg (LOGD_FIREWALL, "firewall stopped");
|
||||
_LOGD (NULL, "firewall stopped");
|
||||
set_running (self, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/*******************************************************************/
|
||||
|
||||
NM_DEFINE_SINGLETON_GETTER (NMFirewallManager, nm_firewall_manager_get, NM_TYPE_FIREWALL_MANAGER);
|
||||
|
||||
static void
|
||||
nm_firewall_manager_init (NMFirewallManager * self)
|
||||
{
|
||||
NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
priv->pending_calls = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
constructed (GObject *object)
|
||||
{
|
||||
NMFirewallManager *self = (NMFirewallManager *) object;
|
||||
NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
|
||||
gs_free char *owner = NULL;
|
||||
|
||||
G_OBJECT_CLASS (nm_firewall_manager_parent_class)->constructed (object);
|
||||
|
||||
priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES |
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS,
|
||||
|
@ -291,14 +461,7 @@ nm_firewall_manager_init (NMFirewallManager * self)
|
|||
G_CALLBACK (name_owner_changed), self);
|
||||
owner = g_dbus_proxy_get_name_owner (priv->proxy);
|
||||
priv->running = (owner != NULL);
|
||||
nm_log_dbg (LOGD_FIREWALL, "firewall %s running", priv->running ? "is" : "is not" );
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
_LOGD (NULL, "firewall constructed (%srunning)", priv->running ? "" : "not");
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -317,9 +480,16 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
|||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (object);
|
||||
NMFirewallManager *self = NM_FIREWALL_MANAGER (object);
|
||||
NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
g_assert (priv->pending_calls == NULL);
|
||||
if (priv->pending_calls) {
|
||||
/* as every pending operation takes a reference to the manager,
|
||||
* we don't expect pending operations at this point. */
|
||||
g_assert (g_hash_table_size (priv->pending_calls) == 0);
|
||||
g_hash_table_unref (priv->pending_calls);
|
||||
priv->pending_calls = NULL;
|
||||
}
|
||||
|
||||
g_clear_object (&priv->proxy);
|
||||
|
||||
|
@ -334,25 +504,25 @@ nm_firewall_manager_class_init (NMFirewallManagerClass *klass)
|
|||
|
||||
g_type_class_add_private (object_class, sizeof (NMFirewallManagerPrivate));
|
||||
|
||||
object_class->constructed = constructed;
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
object_class->dispose = dispose;
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_AVAILABLE,
|
||||
g_param_spec_boolean (NM_FIREWALL_MANAGER_AVAILABLE, "", "",
|
||||
FALSE,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
(object_class, PROP_AVAILABLE,
|
||||
g_param_spec_boolean (NM_FIREWALL_MANAGER_AVAILABLE, "", "",
|
||||
FALSE,
|
||||
G_PARAM_READABLE |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
signals[STARTED] =
|
||||
g_signal_new ("started",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMFirewallManagerClass, started),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
g_signal_new ("started",
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
G_STRUCT_OFFSET (NMFirewallManagerClass, started),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -40,8 +40,8 @@ G_BEGIN_DECLS
|
|||
|
||||
#define NM_FIREWALL_MANAGER_AVAILABLE "available"
|
||||
|
||||
struct _NMFirewallPendingCall;
|
||||
typedef struct _NMFirewallPendingCall *NMFirewallPendingCall;
|
||||
struct _NMFirewallManagerCallId;
|
||||
typedef struct _NMFirewallManagerCallId *NMFirewallManagerCallId;
|
||||
|
||||
typedef struct {
|
||||
GObject parent;
|
||||
|
@ -58,18 +58,23 @@ GType nm_firewall_manager_get_type (void);
|
|||
|
||||
NMFirewallManager *nm_firewall_manager_get (void);
|
||||
|
||||
typedef void (*FwAddToZoneFunc) (GError *error, gpointer user_data);
|
||||
typedef void (*NMFirewallManagerAddRemoveCallback) (NMFirewallManager *self,
|
||||
NMFirewallManagerCallId call_id,
|
||||
GError *error,
|
||||
gpointer user_data);
|
||||
|
||||
NMFirewallPendingCall nm_firewall_manager_add_or_change_zone (NMFirewallManager *mgr,
|
||||
NMFirewallManagerCallId nm_firewall_manager_add_or_change_zone (NMFirewallManager *mgr,
|
||||
const char *iface,
|
||||
const char *zone,
|
||||
gboolean add,
|
||||
NMFirewallManagerAddRemoveCallback callback,
|
||||
gpointer user_data);
|
||||
NMFirewallManagerCallId nm_firewall_manager_remove_from_zone (NMFirewallManager *mgr,
|
||||
const char *iface,
|
||||
const char *zone,
|
||||
gboolean add,
|
||||
FwAddToZoneFunc callback,
|
||||
NMFirewallManagerAddRemoveCallback callback,
|
||||
gpointer user_data);
|
||||
NMFirewallPendingCall nm_firewall_manager_remove_from_zone (NMFirewallManager *mgr,
|
||||
const char *iface,
|
||||
const char *zone);
|
||||
|
||||
void nm_firewall_manager_cancel_call (NMFirewallManager *mgr, NMFirewallPendingCall fw_call);
|
||||
void nm_firewall_manager_cancel_call (NMFirewallManagerCallId fw_call);
|
||||
|
||||
#endif /* __NETWORKMANAGER_FIREWALL_MANAGER_H__ */
|
||||
|
|
|
@ -576,19 +576,15 @@ req_complete_release (Request *req,
|
|||
}
|
||||
|
||||
static void
|
||||
req_complete_cancel (Request *req,
|
||||
GQuark domain,
|
||||
guint code,
|
||||
const char *message)
|
||||
req_complete_cancel (Request *req, gboolean is_disposing)
|
||||
{
|
||||
GError *error = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
nm_assert (req && req->self);
|
||||
nm_assert (!g_hash_table_contains (NM_AGENT_MANAGER_GET_PRIVATE (req->self)->requests, req));
|
||||
|
||||
g_set_error_literal (&error, domain, code, message);
|
||||
nm_utils_error_set_cancelled (&error, is_disposing, "NMAgentManager");
|
||||
req_complete_release (req, NULL, NULL, NULL, error);
|
||||
g_error_free (error);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -1242,7 +1238,7 @@ nm_agent_manager_cancel_secrets (NMAgentManager *self,
|
|||
request_id))
|
||||
g_return_if_reached ();
|
||||
|
||||
req_complete_cancel (request_id, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Request cancelled");
|
||||
req_complete_cancel (request_id, FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
@ -1571,12 +1567,14 @@ dispose (GObject *object)
|
|||
GHashTableIter iter;
|
||||
Request *req;
|
||||
|
||||
cancel_more:
|
||||
g_hash_table_iter_init (&iter, priv->requests);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &req, NULL)) {
|
||||
if (g_hash_table_iter_next (&iter, (gpointer *) &req, NULL)) {
|
||||
g_hash_table_iter_remove (&iter);
|
||||
req_complete_cancel (req, G_IO_ERROR, G_IO_ERROR_FAILED, "Disposing NMAgentManagerClass instance");
|
||||
req_complete_cancel (req, TRUE);
|
||||
goto cancel_more;
|
||||
}
|
||||
g_hash_table_destroy (priv->requests);
|
||||
g_hash_table_unref (priv->requests);
|
||||
priv->requests = NULL;
|
||||
}
|
||||
|
||||
|
|
|
@ -29,6 +29,7 @@
|
|||
#include "nm-bus-manager.h"
|
||||
#include "nm-auth-subject.h"
|
||||
#include "nm-simple-connection.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
|
||||
#include "nmdbus-secret-agent.h"
|
||||
|
||||
|
@ -428,23 +429,12 @@ do_cancel_secrets (NMSecretAgent *self, Request *r, gboolean disposing)
|
|||
* Only clear r->cancellable to indicate that the request was cancelled. */
|
||||
|
||||
if (callback) {
|
||||
GError *error = NULL;
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
if (disposing) {
|
||||
/* hijack an error code. G_IO_ERROR_CANCELLED is only used synchronously
|
||||
* when the user calls nm_act_request_cancel_secrets().
|
||||
* When the user disposes the instance, we also invoke the callback synchronously,
|
||||
* but with a different error-reason. */
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Disposing NMSecretAgent instance");
|
||||
} else {
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
||||
"Request cancelled");
|
||||
}
|
||||
nm_utils_error_set_cancelled (&error, disposing, "NMSecretAgent");
|
||||
/* @r might be a dangling pointer at this point. However, that is no problem
|
||||
* to pass it as (opaque) call_id. */
|
||||
callback (self, r, NULL, error, callback_data);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1270,10 +1270,9 @@ schedule_dummy:
|
|||
static void
|
||||
_get_secrets_cancel (NMSettingsConnection *self,
|
||||
GetSecretsInfo *info,
|
||||
gboolean shutdown)
|
||||
gboolean is_disposing)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
|
||||
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
if (!g_slist_find (priv->get_secret_requests, info))
|
||||
|
@ -1286,17 +1285,7 @@ _get_secrets_cancel (NMSettingsConnection *self,
|
|||
else
|
||||
g_source_remove (info->t.idle.id);
|
||||
|
||||
if (shutdown) {
|
||||
/* Use a different error code. G_IO_ERROR_CANCELLED is only used synchronously
|
||||
* when the user calls nm_act_request_cancel_secrets(). Disposing the instance
|
||||
* with pending requests also cancels the requests, but with a different error
|
||||
* code. */
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Disposing NMActRequest instance");
|
||||
} else {
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
||||
"Request cancelled");
|
||||
}
|
||||
nm_utils_error_set_cancelled (&error, is_disposing, "NMSettingsConnection");
|
||||
|
||||
_get_secrets_info_callback (info, NULL, NULL, error);
|
||||
|
||||
|
|
|
@ -91,7 +91,7 @@ typedef struct {
|
|||
NMVpnServiceState service_state;
|
||||
|
||||
/* Firewall */
|
||||
NMFirewallPendingCall fw_call;
|
||||
NMFirewallManagerCallId fw_call;
|
||||
|
||||
NMDefaultRouteManager *default_route_manager;
|
||||
NMRouteManager *route_manager;
|
||||
|
@ -323,7 +323,8 @@ fw_call_cleanup (NMVpnConnection *self)
|
|||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
|
||||
|
||||
if (priv->fw_call) {
|
||||
nm_firewall_manager_cancel_call (nm_firewall_manager_get (), priv->fw_call);
|
||||
nm_firewall_manager_cancel_call (priv->fw_call);
|
||||
g_warn_if_fail (!priv->fw_call);
|
||||
priv->fw_call = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -343,10 +344,13 @@ vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev)
|
|||
nm_device_set_vpn6_config (parent_dev, NULL);
|
||||
|
||||
/* Remove zone from firewall */
|
||||
if (priv->ip_iface)
|
||||
if (priv->ip_iface) {
|
||||
nm_firewall_manager_remove_from_zone (nm_firewall_manager_get (),
|
||||
priv->ip_iface,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL);
|
||||
}
|
||||
/* Cancel pending firewall call */
|
||||
fw_call_cleanup (self);
|
||||
|
||||
|
@ -1090,19 +1094,25 @@ _cleanup_failed_config (NMVpnConnection *self)
|
|||
}
|
||||
|
||||
static void
|
||||
fw_change_zone_cb (GError *error, gpointer user_data)
|
||||
fw_change_zone_cb (NMFirewallManager *firewall_manager,
|
||||
NMFirewallManagerCallId call_id,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMVpnConnection *self = NM_VPN_CONNECTION (user_data);
|
||||
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
|
||||
NMVpnConnection *self = user_data;
|
||||
NMVpnConnectionPrivate *priv;
|
||||
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
|
||||
return;
|
||||
g_return_if_fail (NM_IS_VPN_CONNECTION (self));
|
||||
|
||||
priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
|
||||
g_return_if_fail (priv->fw_call == call_id);
|
||||
|
||||
priv->fw_call = NULL;
|
||||
|
||||
if (nm_utils_error_is_cancelled (error, FALSE))
|
||||
return;
|
||||
|
||||
if (error) {
|
||||
_LOGW ("VPN connection: setting firewall zone failed: '%s'",
|
||||
error->message);
|
||||
// FIXME: fail the activation?
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue