summary refs log tree commit diff
path: root/src/nm-firewall-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-firewall-manager.c')
-rw-r--r--src/nm-firewall-manager.c578
1 files changed, 341 insertions, 237 deletions
diff --git a/src/nm-firewall-manager.c b/src/nm-firewall-manager.c
index 4d302e9d..5e5248a9 100644
--- a/src/nm-firewall-manager.c
+++ b/src/nm-firewall-manager.c
@@ -15,19 +15,17 @@
  * 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"
 
 #include <string.h>
-#include <glib.h>
-#include <gio/gio.h>
-#include <dbus/dbus.h>
 
+#include "nm-default.h"
 #include "nm-firewall-manager.h"
-#include "nm-dbus-manager.h"
-#include "nm-logging.h"
+#include "gsystem-local-alloc.h"
+#include "NetworkManagerUtils.h"
 
 #define NM_FIREWALL_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
                                               NM_TYPE_FIREWALL_MANAGER, \
@@ -43,12 +41,10 @@ enum {
 };
 
 typedef struct {
-	NMDBusManager * dbus_mgr;
-	guint           name_owner_id;
-	DBusGProxy *    proxy;
+	GDBusProxy *    proxy;
 	gboolean        running;
 
-	GSList         *pending_calls;
+	GHashTable     *pending_calls;
 } NMFirewallManagerPrivate;
 
 enum {
@@ -59,246 +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;
-	gboolean completed;
-
-	guint idle_id;
-	DBusGProxyCall *dbus_call;
-} CBInfo;
-
-static void
-_cb_info_free (CBInfo *info)
-{
-	NMFirewallManagerPrivate *priv;
 
-	g_return_if_fail (info != NULL);
+	union {
+		struct {
+			GCancellable *cancellable;
+		} dbus;
+		struct {
+			guint id;
+		} idle;
+	};
+};
+typedef struct _NMFirewallManagerCallId CBInfo;
 
-	if (!info->completed) {
-		nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone call cancelled [%u]", info->iface, info->id);
-		if (info->callback) {
-			GError *error;
+/********************************************************************/
 
-			error = g_error_new_literal (G_IO_ERROR, G_IO_ERROR_CANCELLED,
-			                             "Operation was cancelled");
-			info->callback (error, info->user_data);
-			g_error_free (error);
-		}
+static const char *
+_ops_type_to_string (CBInfoOpsType ops_type)
+{
+	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");
 	}
-	g_free (info->iface);
+}
 
-	priv = NM_FIREWALL_MANAGER_GET_PRIVATE (info->self);
-	priv->pending_calls = g_slist_remove (priv->pending_calls, info);
-	g_object_unref (info->self);
+#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
 
-	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;
 	CBInfo *info;
 
 	info = g_slice_new0 (CBInfo);
-	if (++id == 0)
-		++id;
 	info->self = g_object_ref (self);
-	info->id = id;
+	info->ops_type = ops_type;
 	info->iface = g_strdup (iface);
-	info->completed = FALSE;
 	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 (!nm_g_hash_table_add (priv->pending_calls, info))
+		g_return_val_if_reached (NULL);
+
 	return info;
 }
 
+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
-add_or_change_idle_cb (gpointer user_data)
+_handle_idle (gpointer user_data)
 {
+	NMFirewallManager *self;
 	CBInfo *info = user_data;
 
-	if (info->idle_id == 0) {
-		/* operation was cancelled. _cb_info_free will invoke callback. */
-	} else {
-		nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone call pretends success [%u]",
-		            info->iface, info->id);
-		if (info->callback)
-			info->callback (NULL, info->user_data);
-		info->completed = TRUE;
-		info->idle_id = 0;
-	}
+	nm_assert (info && NM_IS_FIREWALL_MANAGER (info->self));
 
-	_cb_info_free (info);
+	self = info->self;
+
+	_LOGD (info, "complete: fake success");
+
+	_cb_info_complete_normal (info, NULL);
 	return G_SOURCE_REMOVE;
 }
 
 static void
-add_or_change_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+_handle_dbus (GObject *proxy, GAsyncResult *result, gpointer user_data)
 {
+	NMFirewallManager *self;
 	CBInfo *info = user_data;
-	GError *error = NULL;
-	char *zone = NULL;
-
-	if (!dbus_g_proxy_end_call (proxy, call_id, &error,
-	                            G_TYPE_STRING, &zone,
-	                            G_TYPE_INVALID)) {
-		g_assert (error);
-		if (g_strcmp0 (error->message, "ZONE_ALREADY_SET") != 0) {
-			nm_log_warn (LOGD_FIREWALL, "(%s) firewall zone add/change failed [%u]: (%d) %s",
-			             info->iface, info->id, error->code, error->message);
-		} else {
-			nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone add/change failed [%u]: (%d) %s",
-			            info->iface, info->id, error->code, error->message);
-		}
-	} else {
-		nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone add/change succeeded [%u]",
-		            info->iface, info->id);
+	gs_free_error GError *error = NULL;
+	gs_unref_variant GVariant *ret = NULL;
+
+	if (info->mode != CB_INFO_MODE_DBUS) {
+		_cb_info_free (info);
+		return;
 	}
 
-	if (info->callback)
-		info->callback (error, info->user_data);
+	self = info->self;
+
+	ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), result, &error);
 
-	info->completed = TRUE;
-	g_free (zone);
-	g_clear_error (&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
-nm_firewall_manager_add_or_change_zone (NMFirewallManager *self,
-                                        const char *iface,
-                                        const char *zone,
-                                        gboolean add, /* TRUE == add, FALSE == change */
-                                        FwAddToZoneFunc callback,
-                                        gpointer user_data)
+static NMFirewallManagerCallId
+_start_request (NMFirewallManager *self,
+                CBInfoOpsType ops_type,
+                const char *iface,
+                const char *zone,
+                NMFirewallManagerAddRemoveCallback callback,
+                gpointer user_data)
 {
-	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
+	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 ();
+		}
 
-	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;
+		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_complete_normal (info, NULL);
+		return NULL;
+	} else
+		info->idle.id = g_idle_add (_handle_idle, info);
 
-	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);
-	info->dbus_call = dbus_g_proxy_begin_call_with_timeout (priv->proxy,
-	                                                        add ? "addInterface" : "changeZone",
-	                                                        add_or_change_cb,
-	                                                        info,
-	                                                        (GDestroyNotify) _cb_info_free,
-	                                                        10000,      /* timeout */
-	                                                        G_TYPE_STRING, zone ? zone : "",
-	                                                        G_TYPE_STRING, iface,
-	                                                        G_TYPE_INVALID);
-	return PENDING_CALL_FROM_INFO (info);
+	return info;
 }
 
-static void
-remove_cb (DBusGProxy *proxy, DBusGProxyCall *call_id, gpointer user_data)
+NMFirewallManagerCallId
+nm_firewall_manager_add_or_change_zone (NMFirewallManager *self,
+                                        const char *iface,
+                                        const char *zone,
+                                        gboolean add, /* TRUE == add, FALSE == change */
+                                        NMFirewallManagerAddRemoveCallback callback,
+                                        gpointer user_data)
 {
-	CBInfo *info = user_data;
-	GError *error = NULL;
-	char * zone = NULL;
-
-	if (!dbus_g_proxy_end_call (proxy, call_id, &error,
-	                            G_TYPE_STRING, &zone,
-	                            G_TYPE_INVALID)) {
-		g_assert (error);
-		/* ignore UNKNOWN_INTERFACE errors */
-		if (error->message && !strstr (error->message, "UNKNOWN_INTERFACE")) {
-			nm_log_warn (LOGD_FIREWALL, "(%s) firewall zone remove failed [%u]: (%d) %s",
-			             info->iface, info->id, error->code, error->message);
-		} else {
-			nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove failed [%u]: (%d) %s",
-			            info->iface, info->id, error->code, error->message);
-		}
-	} else {
-		nm_log_dbg (LOGD_FIREWALL, "(%s) firewall zone remove succeeded [%u]",
-		            info->iface, info->id);
-	}
-
-	info->completed = TRUE;
-	g_free (zone);
-	g_clear_error (&error);
+	return _start_request (self,
+	                       add ? CB_INFO_OPS_ADD : CB_INFO_OPS_CHANGE,
+	                       iface,
+	                       zone,
+	                       callback,
+	                       user_data);
 }
 
-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);
-	info->dbus_call = dbus_g_proxy_begin_call_with_timeout (priv->proxy,
-	                                                        "removeInterface",
-	                                                        remove_cb,
-	                                                        info,
-	                                                        (GDestroyNotify) _cb_info_free,
-	                                                        10000,      /* timeout */
-	                                                        G_TYPE_STRING, zone ? zone : "",
-	                                                        G_TYPE_STRING, iface,
-	                                                        G_TYPE_INVALID);
-	return PENDING_CALL_FROM_INFO (info);
+	return _start_request (self,
+	                       CB_INFO_OPS_REMOVE,
+	                       iface,
+	                       zone,
+	                       callback,
+	                       user_data);
 }
 
-void nm_firewall_manager_cancel_call (NMFirewallManager *self, NMFirewallPendingCall call)
+void
+nm_firewall_manager_cancel_call (NMFirewallManagerCallId call)
 {
-	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
-	GSList *pending;
-	CBInfo *info;
+	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));
 
-	if (call == PENDING_CALL_DUMMY)
-		return;
+	self = info->self;
+	priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
 
-	pending = g_slist_find (priv->pending_calls, call);
+	if (!g_hash_table_remove (priv->pending_calls, info))
+		g_return_if_reached ();
 
-	if (!pending)
-		return;
-	priv->pending_calls = g_slist_remove_link (priv->pending_calls, pending);
-
-	info = (CBInfo *) call;
-	if (info->idle_id)
-		info->idle_id = 0;
-	else {
-		dbus_g_proxy_cancel_call (NM_FIREWALL_MANAGER_GET_PRIVATE (self)->proxy,
-		                          info->dbus_call);
+	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)
 {
@@ -311,59 +411,62 @@ set_running (NMFirewallManager *self, gboolean now_running)
 }
 
 static void
-name_owner_changed (NMDBusManager *dbus_mgr,
-                    const char *name,
-                    const char *old_owner,
-                    const char *new_owner,
-                    gpointer user_data)
+name_owner_changed (GObject    *object,
+                    GParamSpec *pspec,
+                    gpointer    user_data)
 {
 	NMFirewallManager *self = NM_FIREWALL_MANAGER (user_data);
-	gboolean old_owner_good = (old_owner && strlen (old_owner));
-	gboolean new_owner_good = (new_owner && strlen (new_owner));
-
-	/* We only care about the firewall here */
-	if (strcmp (FIREWALL_DBUS_SERVICE, name) != 0)
-		return;
+	gs_free char *owner = NULL;
 
-	if (!old_owner_good && new_owner_good) {
-		nm_log_dbg (LOGD_FIREWALL, "firewall started");
+	owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (object));
+	if (owner) {
+		_LOGD (NULL, "firewall started");
 		set_running (self, TRUE);
 		g_signal_emit (self, signals[STARTED], 0);
-	} else if (old_owner_good && !new_owner_good) {
-		nm_log_dbg (LOGD_FIREWALL, "firewall stopped");
+	} else {
+		_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);
-	DBusGConnection *bus;
-
-	priv->dbus_mgr = g_object_ref (nm_dbus_manager_get ());
-	priv->name_owner_id = g_signal_connect (priv->dbus_mgr,
-	                                        NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
-	                                        G_CALLBACK (name_owner_changed),
-	                                        self);
-	priv->running = nm_dbus_manager_name_has_owner (priv->dbus_mgr, FIREWALL_DBUS_SERVICE);
-	nm_log_dbg (LOGD_FIREWALL, "firewall %s running", priv->running ? "is" : "is not" );
-
-	bus = nm_dbus_manager_get_connection (priv->dbus_mgr);
-	priv->proxy = dbus_g_proxy_new_for_name (bus,
-	                                         FIREWALL_DBUS_SERVICE,
-	                                         FIREWALL_DBUS_PATH,
-	                                         FIREWALL_DBUS_INTERFACE_ZONE);
+
+	priv->pending_calls = g_hash_table_new (g_direct_hash, g_direct_equal);
 }
 
 static void
-set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
+constructed (GObject *object)
 {
-	G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+	NMFirewallManager *self = (NMFirewallManager *) object;
+	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
+	gs_free char *owner = NULL;
+	gs_free_error GError *error = 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,
+	                                             NULL,
+	                                             FIREWALL_DBUS_SERVICE,
+	                                             FIREWALL_DBUS_PATH,
+	                                             FIREWALL_DBUS_INTERFACE_ZONE,
+	                                             NULL, &error);
+        if (priv->proxy) {
+		g_signal_connect (priv->proxy, "notify::g-name-owner",
+				  G_CALLBACK (name_owner_changed), self);
+		owner = g_dbus_proxy_get_name_owner (priv->proxy);
+		priv->running = (owner != NULL);
+        } else {
+                _LOGW (NULL, "could not connect to system D-Bus (%s)", error->message);
+	}
+
+	_LOGD (NULL, "firewall constructed (%srunning)", priv->running ? "" : "not");
 }
 
 static void
@@ -382,14 +485,15 @@ get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
 static void
 dispose (GObject *object)
 {
-	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (object);
-
-	g_assert (priv->pending_calls == NULL);
+	NMFirewallManager *self = NM_FIREWALL_MANAGER (object);
+	NMFirewallManagerPrivate *priv = NM_FIREWALL_MANAGER_GET_PRIVATE (self);
 
-	if (priv->dbus_mgr) {
-		g_signal_handler_disconnect (priv->dbus_mgr, priv->name_owner_id);
-		priv->name_owner_id = 0;
-		g_clear_object (&priv->dbus_mgr);
+	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);
@@ -405,25 +509,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);
 
 }