diff options
Diffstat (limited to 'src/nm-dbus-manager.c')
| -rw-r--r-- | src/nm-dbus-manager.c | 2715 |
1 files changed, 1348 insertions, 1367 deletions
diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c index 9849656d..00cb6a9f 100644 --- a/src/nm-dbus-manager.c +++ b/src/nm-dbus-manager.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2006 - 2013 Red Hat, Inc. * Copyright (C) 2006 - 2008 Novell, Inc. @@ -31,653 +31,648 @@ /*****************************************************************************/ typedef struct { - CList caller_info_lst; - gulong uid; - gulong pid; - gint64 uid_checked_at; - gint64 pid_checked_at; - bool uid_valid:1; - bool pid_valid:1; - char sender[0]; + CList caller_info_lst; + gulong uid; + gulong pid; + gint64 uid_checked_at; + gint64 pid_checked_at; + bool uid_valid : 1; + bool pid_valid : 1; + char sender[0]; } CallerInfo; typedef struct { - GVariant *value; + GVariant *value; } PropertyCacheData; typedef struct { - CList registration_lst; - NMDBusObject *obj; - NMDBusObjectClass *klass; - guint info_idx; - guint registration_id; - PropertyCacheData property_cache[]; + CList registration_lst; + NMDBusObject * obj; + NMDBusObjectClass *klass; + guint info_idx; + guint registration_id; + PropertyCacheData property_cache[]; } RegistrationData; /* we require that @path is the first member of NMDBusManagerData * because _objects_by_path_hash() requires that. */ -G_STATIC_ASSERT (G_STRUCT_OFFSET (struct _NMDBusObjectInternal, path) == 0); +G_STATIC_ASSERT(G_STRUCT_OFFSET(struct _NMDBusObjectInternal, path) == 0); enum { - PRIVATE_CONNECTION_NEW, - PRIVATE_CONNECTION_DISCONNECTED, + PRIVATE_CONNECTION_NEW, + PRIVATE_CONNECTION_DISCONNECTED, - LAST_SIGNAL + LAST_SIGNAL }; static guint signals[LAST_SIGNAL]; typedef struct { - GHashTable *objects_by_path; - CList objects_lst_head; + GHashTable *objects_by_path; + CList objects_lst_head; - CList private_servers_lst_head; + CList private_servers_lst_head; - NMDBusManagerSetPropertyHandler set_property_handler; - gpointer set_property_handler_data; + NMDBusManagerSetPropertyHandler set_property_handler; + gpointer set_property_handler_data; - GDBusConnection *main_dbus_connection; + GDBusConnection *main_dbus_connection; - CList caller_info_lst_head; + CList caller_info_lst_head; - guint objmgr_registration_id; - bool started:1; - bool shutting_down:1; + guint objmgr_registration_id; + bool started : 1; + bool shutting_down : 1; } NMDBusManagerPrivate; struct _NMDBusManager { - GObject parent; - NMDBusManagerPrivate _priv; + GObject parent; + NMDBusManagerPrivate _priv; }; struct _NMDBusManagerClass { - GObjectClass parent; + GObjectClass parent; }; G_DEFINE_TYPE(NMDBusManager, nm_dbus_manager, G_TYPE_OBJECT) -#define NM_DBUS_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMDBusManager, NM_IS_DBUS_MANAGER) +#define NM_DBUS_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMDBusManager, NM_IS_DBUS_MANAGER) /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_CORE -#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "bus-manager", __VA_ARGS__) +#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "bus-manager", __VA_ARGS__) -NM_DEFINE_SINGLETON_GETTER (NMDBusManager, nm_dbus_manager_get, NM_TYPE_DBUS_MANAGER); +NM_DEFINE_SINGLETON_GETTER(NMDBusManager, nm_dbus_manager_get, NM_TYPE_DBUS_MANAGER); /*****************************************************************************/ static const GDBusInterfaceInfo interface_info_objmgr; -static const GDBusSignalInfo signal_info_objmgr_interfaces_added; -static const GDBusSignalInfo signal_info_objmgr_interfaces_removed; -static GVariantBuilder *_obj_collect_properties_all (NMDBusObject *obj, - GVariantBuilder *builder); +static const GDBusSignalInfo signal_info_objmgr_interfaces_added; +static const GDBusSignalInfo signal_info_objmgr_interfaces_removed; +static GVariantBuilder *_obj_collect_properties_all(NMDBusObject *obj, GVariantBuilder *builder); /*****************************************************************************/ static guint -_objects_by_path_hash (gconstpointer user_data) +_objects_by_path_hash(gconstpointer user_data) { - const char *const*p_data = user_data; + const char *const *p_data = user_data; - nm_assert (p_data); - nm_assert (*p_data); - nm_assert ((*p_data)[0] == '/'); + nm_assert(p_data); + nm_assert(*p_data); + nm_assert((*p_data)[0] == '/'); - return nm_hash_str (*p_data); + return nm_hash_str(*p_data); } static gboolean -_objects_by_path_equal (gconstpointer user_data_a, gconstpointer user_data_b) +_objects_by_path_equal(gconstpointer user_data_a, gconstpointer user_data_b) { - const char *const*p_data_a = user_data_a; - const char *const*p_data_b = user_data_b; + const char *const *p_data_a = user_data_a; + const char *const *p_data_b = user_data_b; - nm_assert (p_data_a); - nm_assert (*p_data_a); - nm_assert ((*p_data_a)[0] == '/'); - nm_assert (p_data_b); - nm_assert (*p_data_b); - nm_assert ((*p_data_b)[0] == '/'); + nm_assert(p_data_a); + nm_assert(*p_data_a); + nm_assert((*p_data_a)[0] == '/'); + nm_assert(p_data_b); + nm_assert(*p_data_b); + nm_assert((*p_data_b)[0] == '/'); - return nm_streq (*p_data_a, *p_data_b); + return nm_streq(*p_data_a, *p_data_b); } /*****************************************************************************/ typedef struct { - CList private_servers_lst; - - const char *tag; - GQuark detail; - char *address; - GDBusServer *server; - - /* With peer bus connections, we'll get a new connection for each - * client. For each connection we create an ObjectManager for - * that connection to handle exporting our objects. - * - * Note that even for connections that don't export any objects - * we'll still create GDBusObjectManager since that's where we store - * the pointer to the GDBusConnection. - */ - CList object_mgr_lst_head; - - NMDBusManager *manager; + CList private_servers_lst; + + const char * tag; + GQuark detail; + char * address; + GDBusServer *server; + + /* With peer bus connections, we'll get a new connection for each + * client. For each connection we create an ObjectManager for + * that connection to handle exporting our objects. + * + * Note that even for connections that don't export any objects + * we'll still create GDBusObjectManager since that's where we store + * the pointer to the GDBusConnection. + */ + CList object_mgr_lst_head; + + NMDBusManager *manager; } PrivateServer; typedef struct { - CList object_mgr_lst; - GDBusObjectManagerServer *manager; - char *fake_sender; + CList object_mgr_lst; + GDBusObjectManagerServer *manager; + char * fake_sender; } ObjectMgrData; typedef struct { - GDBusConnection *connection; - PrivateServer *server; - gboolean remote_peer_vanished; + GDBusConnection *connection; + PrivateServer * server; + gboolean remote_peer_vanished; } CloseConnectionInfo; /*****************************************************************************/ static void -_object_mgr_data_free (ObjectMgrData *obj_mgr_data) +_object_mgr_data_free(ObjectMgrData *obj_mgr_data) { - GDBusConnection *connection; + GDBusConnection *connection; - c_list_unlink_stale (&obj_mgr_data->object_mgr_lst); + c_list_unlink_stale(&obj_mgr_data->object_mgr_lst); - connection = g_dbus_object_manager_server_get_connection (obj_mgr_data->manager); - if (!g_dbus_connection_is_closed (connection)) - g_dbus_connection_close (connection, NULL, NULL, NULL); - g_dbus_object_manager_server_set_connection (obj_mgr_data->manager, NULL); - g_object_unref (obj_mgr_data->manager); - g_object_unref (connection); + connection = g_dbus_object_manager_server_get_connection(obj_mgr_data->manager); + if (!g_dbus_connection_is_closed(connection)) + g_dbus_connection_close(connection, NULL, NULL, NULL); + g_dbus_object_manager_server_set_connection(obj_mgr_data->manager, NULL); + g_object_unref(obj_mgr_data->manager); + g_object_unref(connection); - g_free (obj_mgr_data->fake_sender); + g_free(obj_mgr_data->fake_sender); - g_slice_free (ObjectMgrData, obj_mgr_data); + g_slice_free(ObjectMgrData, obj_mgr_data); } /*****************************************************************************/ static gboolean -close_connection_in_idle (gpointer user_data) +close_connection_in_idle(gpointer user_data) { - CloseConnectionInfo *info = user_data; - PrivateServer *server = info->server; - ObjectMgrData *obj_mgr_data, *obj_mgr_data_safe; - - /* Emit this for the manager */ - g_signal_emit (server->manager, - signals[PRIVATE_CONNECTION_DISCONNECTED], - server->detail, - info->connection); - - /* FIXME: there's a bug (754730) in GLib for which the connection - * is marked as closed when the remote peer vanishes but its - * resources are not cleaned up. Work around it by explicitly - * closing the connection in that case. */ - if (info->remote_peer_vanished) - g_dbus_connection_close (info->connection, NULL, NULL, NULL); - - c_list_for_each_entry_safe (obj_mgr_data, obj_mgr_data_safe, &server->object_mgr_lst_head, object_mgr_lst) { - gs_unref_object GDBusConnection *connection = NULL; - - connection = g_dbus_object_manager_server_get_connection (obj_mgr_data->manager); - if (connection == info->connection) { - _object_mgr_data_free (obj_mgr_data); - break; - } - } - - g_object_unref (server->manager); - g_slice_free (CloseConnectionInfo, info); - - return G_SOURCE_REMOVE; + CloseConnectionInfo *info = user_data; + PrivateServer * server = info->server; + ObjectMgrData * obj_mgr_data, *obj_mgr_data_safe; + + /* Emit this for the manager */ + g_signal_emit(server->manager, + signals[PRIVATE_CONNECTION_DISCONNECTED], + server->detail, + info->connection); + + /* FIXME: there's a bug (754730) in GLib for which the connection + * is marked as closed when the remote peer vanishes but its + * resources are not cleaned up. Work around it by explicitly + * closing the connection in that case. */ + if (info->remote_peer_vanished) + g_dbus_connection_close(info->connection, NULL, NULL, NULL); + + c_list_for_each_entry_safe (obj_mgr_data, + obj_mgr_data_safe, + &server->object_mgr_lst_head, + object_mgr_lst) { + gs_unref_object GDBusConnection *connection = NULL; + + connection = g_dbus_object_manager_server_get_connection(obj_mgr_data->manager); + if (connection == info->connection) { + _object_mgr_data_free(obj_mgr_data); + break; + } + } + + g_object_unref(server->manager); + g_slice_free(CloseConnectionInfo, info); + + return G_SOURCE_REMOVE; } static void -private_server_closed_connection (GDBusConnection *conn, - gboolean remote_peer_vanished, - GError *error, - gpointer user_data) +private_server_closed_connection(GDBusConnection *conn, + gboolean remote_peer_vanished, + GError * error, + gpointer user_data) { - PrivateServer *s = user_data; - CloseConnectionInfo *info; + PrivateServer * s = user_data; + CloseConnectionInfo *info; - /* Clean up after the connection */ - _LOGD ("(%s) closed connection "NM_HASH_OBFUSCATE_PTR_FMT" on private socket", - s->tag, - NM_HASH_OBFUSCATE_PTR (conn)); + /* Clean up after the connection */ + _LOGD("(%s) closed connection " NM_HASH_OBFUSCATE_PTR_FMT " on private socket", + s->tag, + NM_HASH_OBFUSCATE_PTR(conn)); - info = g_slice_new0 (CloseConnectionInfo); - info->connection = conn; - info->server = s; - info->remote_peer_vanished = remote_peer_vanished; + info = g_slice_new0(CloseConnectionInfo); + info->connection = conn; + info->server = s; + info->remote_peer_vanished = remote_peer_vanished; - g_object_ref (s->manager); + g_object_ref(s->manager); - /* Delay the close of connection to ensure that D-Bus signals - * are handled */ - g_idle_add (close_connection_in_idle, info); + /* Delay the close of connection to ensure that D-Bus signals + * are handled */ + g_idle_add(close_connection_in_idle, info); } static gboolean -private_server_new_connection (GDBusServer *server, - GDBusConnection *conn, - gpointer user_data) +private_server_new_connection(GDBusServer *server, GDBusConnection *conn, gpointer user_data) { - PrivateServer *s = user_data; - ObjectMgrData *obj_mgr_data; - static guint32 counter = 0; - GDBusObjectManagerServer *manager; - char *sender; - - g_signal_connect (conn, "closed", G_CALLBACK (private_server_closed_connection), s); - - /* Fake a sender since private connections don't have one */ - sender = g_strdup_printf ("x:y:%d", counter++); - - manager = g_dbus_object_manager_server_new (OBJECT_MANAGER_SERVER_BASE_PATH); - g_dbus_object_manager_server_set_connection (manager, conn); - - obj_mgr_data = g_slice_new (ObjectMgrData); - obj_mgr_data->manager = manager; - obj_mgr_data->fake_sender = sender; - c_list_link_tail (&s->object_mgr_lst_head, &obj_mgr_data->object_mgr_lst); - - _LOGD ("(%s) accepted connection "NM_HASH_OBFUSCATE_PTR_FMT" on private socket", - s->tag, - NM_HASH_OBFUSCATE_PTR (conn)); - - /* Emit this for the manager. - * - * It is essential to do this from the "new-connection" signal handler, as - * at that point no messages from the connection are yet processed - * (which avoids races with registering objects). */ - g_signal_emit (s->manager, - signals[PRIVATE_CONNECTION_NEW], - s->detail, - conn, - manager); - return TRUE; + PrivateServer * s = user_data; + ObjectMgrData * obj_mgr_data; + static guint32 counter = 0; + GDBusObjectManagerServer *manager; + char * sender; + + g_signal_connect(conn, "closed", G_CALLBACK(private_server_closed_connection), s); + + /* Fake a sender since private connections don't have one */ + sender = g_strdup_printf("x:y:%d", counter++); + + manager = g_dbus_object_manager_server_new(OBJECT_MANAGER_SERVER_BASE_PATH); + g_dbus_object_manager_server_set_connection(manager, conn); + + obj_mgr_data = g_slice_new(ObjectMgrData); + obj_mgr_data->manager = manager; + obj_mgr_data->fake_sender = sender; + c_list_link_tail(&s->object_mgr_lst_head, &obj_mgr_data->object_mgr_lst); + + _LOGD("(%s) accepted connection " NM_HASH_OBFUSCATE_PTR_FMT " on private socket", + s->tag, + NM_HASH_OBFUSCATE_PTR(conn)); + + /* Emit this for the manager. + * + * It is essential to do this from the "new-connection" signal handler, as + * at that point no messages from the connection are yet processed + * (which avoids races with registering objects). */ + g_signal_emit(s->manager, signals[PRIVATE_CONNECTION_NEW], s->detail, conn, manager); + return TRUE; } static gboolean -private_server_authorize (GDBusAuthObserver *observer, - GIOStream *stream, - GCredentials *credentials, - gpointer user_data) +private_server_authorize(GDBusAuthObserver *observer, + GIOStream * stream, + GCredentials * credentials, + gpointer user_data) { - return g_credentials_get_unix_user (credentials, NULL) == 0; + return g_credentials_get_unix_user(credentials, NULL) == 0; } static gboolean -private_server_allow_mechanism (GDBusAuthObserver *observer, - const char *mechanism, - gpointer user_data) +private_server_allow_mechanism(GDBusAuthObserver *observer, + const char * mechanism, + gpointer user_data) { - return NM_IN_STRSET (mechanism, "EXTERNAL"); + return NM_IN_STRSET(mechanism, "EXTERNAL"); } static void -private_server_free (gpointer ptr) +private_server_free(gpointer ptr) { - PrivateServer *s = ptr; - ObjectMgrData *obj_mgr_data, *obj_mgr_data_safe; + PrivateServer *s = ptr; + ObjectMgrData *obj_mgr_data, *obj_mgr_data_safe; - c_list_unlink_stale (&s->private_servers_lst); + c_list_unlink_stale(&s->private_servers_lst); - unlink (s->address); - g_free (s->address); + unlink(s->address); + g_free(s->address); - c_list_for_each_entry_safe (obj_mgr_data, obj_mgr_data_safe, &s->object_mgr_lst_head, object_mgr_lst) - _object_mgr_data_free (obj_mgr_data); + c_list_for_each_entry_safe (obj_mgr_data, + obj_mgr_data_safe, + &s->object_mgr_lst_head, + object_mgr_lst) + _object_mgr_data_free(obj_mgr_data); - g_dbus_server_stop (s->server); + g_dbus_server_stop(s->server); - g_signal_handlers_disconnect_by_func (s->server, G_CALLBACK (private_server_new_connection), s); + g_signal_handlers_disconnect_by_func(s->server, G_CALLBACK(private_server_new_connection), s); - g_object_unref (s->server); + g_object_unref(s->server); - g_slice_free (PrivateServer, s); + g_slice_free(PrivateServer, s); } void -nm_dbus_manager_private_server_register (NMDBusManager *self, - const char *path, - const char *tag) +nm_dbus_manager_private_server_register(NMDBusManager *self, const char *path, const char *tag) { - NMDBusManagerPrivate *priv; - PrivateServer *s; - gs_unref_object GDBusAuthObserver *auth_observer = NULL; - GDBusServer *server; - GError *error = NULL; - gs_free char *address = NULL; - gs_free char *guid = NULL; - - g_return_if_fail (NM_IS_DBUS_MANAGER (self)); - g_return_if_fail (path); - g_return_if_fail (tag); - - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - /* Only one instance per tag; but don't warn */ - c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { - if (nm_streq0 (tag, s->tag)) - return; - } - - unlink (path); - address = g_strdup_printf ("unix:path=%s", path); - - _LOGD ("(%s) creating private socket %s", tag, address); - - guid = g_dbus_generate_guid (); - auth_observer = g_dbus_auth_observer_new (); - g_signal_connect (auth_observer, "authorize-authenticated-peer", - G_CALLBACK (private_server_authorize), NULL); - g_signal_connect (auth_observer, "allow-mechanism", - G_CALLBACK (private_server_allow_mechanism), NULL); - server = g_dbus_server_new_sync (address, - G_DBUS_SERVER_FLAGS_NONE, - guid, - auth_observer, - NULL, &error); - - if (!server) { - _LOGW ("(%s) failed to set up private socket %s: %s", - tag, address, error->message); - g_error_free (error); - return; - } - - s = g_slice_new0 (PrivateServer); - s->address = g_steal_pointer (&address); - s->server = server; - g_signal_connect (server, "new-connection", - G_CALLBACK (private_server_new_connection), s); - - c_list_init (&s->object_mgr_lst_head); - - s->manager = self; - s->detail = g_quark_from_string (tag); - s->tag = g_quark_to_string (s->detail); - - c_list_link_tail (&priv->private_servers_lst_head, &s->private_servers_lst); - - g_dbus_server_start (server); + NMDBusManagerPrivate *priv; + PrivateServer * s; + gs_unref_object GDBusAuthObserver *auth_observer = NULL; + GDBusServer * server; + GError * error = NULL; + gs_free char * address = NULL; + gs_free char * guid = NULL; + + g_return_if_fail(NM_IS_DBUS_MANAGER(self)); + g_return_if_fail(path); + g_return_if_fail(tag); + + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + + /* Only one instance per tag; but don't warn */ + c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { + if (nm_streq0(tag, s->tag)) + return; + } + + unlink(path); + address = g_strdup_printf("unix:path=%s", path); + + _LOGD("(%s) creating private socket %s", tag, address); + + guid = g_dbus_generate_guid(); + auth_observer = g_dbus_auth_observer_new(); + g_signal_connect(auth_observer, + "authorize-authenticated-peer", + G_CALLBACK(private_server_authorize), + NULL); + g_signal_connect(auth_observer, + "allow-mechanism", + G_CALLBACK(private_server_allow_mechanism), + NULL); + server = g_dbus_server_new_sync(address, + G_DBUS_SERVER_FLAGS_NONE, + guid, + auth_observer, + NULL, + &error); + + if (!server) { + _LOGW("(%s) failed to set up private socket %s: %s", tag, address, error->message); + g_error_free(error); + return; + } + + s = g_slice_new0(PrivateServer); + s->address = g_steal_pointer(&address); + s->server = server; + g_signal_connect(server, "new-connection", G_CALLBACK(private_server_new_connection), s); + + c_list_init(&s->object_mgr_lst_head); + + s->manager = self; + s->detail = g_quark_from_string(tag); + s->tag = g_quark_to_string(s->detail); + + c_list_link_tail(&priv->private_servers_lst_head, &s->private_servers_lst); + + g_dbus_server_start(server); } static const char * -private_server_get_connection_owner (PrivateServer *s, GDBusConnection *connection) +private_server_get_connection_owner(PrivateServer *s, GDBusConnection *connection) { - ObjectMgrData *obj_mgr_data; + ObjectMgrData *obj_mgr_data; - nm_assert (s); - nm_assert (G_IS_DBUS_CONNECTION (connection)); + nm_assert(s); + nm_assert(G_IS_DBUS_CONNECTION(connection)); - c_list_for_each_entry (obj_mgr_data, &s->object_mgr_lst_head, object_mgr_lst) { - gs_unref_object GDBusConnection *c = NULL; + c_list_for_each_entry (obj_mgr_data, &s->object_mgr_lst_head, object_mgr_lst) { + gs_unref_object GDBusConnection *c = NULL; - c = g_dbus_object_manager_server_get_connection (obj_mgr_data->manager); - if (c == connection) - return obj_mgr_data->fake_sender; - } - return NULL; + c = g_dbus_object_manager_server_get_connection(obj_mgr_data->manager); + if (c == connection) + return obj_mgr_data->fake_sender; + } + return NULL; } static GDBusConnection * -private_server_get_connection_by_owner (PrivateServer *s, const char *owner) +private_server_get_connection_by_owner(PrivateServer *s, const char *owner) { - ObjectMgrData *obj_mgr_data; + ObjectMgrData *obj_mgr_data; - nm_assert (s); - nm_assert (owner); + nm_assert(s); + nm_assert(owner); - c_list_for_each_entry (obj_mgr_data, &s->object_mgr_lst_head, object_mgr_lst) { - if (nm_streq (owner, obj_mgr_data->fake_sender)) - return g_dbus_object_manager_server_get_connection (obj_mgr_data->manager); - } - return NULL; + c_list_for_each_entry (obj_mgr_data, &s->object_mgr_lst_head, object_mgr_lst) { + if (nm_streq(owner, obj_mgr_data->fake_sender)) + return g_dbus_object_manager_server_get_connection(obj_mgr_data->manager); + } + return NULL; } /*****************************************************************************/ static void -_caller_info_free (CallerInfo *caller_info) +_caller_info_free(CallerInfo *caller_info) { - c_list_unlink_stale (&caller_info->caller_info_lst); - g_free (caller_info); + c_list_unlink_stale(&caller_info->caller_info_lst); + g_free(caller_info); } static gboolean -_bus_get_unix_pid (NMDBusManager *self, - const char *sender, - gulong *out_pid) +_bus_get_unix_pid(NMDBusManager *self, const char *sender, gulong *out_pid) { - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - guint32 unix_pid = G_MAXUINT32; - gs_unref_variant GVariant *ret = NULL; - - if (!priv->main_dbus_connection) - return FALSE; - - ret = g_dbus_connection_call_sync (priv->main_dbus_connection, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixProcessID", - g_variant_new ("(s)", sender), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, - 2000, - NULL, - NULL); - if (!ret) - return FALSE; - - g_variant_get (ret, "(u)", &unix_pid); - - *out_pid = (gulong) unix_pid; - return TRUE; + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + guint32 unix_pid = G_MAXUINT32; + gs_unref_variant GVariant *ret = NULL; + + if (!priv->main_dbus_connection) + return FALSE; + + ret = g_dbus_connection_call_sync(priv->main_dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetConnectionUnixProcessID", + g_variant_new("(s)", sender), + G_VARIANT_TYPE("(u)"), + G_DBUS_CALL_FLAGS_NONE, + 2000, + NULL, + NULL); + if (!ret) + return FALSE; + + g_variant_get(ret, "(u)", &unix_pid); + + *out_pid = (gulong) unix_pid; + return TRUE; } static gboolean -_bus_get_unix_user (NMDBusManager *self, - const char *sender, - gulong *out_user) +_bus_get_unix_user(NMDBusManager *self, const char *sender, gulong *out_user) { - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - guint32 unix_uid = G_MAXUINT32; - gs_unref_variant GVariant *ret = NULL; - - if (!priv->main_dbus_connection) - return FALSE; - - ret = g_dbus_connection_call_sync (priv->main_dbus_connection, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetConnectionUnixUser", - g_variant_new ("(s)", sender), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, - 2000, - NULL, - NULL); - if (!ret) - return FALSE; - - g_variant_get (ret, "(u)", &unix_uid); - - *out_user = (gulong) unix_uid; - return TRUE; + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + guint32 unix_uid = G_MAXUINT32; + gs_unref_variant GVariant *ret = NULL; + + if (!priv->main_dbus_connection) + return FALSE; + + ret = g_dbus_connection_call_sync(priv->main_dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetConnectionUnixUser", + g_variant_new("(s)", sender), + G_VARIANT_TYPE("(u)"), + G_DBUS_CALL_FLAGS_NONE, + 2000, + NULL, + NULL); + if (!ret) + return FALSE; + + g_variant_get(ret, "(u)", &unix_uid); + + *out_user = (gulong) unix_uid; + return TRUE; } static const CallerInfo * -_get_caller_info_ensure (NMDBusManager *self, - const char *sender, - gboolean ensure_uid, - gboolean ensure_pid) +_get_caller_info_ensure(NMDBusManager *self, + const char * sender, + gboolean ensure_uid, + gboolean ensure_pid) { - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - CallerInfo *caller_info; - CallerInfo *ci; - gint64 now_ns; - gsize num; - -#define CALLER_INFO_MAX_AGE (NM_UTILS_NSEC_PER_SEC * 1) - - /* Linear search the cache for the sender. - * - * The number of cached caller-infos is limited. Hence, it's O(1) and - * the list is reasonably short. - * Also, the entire caching assumes that we repeatedly ask for the - * same sender. That means, we expect to find the right caller info - * at the front of the list. */ - num = 1; - caller_info = NULL; - c_list_for_each_entry (ci, &priv->caller_info_lst_head, caller_info_lst) { - if (nm_streq (sender, ci->sender)) { - caller_info = ci; - break; - } - num++; - } - - if (caller_info) - nm_c_list_move_front (&priv->caller_info_lst_head, &caller_info->caller_info_lst); - else { - gsize l = strlen (sender) + 1; - - caller_info = g_malloc (sizeof (CallerInfo) + l); - *caller_info = (CallerInfo) { - .uid_checked_at = - CALLER_INFO_MAX_AGE, - .pid_checked_at = - CALLER_INFO_MAX_AGE, - }; - memcpy (caller_info->sender, sender, l); - c_list_link_front (&priv->caller_info_lst_head, &caller_info->caller_info_lst); - - /* only cache the last few entries. */ - while (TRUE) { - nm_assert (num > 0 && num == c_list_length (&priv->caller_info_lst_head)); - if (num-- <= 5) - break; - _caller_info_free (c_list_last_entry (&priv->caller_info_lst_head, CallerInfo, caller_info_lst)); - } - } - - now_ns = nm_utils_get_monotonic_timestamp_nsec (); - - if ( ensure_uid - && (now_ns - caller_info->uid_checked_at) > CALLER_INFO_MAX_AGE) { - caller_info->uid_checked_at = now_ns; - if (!(caller_info->uid_valid = _bus_get_unix_user (self, sender, &caller_info->uid))) - caller_info->uid = G_MAXULONG; - } - - if ( ensure_pid - && (now_ns - caller_info->pid_checked_at) > CALLER_INFO_MAX_AGE) { - caller_info->pid_checked_at = now_ns; - if (!(caller_info->pid_valid = _bus_get_unix_pid (self, sender, &caller_info->pid))) - caller_info->pid = G_MAXULONG; - } - - return caller_info; + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + CallerInfo * caller_info; + CallerInfo * ci; + gint64 now_ns; + gsize num; + +#define CALLER_INFO_MAX_AGE (NM_UTILS_NSEC_PER_SEC * 1) + + /* Linear search the cache for the sender. + * + * The number of cached caller-infos is limited. Hence, it's O(1) and + * the list is reasonably short. + * Also, the entire caching assumes that we repeatedly ask for the + * same sender. That means, we expect to find the right caller info + * at the front of the list. */ + num = 1; + caller_info = NULL; + c_list_for_each_entry (ci, &priv->caller_info_lst_head, caller_info_lst) { + if (nm_streq(sender, ci->sender)) { + caller_info = ci; + break; + } + num++; + } + + if (caller_info) + nm_c_list_move_front(&priv->caller_info_lst_head, &caller_info->caller_info_lst); + else { + gsize l = strlen(sender) + 1; + + caller_info = g_malloc(sizeof(CallerInfo) + l); + *caller_info = (CallerInfo){ + .uid_checked_at = -CALLER_INFO_MAX_AGE, + .pid_checked_at = -CALLER_INFO_MAX_AGE, + }; + memcpy(caller_info->sender, sender, l); + c_list_link_front(&priv->caller_info_lst_head, &caller_info->caller_info_lst); + + /* only cache the last few entries. */ + while (TRUE) { + nm_assert(num > 0 && num == c_list_length(&priv->caller_info_lst_head)); + if (num-- <= 5) + break; + _caller_info_free( + c_list_last_entry(&priv->caller_info_lst_head, CallerInfo, caller_info_lst)); + } + } + + now_ns = nm_utils_get_monotonic_timestamp_nsec(); + + if (ensure_uid && (now_ns - caller_info->uid_checked_at) > CALLER_INFO_MAX_AGE) { + caller_info->uid_checked_at = now_ns; + if (!(caller_info->uid_valid = _bus_get_unix_user(self, sender, &caller_info->uid))) + caller_info->uid = G_MAXULONG; + } + + if (ensure_pid && (now_ns - caller_info->pid_checked_at) > CALLER_INFO_MAX_AGE) { + caller_info->pid_checked_at = now_ns; + if (!(caller_info->pid_valid = _bus_get_unix_pid(self, sender, &caller_info->pid))) + caller_info->pid = G_MAXULONG; + } + + return caller_info; } static gboolean -_get_caller_info (NMDBusManager *self, - GDBusMethodInvocation *context, - GDBusConnection *connection, - GDBusMessage *message, - const char **out_sender, - gulong *out_uid, - gulong *out_pid) +_get_caller_info(NMDBusManager * self, + GDBusMethodInvocation *context, + GDBusConnection * connection, + GDBusMessage * message, + const char ** out_sender, + gulong * out_uid, + gulong * out_pid) { - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - const CallerInfo *caller_info; - const char *sender; - - if (context) { - nm_assert (G_IS_DBUS_METHOD_INVOCATION (context)); - connection = g_dbus_method_invocation_get_connection (context); - - /* only bus connections will have a sender */ - sender = g_dbus_method_invocation_get_sender (context); - } else { - nm_assert (G_IS_DBUS_MESSAGE (message)); - sender = g_dbus_message_get_sender (message); - } - nm_assert (G_IS_DBUS_CONNECTION (connection)); - - if (!sender) { - PrivateServer *s; - - /* Might be a private connection, for which we fake a sender */ - c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { - sender = private_server_get_connection_owner (s, connection); - if (sender) { - NM_SET_OUT (out_uid, 0); - NM_SET_OUT (out_sender, sender); - if (out_pid) { - GCredentials *creds; - - creds = g_dbus_connection_get_peer_credentials (connection); - if (creds) { - pid_t pid; - - pid = g_credentials_get_unix_pid (creds, NULL); - if (pid == -1) - *out_pid = G_MAXULONG; - else - *out_pid = pid; - } else - *out_pid = G_MAXULONG; - } - return TRUE; - } - } - NM_SET_OUT (out_sender, NULL); - NM_SET_OUT (out_uid, G_MAXULONG); - NM_SET_OUT (out_pid, G_MAXULONG); - return FALSE; - } - - caller_info = _get_caller_info_ensure (self, sender, !!out_uid, !!out_pid); - - NM_SET_OUT (out_sender, caller_info->sender); - NM_SET_OUT (out_uid, caller_info->uid); - NM_SET_OUT (out_pid, caller_info->pid); - - if (out_uid && !caller_info->uid_valid) - return FALSE; - if (out_pid && !caller_info->pid_valid) - return FALSE; - return TRUE; + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + const CallerInfo * caller_info; + const char * sender; + + if (context) { + nm_assert(G_IS_DBUS_METHOD_INVOCATION(context)); + connection = g_dbus_method_invocation_get_connection(context); + + /* only bus connections will have a sender */ + sender = g_dbus_method_invocation_get_sender(context); + } else { + nm_assert(G_IS_DBUS_MESSAGE(message)); + sender = g_dbus_message_get_sender(message); + } + nm_assert(G_IS_DBUS_CONNECTION(connection)); + + if (!sender) { + PrivateServer *s; + + /* Might be a private connection, for which we fake a sender */ + c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { + sender = private_server_get_connection_owner(s, connection); + if (sender) { + NM_SET_OUT(out_uid, 0); + NM_SET_OUT(out_sender, sender); + if (out_pid) { + GCredentials *creds; + + creds = g_dbus_connection_get_peer_credentials(connection); + if (creds) { + pid_t pid; + + pid = g_credentials_get_unix_pid(creds, NULL); + if (pid == -1) + *out_pid = G_MAXULONG; + else + *out_pid = pid; + } else + *out_pid = G_MAXULONG; + } + return TRUE; + } + } + NM_SET_OUT(out_sender, NULL); + NM_SET_OUT(out_uid, G_MAXULONG); + NM_SET_OUT(out_pid, G_MAXULONG); + return FALSE; + } + + caller_info = _get_caller_info_ensure(self, sender, !!out_uid, !!out_pid); + + NM_SET_OUT(out_sender, caller_info->sender); + NM_SET_OUT(out_uid, caller_info->uid); + NM_SET_OUT(out_pid, caller_info->pid); + + if (out_uid && !caller_info->uid_valid) + return FALSE; + if (out_pid && !caller_info->pid_valid) + return FALSE; + return TRUE; } gboolean -nm_dbus_manager_get_caller_info (NMDBusManager *self, - GDBusMethodInvocation *context, - const char **out_sender, - gulong *out_uid, - gulong *out_pid) +nm_dbus_manager_get_caller_info(NMDBusManager * self, + GDBusMethodInvocation *context, + const char ** out_sender, + gulong * out_uid, + gulong * out_pid) { - return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid, out_pid); + return _get_caller_info(self, context, NULL, NULL, out_sender, out_uid, out_pid); } gboolean -nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, - GDBusConnection *connection, - GDBusMessage *message, - const char **out_sender, - gulong *out_uid, - gulong *out_pid) +nm_dbus_manager_get_caller_info_from_message(NMDBusManager * self, + GDBusConnection *connection, + GDBusMessage * message, + const char ** out_sender, + gulong * out_uid, + gulong * out_pid) { - return _get_caller_info (self, NULL, connection, message, out_sender, out_uid, out_pid); + return _get_caller_info(self, NULL, connection, message, out_sender, out_uid, out_pid); } /** @@ -697,1043 +692,1029 @@ nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, * Returns: %TRUE if the check succeeded, %FALSE otherwise */ gboolean -nm_dbus_manager_ensure_uid (NMDBusManager *self, - GDBusMethodInvocation *context, - gulong uid, - GQuark error_domain, - int error_code) +nm_dbus_manager_ensure_uid(NMDBusManager * self, + GDBusMethodInvocation *context, + gulong uid, + GQuark error_domain, + int error_code) { - gulong caller_uid; - GError *error = NULL; - - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), FALSE); - g_return_val_if_fail (G_IS_DBUS_METHOD_INVOCATION (context), FALSE); - - if (!nm_dbus_manager_get_caller_info (self, context, NULL, &caller_uid, NULL)) { - error = g_error_new_literal (error_domain, - error_code, - "Unable to determine request UID."); - g_dbus_method_invocation_take_error (context, error); - return FALSE; - } - - if (uid != G_MAXULONG && caller_uid != uid) { - error = g_error_new_literal (error_domain, - error_code, - "Permission denied"); - g_dbus_method_invocation_take_error (context, error); - return FALSE; - } - - return TRUE; + gulong caller_uid; + GError *error = NULL; + + g_return_val_if_fail(NM_IS_DBUS_MANAGER(self), FALSE); + g_return_val_if_fail(G_IS_DBUS_METHOD_INVOCATION(context), FALSE); + + if (!nm_dbus_manager_get_caller_info(self, context, NULL, &caller_uid, NULL)) { + error = g_error_new_literal(error_domain, error_code, "Unable to determine request UID."); + g_dbus_method_invocation_take_error(context, error); + return FALSE; + } + + if (uid != G_MAXULONG && caller_uid != uid) { + error = g_error_new_literal(error_domain, error_code, "Permission denied"); + g_dbus_method_invocation_take_error(context, error); + return FALSE; + } + + return TRUE; } gboolean -nm_dbus_manager_get_unix_user (NMDBusManager *self, - const char *sender, - gulong *out_uid) +nm_dbus_manager_get_unix_user(NMDBusManager *self, const char *sender, gulong *out_uid) { - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - const CallerInfo *caller_info; - PrivateServer *s; - - g_return_val_if_fail (sender != NULL, FALSE); - g_return_val_if_fail (out_uid != NULL, FALSE); - - /* Check if it's a private connection sender, which we fake */ - c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { - gs_unref_object GDBusConnection *connection = NULL; - - connection = private_server_get_connection_by_owner (s, sender); - if (connection) { - *out_uid = 0; - return TRUE; - } - } - - /* Otherwise, a bus connection */ - caller_info = _get_caller_info_ensure (self, sender, TRUE, FALSE); - *out_uid = caller_info->uid; - if (!caller_info->uid_valid) { - _LOGW ("failed to get unix user for dbus sender '%s'", sender); - return FALSE; - } - return TRUE; + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + const CallerInfo * caller_info; + PrivateServer * s; + + g_return_val_if_fail(sender != NULL, FALSE); + g_return_val_if_fail(out_uid != NULL, FALSE); + + /* Check if it's a private connection sender, which we fake */ + c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { + gs_unref_object GDBusConnection *connection = NULL; + + connection = private_server_get_connection_by_owner(s, sender); + if (connection) { + *out_uid = 0; + return TRUE; + } + } + + /* Otherwise, a bus connection */ + caller_info = _get_caller_info_ensure(self, sender, TRUE, FALSE); + *out_uid = caller_info->uid; + if (!caller_info->uid_valid) { + _LOGW("failed to get unix user for dbus sender '%s'", sender); + return FALSE; + } + return TRUE; } /*****************************************************************************/ static const NMDBusInterfaceInfoExtended * -_reg_data_get_interface_info (RegistrationData *reg_data) +_reg_data_get_interface_info(RegistrationData *reg_data) { - nm_assert (reg_data); + nm_assert(reg_data); - return reg_data->klass->interface_infos[reg_data->info_idx]; + return reg_data->klass->interface_infos[reg_data->info_idx]; } /*****************************************************************************/ static void -dbus_vtable_method_call (GDBusConnection *connection, - const char *sender, - const char *object_path, - const char *interface_name, - const char *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) +dbus_vtable_method_call(GDBusConnection * connection, + const char * sender, + const char * object_path, + const char * interface_name, + const char * method_name, + GVariant * parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) { - NMDBusManager *self; - NMDBusManagerPrivate *priv; - RegistrationData *reg_data = user_data; - NMDBusObject *obj = reg_data->obj; - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - const NMDBusMethodInfoExtended *method_info = NULL; - gboolean on_same_interface; - - on_same_interface = nm_streq (interface_info->parent.name, interface_name); - - /* handle property setter first... */ - if ( !on_same_interface - && nm_streq (interface_name, DBUS_INTERFACE_PROPERTIES) - && nm_streq (method_name, "Set")) { - const NMDBusPropertyInfoExtended *property_info = NULL; - const char *property_interface; - const char *property_name; - gs_unref_variant GVariant *value = NULL; - - self = nm_dbus_object_get_manager (obj); - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - g_variant_get (parameters, "(&s&sv)", &property_interface, &property_name, &value); - - nm_assert (nm_streq (property_interface, interface_info->parent.name)); - - property_info = (const NMDBusPropertyInfoExtended *) nm_dbus_utils_interface_info_lookup_property (&interface_info->parent, - property_name, - NULL); - if ( !property_info - || !NM_FLAGS_HAS (property_info->parent.flags, G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)) - g_return_if_reached (); - - if (!priv->set_property_handler) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_AUTH_FAILED, - "Cannot authenticate setting property %s", - property_name); - return; - } - - priv->set_property_handler (obj, - interface_info, - property_info, - connection, - sender, - invocation, - value, - priv->set_property_handler_data); - return; - } - - if (on_same_interface) { - method_info = (const NMDBusMethodInfoExtended *) nm_dbus_utils_interface_info_lookup_method (&interface_info->parent, - method_name); - } - if (!method_info) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s", - method_name); - return; - } - - self = nm_dbus_object_get_manager (obj); - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - if ( priv->shutting_down - && !method_info->allow_during_shutdown) { - g_dbus_method_invocation_return_error_literal (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_FAILED, - "NetworkManager is exiting"); - return; - } - - method_info->handle (reg_data->obj, - interface_info, - method_info, - connection, - sender, - invocation, - parameters); + NMDBusManager * self; + NMDBusManagerPrivate * priv; + RegistrationData * reg_data = user_data; + NMDBusObject * obj = reg_data->obj; + const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info(reg_data); + const NMDBusMethodInfoExtended * method_info = NULL; + gboolean on_same_interface; + + on_same_interface = nm_streq(interface_info->parent.name, interface_name); + + /* handle property setter first... */ + if (!on_same_interface && nm_streq(interface_name, DBUS_INTERFACE_PROPERTIES) + && nm_streq(method_name, "Set")) { + const NMDBusPropertyInfoExtended *property_info = NULL; + const char * property_interface; + const char * property_name; + gs_unref_variant GVariant *value = NULL; + + self = nm_dbus_object_get_manager(obj); + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + + g_variant_get(parameters, "(&s&sv)", &property_interface, &property_name, &value); + + nm_assert(nm_streq(property_interface, interface_info->parent.name)); + + property_info = + (const NMDBusPropertyInfoExtended *) nm_dbus_utils_interface_info_lookup_property( + &interface_info->parent, + property_name, + NULL); + if (!property_info + || !NM_FLAGS_HAS(property_info->parent.flags, G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE)) + g_return_if_reached(); + + if (!priv->set_property_handler) { + g_dbus_method_invocation_return_error(invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_AUTH_FAILED, + "Cannot authenticate setting property %s", + property_name); + return; + } + + priv->set_property_handler(obj, + interface_info, + property_info, + connection, + sender, + invocation, + value, + priv->set_property_handler_data); + return; + } + + if (on_same_interface) { + method_info = (const NMDBusMethodInfoExtended *) nm_dbus_utils_interface_info_lookup_method( + &interface_info->parent, + method_name); + } + if (!method_info) { + g_dbus_method_invocation_return_error(invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_UNKNOWN_METHOD, + "Unknown method %s", + method_name); + return; + } + + self = nm_dbus_object_get_manager(obj); + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + if (priv->shutting_down && !method_info->allow_during_shutdown) { + g_dbus_method_invocation_return_error_literal(invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_FAILED, + "NetworkManager is exiting"); + return; + } + + method_info->handle(reg_data->obj, + interface_info, + method_info, + connection, + sender, + invocation, + parameters); } static GVariant * -_obj_get_property (RegistrationData *reg_data, - guint property_idx, - gboolean refetch) +_obj_get_property(RegistrationData *reg_data, guint property_idx, gboolean refetch) { - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - const NMDBusPropertyInfoExtended *property_info; - GVariant *value; - - property_info = (const NMDBusPropertyInfoExtended *) (interface_info->parent.properties[property_idx]); - - if (refetch) - nm_clear_g_variant (®_data->property_cache[property_idx].value); - else { - value = reg_data->property_cache[property_idx].value; - if (value) - goto out; - } - - value = nm_dbus_utils_get_property (G_OBJECT (reg_data->obj), - property_info->parent.signature, - property_info->property_name); - reg_data->property_cache[property_idx].value = value; + const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info(reg_data); + const NMDBusPropertyInfoExtended * property_info; + GVariant * value; + + property_info = + (const NMDBusPropertyInfoExtended *) (interface_info->parent.properties[property_idx]); + + if (refetch) + nm_clear_g_variant(®_data->property_cache[property_idx].value); + else { + value = reg_data->property_cache[property_idx].value; + if (value) + goto out; + } + + value = nm_dbus_utils_get_property(G_OBJECT(reg_data->obj), + property_info->parent.signature, + property_info->property_name); + reg_data->property_cache[property_idx].value = value; out: - return g_variant_ref (value); + return g_variant_ref(value); } static GVariant * -dbus_vtable_get_property (GDBusConnection *connection, - const char *sender, - const char *object_path, - const char *interface_name, - const char *property_name, - GError **error, - gpointer user_data) +dbus_vtable_get_property(GDBusConnection *connection, + const char * sender, + const char * object_path, + const char * interface_name, + const char * property_name, + GError ** error, + gpointer user_data) { - RegistrationData *reg_data = user_data; - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - guint property_idx; + RegistrationData * reg_data = user_data; + const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info(reg_data); + guint property_idx; - if (!nm_dbus_utils_interface_info_lookup_property (&interface_info->parent, - property_name, - &property_idx)) - g_return_val_if_reached (NULL); + if (!nm_dbus_utils_interface_info_lookup_property(&interface_info->parent, + property_name, + &property_idx)) + g_return_val_if_reached(NULL); - return _obj_get_property (reg_data, property_idx, FALSE); + return _obj_get_property(reg_data, property_idx, FALSE); } static const GDBusInterfaceVTable dbus_vtable = { - .method_call = dbus_vtable_method_call, - .get_property = dbus_vtable_get_property, + .method_call = dbus_vtable_method_call, + .get_property = dbus_vtable_get_property, - /* set_property is handled via method_call as well. We need to authenticate - * which requires an asynchronous handler. */ - .set_property = NULL, + /* set_property is handled via method_call as well. We need to authenticate + * which requires an asynchronous handler. */ + .set_property = NULL, }; static void -_obj_register (NMDBusManager *self, - NMDBusObject *obj) +_obj_register(NMDBusManager *self, NMDBusObject *obj) { - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - guint i, k; - guint n_klasses; - GType gtype; - NMDBusObjectClass *klasses[10]; - const NMDBusInterfaceInfoExtended *const*prev_interface_infos = NULL; - GVariantBuilder builder; - - nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); - nm_assert (priv->main_dbus_connection); - nm_assert (priv->objmgr_registration_id != 0); - nm_assert (priv->started); - - n_klasses = 0; - gtype = G_OBJECT_TYPE (obj); - while (gtype != NM_TYPE_DBUS_OBJECT) { - nm_assert (n_klasses < G_N_ELEMENTS (klasses)); - klasses[n_klasses++] = g_type_class_ref (gtype); - gtype = g_type_parent (gtype); - } - - for (k = n_klasses; k > 0; ) { - NMDBusObjectClass *klass = NM_DBUS_OBJECT_CLASS (klasses[--k]); - - if (!klass->interface_infos) - continue; - - if (prev_interface_infos == klass->interface_infos) { - /* derived classes inherrit the interface-infos from the parent class. - * For convenience, we allow the subclass to leave interface-infos untouched, - * but it means we must ignore the parent's interface, because we already - * handled it. - * - * Note that the loop goes from the parent classes to child classes */ - continue; - } - prev_interface_infos = klass->interface_infos; - - for (i = 0; klass->interface_infos[i]; i++) { - const NMDBusInterfaceInfoExtended *interface_info = klass->interface_infos[i]; - RegistrationData *reg_data; - gs_free_error GError *error = NULL; - guint registration_id; - guint prop_len = NM_PTRARRAY_LEN (interface_info->parent.properties); - - reg_data = g_malloc0 (sizeof (RegistrationData) + (sizeof (PropertyCacheData) * prop_len)); - - registration_id = g_dbus_connection_register_object (priv->main_dbus_connection, - obj->internal.path, - NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info->parent), - &dbus_vtable, - reg_data, - NULL, - &error); - if (!registration_id) { - _LOGE ("failure to register object %s: %s", obj->internal.path, error->message); - g_free (reg_data); - continue; - } - - reg_data->obj = obj; - reg_data->klass = g_type_class_ref (G_TYPE_FROM_CLASS (klass)); - reg_data->info_idx = i; - reg_data->registration_id = registration_id; - c_list_link_tail (&obj->internal.registration_lst_head, ®_data->registration_lst); - } - } - - for (k = 0; k < n_klasses; k++) - g_type_class_unref (klasses[k]); - - nm_assert (!c_list_is_empty (&obj->internal.registration_lst_head)); - - /* Currently the interfaces of an object do not changed and strictly depend on the object glib type. - * We don't need more flixibility, and it simplifies the code. Hence, now emit interface-added - * signal for the new object. - * - * Warning: note that if @obj's notify signal is currently blocked via g_object_freeze_notify(), - * we might emit properties with an inconsistent (internal) state. There is no easy solution, - * because we have to emit the signal now, and we don't know what the correct desired state - * of the properties is. - * Another problem is, upon unfreezing the signals, we immediately send PropertiesChanged - * notifications out. Which is a bit odd, as we just export the object. - * - * In general, it's ok to export an object with frozen signals. But you better make sure - * that all properties are in a self-consistent state when exporting the object. */ - g_dbus_connection_emit_signal (priv->main_dbus_connection, - NULL, - OBJECT_MANAGER_SERVER_BASE_PATH, - interface_info_objmgr.name, - signal_info_objmgr_interfaces_added.name, - g_variant_new ("(oa{sa{sv}})", - obj->internal.path, - _obj_collect_properties_all (obj, &builder)), - NULL); + NMDBusManagerPrivate * priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + guint i, k; + guint n_klasses; + GType gtype; + NMDBusObjectClass * klasses[10]; + const NMDBusInterfaceInfoExtended *const *prev_interface_infos = NULL; + GVariantBuilder builder; + + nm_assert(c_list_is_empty(&obj->internal.registration_lst_head)); + nm_assert(priv->main_dbus_connection); + nm_assert(priv->objmgr_registration_id != 0); + nm_assert(priv->started); + + n_klasses = 0; + gtype = G_OBJECT_TYPE(obj); + while (gtype != NM_TYPE_DBUS_OBJECT) { + nm_assert(n_klasses < G_N_ELEMENTS(klasses)); + klasses[n_klasses++] = g_type_class_ref(gtype); + gtype = g_type_parent(gtype); + } + + for (k = n_klasses; k > 0;) { + NMDBusObjectClass *klass = NM_DBUS_OBJECT_CLASS(klasses[--k]); + + if (!klass->interface_infos) + continue; + + if (prev_interface_infos == klass->interface_infos) { + /* derived classes inherrit the interface-infos from the parent class. + * For convenience, we allow the subclass to leave interface-infos untouched, + * but it means we must ignore the parent's interface, because we already + * handled it. + * + * Note that the loop goes from the parent classes to child classes */ + continue; + } + prev_interface_infos = klass->interface_infos; + + for (i = 0; klass->interface_infos[i]; i++) { + const NMDBusInterfaceInfoExtended *interface_info = klass->interface_infos[i]; + RegistrationData * reg_data; + gs_free_error GError *error = NULL; + guint registration_id; + guint prop_len = NM_PTRARRAY_LEN(interface_info->parent.properties); + + reg_data = g_malloc0(sizeof(RegistrationData) + (sizeof(PropertyCacheData) * prop_len)); + + registration_id = g_dbus_connection_register_object( + priv->main_dbus_connection, + obj->internal.path, + NM_UNCONST_PTR(GDBusInterfaceInfo, &interface_info->parent), + &dbus_vtable, + reg_data, + NULL, + &error); + if (!registration_id) { + _LOGE("failure to register object %s: %s", obj->internal.path, error->message); + g_free(reg_data); + continue; + } + + reg_data->obj = obj; + reg_data->klass = g_type_class_ref(G_TYPE_FROM_CLASS(klass)); + reg_data->info_idx = i; + reg_data->registration_id = registration_id; + c_list_link_tail(&obj->internal.registration_lst_head, ®_data->registration_lst); + } + } + + for (k = 0; k < n_klasses; k++) + g_type_class_unref(klasses[k]); + + nm_assert(!c_list_is_empty(&obj->internal.registration_lst_head)); + + /* Currently, the interfaces of an object do not changed and strictly depend on the object glib type. + * We don't need more flexibility, and it simplifies the code. Hence, now emit interface-added + * signal for the new object. + * + * Warning: note that if @obj's notify signal is currently blocked via g_object_freeze_notify(), + * we might emit properties with an inconsistent (internal) state. There is no easy solution, + * because we have to emit the signal now, and we don't know what the correct desired state + * of the properties is. + * Another problem is, upon unfreezing the signals, we immediately send PropertiesChanged + * notifications out. Which is a bit odd, as we just export the object. + * + * In general, it's ok to export an object with frozen signals. But you better make sure + * that all properties are in a self-consistent state when exporting the object. */ + g_dbus_connection_emit_signal(priv->main_dbus_connection, + NULL, + OBJECT_MANAGER_SERVER_BASE_PATH, + interface_info_objmgr.name, + signal_info_objmgr_interfaces_added.name, + g_variant_new("(oa{sa{sv}})", + obj->internal.path, + _obj_collect_properties_all(obj, &builder)), + NULL); } static void -_obj_unregister (NMDBusManager *self, - NMDBusObject *obj) +_obj_unregister(NMDBusManager *self, NMDBusObject *obj) { - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - RegistrationData *reg_data; - GVariantBuilder builder; - - nm_assert (NM_IS_DBUS_OBJECT (obj)); - nm_assert (priv->main_dbus_connection); - nm_assert (priv->objmgr_registration_id != 0); - nm_assert (priv->started); - nm_assert (!c_list_is_empty (&obj->internal.registration_lst_head)); - - g_variant_builder_init (&builder, G_VARIANT_TYPE ("as")); - - while ((reg_data = c_list_last_entry (&obj->internal.registration_lst_head, RegistrationData, registration_lst))) { - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - guint i; - - g_variant_builder_add (&builder, - "s", - interface_info->parent.name); - c_list_unlink_stale (®_data->registration_lst); - if (!g_dbus_connection_unregister_object (priv->main_dbus_connection, reg_data->registration_id)) - nm_assert_not_reached (); - - if (interface_info->parent.properties) { - for (i = 0; interface_info->parent.properties[i]; i++) - nm_clear_g_variant (®_data->property_cache[i].value); - } - - g_type_class_unref (reg_data->klass); - g_free (reg_data); - } - - g_dbus_connection_emit_signal (priv->main_dbus_connection, - NULL, - OBJECT_MANAGER_SERVER_BASE_PATH, - interface_info_objmgr.name, - signal_info_objmgr_interfaces_removed.name, - g_variant_new ("(oas)", - obj->internal.path, - &builder), - NULL); + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + RegistrationData * reg_data; + GVariantBuilder builder; + + nm_assert(NM_IS_DBUS_OBJECT(obj)); + nm_assert(priv->main_dbus_connection); + nm_assert(priv->objmgr_registration_id != 0); + nm_assert(priv->started); + nm_assert(!c_list_is_empty(&obj->internal.registration_lst_head)); + + g_variant_builder_init(&builder, G_VARIANT_TYPE("as")); + + while ((reg_data = c_list_last_entry(&obj->internal.registration_lst_head, + RegistrationData, + registration_lst))) { + const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info(reg_data); + guint i; + + g_variant_builder_add(&builder, "s", interface_info->parent.name); + c_list_unlink_stale(®_data->registration_lst); + if (!g_dbus_connection_unregister_object(priv->main_dbus_connection, + reg_data->registration_id)) + nm_assert_not_reached(); + + if (interface_info->parent.properties) { + for (i = 0; interface_info->parent.properties[i]; i++) + nm_clear_g_variant(®_data->property_cache[i].value); + } + + g_type_class_unref(reg_data->klass); + g_free(reg_data); + } + + g_dbus_connection_emit_signal(priv->main_dbus_connection, + NULL, + OBJECT_MANAGER_SERVER_BASE_PATH, + interface_info_objmgr.name, + signal_info_objmgr_interfaces_removed.name, + g_variant_new("(oas)", obj->internal.path, &builder), + NULL); } gpointer -nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path) +nm_dbus_manager_lookup_object(NMDBusManager *self, const char *path) { - NMDBusManagerPrivate *priv; - gpointer ptr; - NMDBusObject *obj; + NMDBusManagerPrivate *priv; + gpointer ptr; + NMDBusObject * obj; - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL); - g_return_val_if_fail (path, NULL); + g_return_val_if_fail(NM_IS_DBUS_MANAGER(self), NULL); + g_return_val_if_fail(path, NULL); - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); - ptr = g_hash_table_lookup (priv->objects_by_path, &path); - if (!ptr) - return NULL; + ptr = g_hash_table_lookup(priv->objects_by_path, &path); + if (!ptr) + return NULL; - obj = (NMDBusObject *) (((char *) ptr) - G_STRUCT_OFFSET (NMDBusObject, internal)); - nm_assert (NM_IS_DBUS_OBJECT (obj)); - return obj; + obj = (NMDBusObject *) (((char *) ptr) - G_STRUCT_OFFSET(NMDBusObject, internal)); + nm_assert(NM_IS_DBUS_OBJECT(obj)); + return obj; } void -_nm_dbus_manager_obj_export (NMDBusObject *obj) +_nm_dbus_manager_obj_export(NMDBusObject *obj) { - NMDBusManager *self; - NMDBusManagerPrivate *priv; + NMDBusManager * self; + NMDBusManagerPrivate *priv; - g_return_if_fail (NM_IS_DBUS_OBJECT (obj)); - g_return_if_fail (obj->internal.path); - g_return_if_fail (NM_IS_DBUS_MANAGER (obj->internal.bus_manager)); - g_return_if_fail (c_list_is_empty (&obj->internal.objects_lst)); - nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); + g_return_if_fail(NM_IS_DBUS_OBJECT(obj)); + g_return_if_fail(obj->internal.path); + g_return_if_fail(NM_IS_DBUS_MANAGER(obj->internal.bus_manager)); + g_return_if_fail(c_list_is_empty(&obj->internal.objects_lst)); + nm_assert(c_list_is_empty(&obj->internal.registration_lst_head)); - self = obj->internal.bus_manager; - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); + self = obj->internal.bus_manager; + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); - if (!g_hash_table_add (priv->objects_by_path, &obj->internal)) - nm_assert_not_reached (); - c_list_link_tail (&priv->objects_lst_head, &obj->internal.objects_lst); + if (!g_hash_table_add(priv->objects_by_path, &obj->internal)) + nm_assert_not_reached(); + c_list_link_tail(&priv->objects_lst_head, &obj->internal.objects_lst); - if (priv->started) - _obj_register (self, obj); + if (priv->started) + _obj_register(self, obj); } void -_nm_dbus_manager_obj_unexport (NMDBusObject *obj) +_nm_dbus_manager_obj_unexport(NMDBusObject *obj) { - NMDBusManager *self; - NMDBusManagerPrivate *priv; + NMDBusManager * self; + NMDBusManagerPrivate *priv; - g_return_if_fail (NM_IS_DBUS_OBJECT (obj)); - g_return_if_fail (obj->internal.path); - g_return_if_fail (NM_IS_DBUS_MANAGER (obj->internal.bus_manager)); - g_return_if_fail (!c_list_is_empty (&obj->internal.objects_lst)); + g_return_if_fail(NM_IS_DBUS_OBJECT(obj)); + g_return_if_fail(obj->internal.path); + g_return_if_fail(NM_IS_DBUS_MANAGER(obj->internal.bus_manager)); + g_return_if_fail(!c_list_is_empty(&obj->internal.objects_lst)); - self = obj->internal.bus_manager; - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); + self = obj->internal.bus_manager; + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); - nm_assert (&obj->internal == g_hash_table_lookup (priv->objects_by_path, &obj->internal)); - nm_assert (c_list_contains (&priv->objects_lst_head, &obj->internal.objects_lst)); + nm_assert(&obj->internal == g_hash_table_lookup(priv->objects_by_path, &obj->internal)); + nm_assert(c_list_contains(&priv->objects_lst_head, &obj->internal.objects_lst)); - if (priv->started) - _obj_unregister (self, obj); - else - nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); + if (priv->started) + _obj_unregister(self, obj); + else + nm_assert(c_list_is_empty(&obj->internal.registration_lst_head)); - if (!g_hash_table_remove (priv->objects_by_path, &obj->internal)) - nm_assert_not_reached (); - c_list_unlink (&obj->internal.objects_lst); + if (!g_hash_table_remove(priv->objects_by_path, &obj->internal)) + nm_assert_not_reached(); + c_list_unlink(&obj->internal.objects_lst); } void -_nm_dbus_manager_obj_notify (NMDBusObject *obj, - guint n_pspecs, - const GParamSpec *const*pspecs) +_nm_dbus_manager_obj_notify(NMDBusObject *obj, guint n_pspecs, const GParamSpec *const *pspecs) { - NMDBusManager *self; - NMDBusManagerPrivate *priv; - RegistrationData *reg_data; - guint i, p; - gboolean any_legacy_signals = FALSE; - gboolean any_legacy_properties = FALSE; - GVariantBuilder legacy_builder; - GVariant *device_statistics_args = NULL; - - nm_assert (NM_IS_DBUS_OBJECT (obj)); - nm_assert (obj->internal.path); - nm_assert (NM_IS_DBUS_MANAGER (obj->internal.bus_manager)); - nm_assert (!c_list_is_empty (&obj->internal.objects_lst)); - - self = obj->internal.bus_manager; - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - nm_assert (!priv->started || priv->objmgr_registration_id != 0); - nm_assert (priv->objmgr_registration_id == 0 || priv->main_dbus_connection); - nm_assert (c_list_is_empty (&obj->internal.registration_lst_head) != priv->started); - - if (G_UNLIKELY (!priv->started)) - return; - - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - if (_reg_data_get_interface_info (reg_data)->legacy_property_changed) { - any_legacy_signals = TRUE; - break; - } - } - - /* do a naive search for the matching NMDBusPropertyInfoExtended infos. Since the number of - * (interfaces x properties) is static and possibly small, this naive search is effectively - * O(1). We might wanna introduce some index to lookup the properties in question faster. - * - * The nice part of this implementation is however, that the order in which properties - * are added to the GVariant is strictly defined to be the order in which the D-Bus property-info - * is declared. Getting a defined ordering with some smart lookup would be hard. */ - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - gboolean has_properties = FALSE; - GVariantBuilder builder; - GVariantBuilder invalidated_builder; - GVariant *args; - - if (!interface_info->parent.properties) - continue; - - for (i = 0; interface_info->parent.properties[i]; i++) { - const NMDBusPropertyInfoExtended *property_info = (const NMDBusPropertyInfoExtended *) interface_info->parent.properties[i]; - - for (p = 0; p < n_pspecs; p++) { - const GParamSpec *pspec = pspecs[p]; - gs_unref_variant GVariant *value = NULL; - - if (!nm_streq (property_info->property_name, pspec->name)) - continue; - - value = _obj_get_property (reg_data, i, TRUE); - - if ( property_info->include_in_legacy_property_changed - && any_legacy_signals) { - /* also track the value in the legacy_builder to emit legacy signals below. */ - if (!any_legacy_properties) { - any_legacy_properties = TRUE; - g_variant_builder_init (&legacy_builder, G_VARIANT_TYPE ("a{sv}")); - } - g_variant_builder_add (&legacy_builder, "{sv}", property_info->parent.name, value); - } - - if (!has_properties) { - has_properties = TRUE; - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); - } - g_variant_builder_add (&builder, "{sv}", property_info->parent.name, value); - } - } - - if (!has_properties) - continue; - - args = g_variant_builder_end (&builder); - - if (G_UNLIKELY (interface_info == &nm_interface_info_device_statistics)) { - /* we treat the Device.Statistics signal special, because we need to - * emit a signal also for it (below). */ - nm_assert (!device_statistics_args); - device_statistics_args = g_variant_ref_sink (args); - } - - g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); - g_dbus_connection_emit_signal (priv->main_dbus_connection, - NULL, - obj->internal.path, - "org.freedesktop.DBus.Properties", - "PropertiesChanged", - g_variant_new ("(s@a{sv}as)", - interface_info->parent.name, - args, - &invalidated_builder), - NULL); - } - - if (G_UNLIKELY (device_statistics_args)) { - /* this is a special interface: it has a legacy PropertiesChanged signal, - * however, contrary to other interfaces with ~regular~ legacy signals, - * we only notify about properties that actually belong to this interface. */ - g_dbus_connection_emit_signal (priv->main_dbus_connection, - NULL, - obj->internal.path, - nm_interface_info_device_statistics.parent.name, - "PropertiesChanged", - g_variant_new ("(@a{sv})", - device_statistics_args), - NULL); - g_variant_unref (device_statistics_args); - } - - if (any_legacy_properties) { - gs_unref_variant GVariant *args = NULL; - - /* The legacy PropertyChanged signal on the NetworkManager D-Bus interface is - * deprecated for the standard signal on org.freedesktop.DBus.Properties. However, - * for backward compatibility, we still need to emit it. - * - * Due to a bug in dbus-glib in NetworkManager <= 1.0, the signal would - * not only notify about properties that were actually on the corresponding - * D-Bus interface. Instead, it would notify about all relevant properties - * on all interfaces that had such a signal. - * - * For example, "HwAddress" gets emitted both on "fdo.NM.Device.Ethernet" - * and "fdo.NM.Device.Veth" for veth interfaces, although only the former - * actually has such a property. - * Also note that "fdo.NM.Device" interface has no legacy signal. All notifications - * about its properties are instead emitted on the interfaces of the subtypes. - * - * See bgo#770629 and commit bef26a2e69f51259095fa080221db73de09fd38d. - */ - args = g_variant_ref_sink (g_variant_new ("(a{sv})", - &legacy_builder)); - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - - if (interface_info->legacy_property_changed) { - g_dbus_connection_emit_signal (priv->main_dbus_connection, - NULL, - obj->internal.path, - interface_info->parent.name, - "PropertiesChanged", - args, - NULL); - } - } - } + NMDBusManager * self; + NMDBusManagerPrivate *priv; + RegistrationData * reg_data; + guint i, p; + gboolean any_legacy_signals = FALSE; + gboolean any_legacy_properties = FALSE; + GVariantBuilder legacy_builder; + GVariant * device_statistics_args = NULL; + + nm_assert(NM_IS_DBUS_OBJECT(obj)); + nm_assert(obj->internal.path); + nm_assert(NM_IS_DBUS_MANAGER(obj->internal.bus_manager)); + nm_assert(!c_list_is_empty(&obj->internal.objects_lst)); + + self = obj->internal.bus_manager; + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + + nm_assert(!priv->started || priv->objmgr_registration_id != 0); + nm_assert(priv->objmgr_registration_id == 0 || priv->main_dbus_connection); + nm_assert(c_list_is_empty(&obj->internal.registration_lst_head) != priv->started); + + if (G_UNLIKELY(!priv->started)) + return; + + c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { + if (_reg_data_get_interface_info(reg_data)->legacy_property_changed) { + any_legacy_signals = TRUE; + break; + } + } + + /* do a naive search for the matching NMDBusPropertyInfoExtended infos. Since the number of + * (interfaces x properties) is static and possibly small, this naive search is effectively + * O(1). We might wanna introduce some index to lookup the properties in question faster. + * + * The nice part of this implementation is however, that the order in which properties + * are added to the GVariant is strictly defined to be the order in which the D-Bus property-info + * is declared. Getting a defined ordering with some smart lookup would be hard. */ + c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { + const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info(reg_data); + gboolean has_properties = FALSE; + GVariantBuilder builder; + GVariantBuilder invalidated_builder; + GVariant * args; + + if (!interface_info->parent.properties) + continue; + + for (i = 0; interface_info->parent.properties[i]; i++) { + const NMDBusPropertyInfoExtended *property_info = + (const NMDBusPropertyInfoExtended *) interface_info->parent.properties[i]; + + for (p = 0; p < n_pspecs; p++) { + const GParamSpec *pspec = pspecs[p]; + gs_unref_variant GVariant *value = NULL; + + if (!nm_streq(property_info->property_name, pspec->name)) + continue; + + value = _obj_get_property(reg_data, i, TRUE); + + if (property_info->include_in_legacy_property_changed && any_legacy_signals) { + /* also track the value in the legacy_builder to emit legacy signals below. */ + if (!any_legacy_properties) { + any_legacy_properties = TRUE; + g_variant_builder_init(&legacy_builder, G_VARIANT_TYPE("a{sv}")); + } + g_variant_builder_add(&legacy_builder, + "{sv}", + property_info->parent.name, + value); + } + + if (!has_properties) { + has_properties = TRUE; + g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); + } + g_variant_builder_add(&builder, "{sv}", property_info->parent.name, value); + } + } + + if (!has_properties) + continue; + + args = g_variant_builder_end(&builder); + + if (G_UNLIKELY(interface_info == &nm_interface_info_device_statistics)) { + /* we treat the Device.Statistics signal special, because we need to + * emit a signal also for it (below). */ + nm_assert(!device_statistics_args); + device_statistics_args = g_variant_ref_sink(args); + } + + g_variant_builder_init(&invalidated_builder, G_VARIANT_TYPE("as")); + g_dbus_connection_emit_signal( + priv->main_dbus_connection, + NULL, + obj->internal.path, + "org.freedesktop.DBus.Properties", + "PropertiesChanged", + g_variant_new("(s@a{sv}as)", interface_info->parent.name, args, &invalidated_builder), + NULL); + } + + if (G_UNLIKELY(device_statistics_args)) { + /* this is a special interface: it has a legacy PropertiesChanged signal, + * however, contrary to other interfaces with ~regular~ legacy signals, + * we only notify about properties that actually belong to this interface. */ + g_dbus_connection_emit_signal(priv->main_dbus_connection, + NULL, + obj->internal.path, + nm_interface_info_device_statistics.parent.name, + "PropertiesChanged", + g_variant_new("(@a{sv})", device_statistics_args), + NULL); + g_variant_unref(device_statistics_args); + } + + if (any_legacy_properties) { + gs_unref_variant GVariant *args = NULL; + + /* The legacy PropertyChanged signal on the NetworkManager D-Bus interface is + * deprecated for the standard signal on org.freedesktop.DBus.Properties. However, + * for backward compatibility, we still need to emit it. + * + * Due to a bug in dbus-glib in NetworkManager <= 1.0, the signal would + * not only notify about properties that were actually on the corresponding + * D-Bus interface. Instead, it would notify about all relevant properties + * on all interfaces that had such a signal. + * + * For example, "HwAddress" gets emitted both on "fdo.NM.Device.Ethernet" + * and "fdo.NM.Device.Veth" for veth interfaces, although only the former + * actually has such a property. + * Also note that "fdo.NM.Device" interface has no legacy signal. All notifications + * about its properties are instead emitted on the interfaces of the subtypes. + * + * See bgo#770629 and commit bef26a2e69f51259095fa080221db73de09fd38d. + */ + args = g_variant_ref_sink(g_variant_new("(a{sv})", &legacy_builder)); + c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { + const NMDBusInterfaceInfoExtended *interface_info = + _reg_data_get_interface_info(reg_data); + + if (interface_info->legacy_property_changed) { + g_dbus_connection_emit_signal(priv->main_dbus_connection, + NULL, + obj->internal.path, + interface_info->parent.name, + "PropertiesChanged", + args, + NULL); + } + } + } } void -_nm_dbus_manager_obj_emit_signal (NMDBusObject *obj, - const NMDBusInterfaceInfoExtended *interface_info, - const GDBusSignalInfo *signal_info, - GVariant *args) +_nm_dbus_manager_obj_emit_signal(NMDBusObject * obj, + const NMDBusInterfaceInfoExtended *interface_info, + const GDBusSignalInfo * signal_info, + GVariant * args) { - NMDBusManager *self; - NMDBusManagerPrivate *priv; - - g_return_if_fail (NM_IS_DBUS_OBJECT (obj)); - g_return_if_fail (obj->internal.path); - g_return_if_fail (NM_IS_DBUS_MANAGER (obj->internal.bus_manager)); - g_return_if_fail (!c_list_is_empty (&obj->internal.objects_lst)); - - self = obj->internal.bus_manager; - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - if (!priv->started) { - nm_g_variant_unref_floating (args); - return; - } - - g_dbus_connection_emit_signal (priv->main_dbus_connection, - NULL, - obj->internal.path, - interface_info->parent.name, - signal_info->name, - args, - NULL); + NMDBusManager * self; + NMDBusManagerPrivate *priv; + + g_return_if_fail(NM_IS_DBUS_OBJECT(obj)); + g_return_if_fail(obj->internal.path); + g_return_if_fail(NM_IS_DBUS_MANAGER(obj->internal.bus_manager)); + g_return_if_fail(!c_list_is_empty(&obj->internal.objects_lst)); + + self = obj->internal.bus_manager; + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + + if (!priv->started) { + nm_g_variant_unref_floating(args); + return; + } + + g_dbus_connection_emit_signal(priv->main_dbus_connection, + NULL, + obj->internal.path, + interface_info->parent.name, + signal_info->name, + args, + NULL); } /*****************************************************************************/ static GVariantBuilder * -_obj_collect_properties_per_interface (NMDBusObject *obj, - RegistrationData *reg_data, - GVariantBuilder *builder) +_obj_collect_properties_per_interface(NMDBusObject * obj, + RegistrationData *reg_data, + GVariantBuilder * builder) { - const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); - guint i; - - g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sv}")); - if (interface_info->parent.properties) { - for (i = 0; interface_info->parent.properties[i]; i++) { - const NMDBusPropertyInfoExtended *property_info = (const NMDBusPropertyInfoExtended *) interface_info->parent.properties[i]; - gs_unref_variant GVariant *variant = NULL; - - variant = _obj_get_property (reg_data, i, FALSE); - g_variant_builder_add (builder, - "{sv}", - property_info->parent.name, - variant); - } - } - return builder; + const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info(reg_data); + guint i; + + g_variant_builder_init(builder, G_VARIANT_TYPE("a{sv}")); + if (interface_info->parent.properties) { + for (i = 0; interface_info->parent.properties[i]; i++) { + const NMDBusPropertyInfoExtended *property_info = + (const NMDBusPropertyInfoExtended *) interface_info->parent.properties[i]; + gs_unref_variant GVariant *variant = NULL; + + variant = _obj_get_property(reg_data, i, FALSE); + g_variant_builder_add(builder, "{sv}", property_info->parent.name, variant); + } + } + return builder; } static GVariantBuilder * -_obj_collect_properties_all (NMDBusObject *obj, - GVariantBuilder *builder) +_obj_collect_properties_all(NMDBusObject *obj, GVariantBuilder *builder) { - RegistrationData *reg_data; + RegistrationData *reg_data; - g_variant_builder_init (builder, G_VARIANT_TYPE ("a{sa{sv}}")); + g_variant_builder_init(builder, G_VARIANT_TYPE("a{sa{sv}}")); - c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { - GVariantBuilder properties_builder; + c_list_for_each_entry (reg_data, &obj->internal.registration_lst_head, registration_lst) { + GVariantBuilder properties_builder; - g_variant_builder_add (builder, - "{sa{sv}}", - _reg_data_get_interface_info (reg_data)->parent.name, - _obj_collect_properties_per_interface (obj, - reg_data, - &properties_builder)); - } + g_variant_builder_add( + builder, + "{sa{sv}}", + _reg_data_get_interface_info(reg_data)->parent.name, + _obj_collect_properties_per_interface(obj, reg_data, &properties_builder)); + } - return builder; + return builder; } static void -dbus_vtable_objmgr_method_call (GDBusConnection *connection, - const char *sender, - const char *object_path, - const char *interface_name, - const char *method_name, - GVariant *parameters, - GDBusMethodInvocation *invocation, - gpointer user_data) +dbus_vtable_objmgr_method_call(GDBusConnection * connection, + const char * sender, + const char * object_path, + const char * interface_name, + const char * method_name, + GVariant * parameters, + GDBusMethodInvocation *invocation, + gpointer user_data) { - NMDBusManager *self = user_data; - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - GVariantBuilder array_builder; - NMDBusObject *obj; - - nm_assert (nm_streq0 (object_path, OBJECT_MANAGER_SERVER_BASE_PATH)); - - if ( !nm_streq (method_name, "GetManagedObjects") - || !nm_streq (interface_name, interface_info_objmgr.name)) { - g_dbus_method_invocation_return_error (invocation, - G_DBUS_ERROR, - G_DBUS_ERROR_UNKNOWN_METHOD, - "Unknown method %s - only GetManagedObjects() is supported", - method_name); - return; - } - - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a{oa{sa{sv}}}")); - c_list_for_each_entry (obj, &priv->objects_lst_head, internal.objects_lst) { - GVariantBuilder interfaces_builder; - - /* note that we are called on an idle handler. Hence, all properties are - * supposed to be in a consistent state. That is true, if you always - * g_object_thaw_notify() before returning to the mainloop. Keeping - * signals frozen between while returning from the current call stack - * is anyway a very fragile thing, easy to get wrong. Don't do that. */ - g_variant_builder_add (&array_builder, - "{oa{sa{sv}}}", - obj->internal.path, - _obj_collect_properties_all (obj, - &interfaces_builder)); - } - g_dbus_method_invocation_return_value (invocation, - g_variant_new ("(a{oa{sa{sv}}})", - &array_builder)); + NMDBusManager * self = user_data; + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + GVariantBuilder array_builder; + NMDBusObject * obj; + + nm_assert(nm_streq0(object_path, OBJECT_MANAGER_SERVER_BASE_PATH)); + + if (!nm_streq(method_name, "GetManagedObjects") + || !nm_streq(interface_name, interface_info_objmgr.name)) { + g_dbus_method_invocation_return_error( + invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_UNKNOWN_METHOD, + "Unknown method %s - only GetManagedObjects() is supported", + method_name); + return; + } + + g_variant_builder_init(&array_builder, G_VARIANT_TYPE("a{oa{sa{sv}}}")); + c_list_for_each_entry (obj, &priv->objects_lst_head, internal.objects_lst) { + GVariantBuilder interfaces_builder; + + /* note that we are called on an idle handler. Hence, all properties are + * supposed to be in a consistent state. That is true, if you always + * g_object_thaw_notify() before returning to the mainloop. Keeping + * signals frozen between while returning from the current call stack + * is anyway a very fragile thing, easy to get wrong. Don't do that. */ + g_variant_builder_add(&array_builder, + "{oa{sa{sv}}}", + obj->internal.path, + _obj_collect_properties_all(obj, &interfaces_builder)); + } + g_dbus_method_invocation_return_value(invocation, + g_variant_new("(a{oa{sa{sv}}})", &array_builder)); } -static const GDBusInterfaceVTable dbus_vtable_objmgr = { - .method_call = dbus_vtable_objmgr_method_call -}; - -static const GDBusSignalInfo signal_info_objmgr_interfaces_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "InterfacesAdded", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("object_path", "o"), - NM_DEFINE_GDBUS_ARG_INFO ("interfaces_and_properties", "a{sa{sv}}"), - ), -); - -static const GDBusSignalInfo signal_info_objmgr_interfaces_removed = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT ( - "InterfacesRemoved", - .args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("object_path", "o"), - NM_DEFINE_GDBUS_ARG_INFO ("interfaces", "as"), - ), -); - -static const GDBusInterfaceInfo interface_info_objmgr = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT ( - DBUS_INTERFACE_OBJECT_MANAGER, - .methods = NM_DEFINE_GDBUS_METHOD_INFOS ( - NM_DEFINE_GDBUS_METHOD_INFO ( - "GetManagedObjects", - .out_args = NM_DEFINE_GDBUS_ARG_INFOS ( - NM_DEFINE_GDBUS_ARG_INFO ("object_paths_interfaces_and_properties", "a{oa{sa{sv}}}"), - ), - ), - ), - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS ( - &signal_info_objmgr_interfaces_added, - &signal_info_objmgr_interfaces_removed, - ), -); +static const GDBusInterfaceVTable dbus_vtable_objmgr = {.method_call = + dbus_vtable_objmgr_method_call}; + +static const GDBusSignalInfo signal_info_objmgr_interfaces_added = NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( + "InterfacesAdded", + .args = NM_DEFINE_GDBUS_ARG_INFOS( + NM_DEFINE_GDBUS_ARG_INFO("object_path", "o"), + NM_DEFINE_GDBUS_ARG_INFO("interfaces_and_properties", "a{sa{sv}}"), ), ); + +static const GDBusSignalInfo signal_info_objmgr_interfaces_removed = + NM_DEFINE_GDBUS_SIGNAL_INFO_INIT( + "InterfacesRemoved", + .args = NM_DEFINE_GDBUS_ARG_INFOS(NM_DEFINE_GDBUS_ARG_INFO("object_path", "o"), + NM_DEFINE_GDBUS_ARG_INFO("interfaces", "as"), ), ); + +static const GDBusInterfaceInfo interface_info_objmgr = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( + DBUS_INTERFACE_OBJECT_MANAGER, + .methods = NM_DEFINE_GDBUS_METHOD_INFOS( + NM_DEFINE_GDBUS_METHOD_INFO( + "GetManagedObjects", + .out_args = NM_DEFINE_GDBUS_ARG_INFOS( + NM_DEFINE_GDBUS_ARG_INFO("object_paths_interfaces_and_properties", + "a{oa{sa{sv}}}"), ), ), ), + .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&signal_info_objmgr_interfaces_added, + &signal_info_objmgr_interfaces_removed, ), ); /*****************************************************************************/ GDBusConnection * -nm_dbus_manager_get_dbus_connection (NMDBusManager *self) +nm_dbus_manager_get_dbus_connection(NMDBusManager *self) { - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL); + g_return_val_if_fail(NM_IS_DBUS_MANAGER(self), NULL); - return NM_DBUS_MANAGER_GET_PRIVATE (self)->main_dbus_connection; + return NM_DBUS_MANAGER_GET_PRIVATE(self)->main_dbus_connection; } void -nm_dbus_manager_start (NMDBusManager *self, - NMDBusManagerSetPropertyHandler set_property_handler, - gpointer set_property_handler_data) +nm_dbus_manager_start(NMDBusManager * self, + NMDBusManagerSetPropertyHandler set_property_handler, + gpointer set_property_handler_data) { - NMDBusManagerPrivate *priv; - NMDBusObject *obj; + NMDBusManagerPrivate *priv; + NMDBusObject * obj; - g_return_if_fail (NM_IS_DBUS_MANAGER (self)); + g_return_if_fail(NM_IS_DBUS_MANAGER(self)); - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); - nm_assert (!priv->started); + nm_assert(!priv->started); - if (priv->objmgr_registration_id == 0) { - /* Do nothing. We're presumably in the configure-and-quit mode. */ - return; - } + if (priv->objmgr_registration_id == 0) { + /* Do nothing. We're presumably in the configure-and-quit mode. */ + return; + } - priv->set_property_handler = set_property_handler; - priv->set_property_handler_data = set_property_handler_data; - priv->started = TRUE; + priv->set_property_handler = set_property_handler; + priv->set_property_handler_data = set_property_handler_data; + priv->started = TRUE; - c_list_for_each_entry (obj, &priv->objects_lst_head, internal.objects_lst) - _obj_register (self, obj); + c_list_for_each_entry (obj, &priv->objects_lst_head, internal.objects_lst) + _obj_register(self, obj); } gboolean -nm_dbus_manager_acquire_bus (NMDBusManager *self, - gboolean request_name) +nm_dbus_manager_acquire_bus(NMDBusManager *self, gboolean request_name) { - NMDBusManagerPrivate *priv; - gs_free_error GError *error = NULL; - gs_unref_variant GVariant *ret = NULL; - guint32 result; - guint registration_id; - - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), FALSE); - - priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - - /* Create the D-Bus connection and registering the name synchronously. - * That is necessary because we need to exit right away if we can't - * acquire the name despite connecting to the bus successfully. - * It means that something is gravely broken -- such as another NetworkManager - * instance running. */ - priv->main_dbus_connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, - NULL, - &error); - if (!priv->main_dbus_connection) { - _LOGE ("cannot connect to D-Bus: %s", error->message); - return FALSE; - } - - g_dbus_connection_set_exit_on_close (priv->main_dbus_connection, FALSE); - - if (!request_name) { - _LOGD ("D-Bus connection created"); - return TRUE; - } - - registration_id = g_dbus_connection_register_object (priv->main_dbus_connection, - OBJECT_MANAGER_SERVER_BASE_PATH, - NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info_objmgr), - &dbus_vtable_objmgr, - self, - NULL, - &error); - if (!registration_id) { - _LOGE ("failure to register object manager: %s", error->message); - return FALSE; - } - - ret = g_dbus_connection_call_sync (priv->main_dbus_connection, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "RequestName", - g_variant_new ("(su)", - NM_DBUS_SERVICE, - DBUS_NAME_FLAG_DO_NOT_QUEUE), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); - if (!ret) { - _LOGE ("fatal failure to acquire D-Bus service \"%s"": %s", - NM_DBUS_SERVICE, error->message); - g_dbus_connection_unregister_object (priv->main_dbus_connection, registration_id); - return FALSE; - } - - g_variant_get (ret, "(u)", &result); - if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { - _LOGE ("fatal failure to acquire D-Bus service \"%s\" (%u). Service already taken", - NM_DBUS_SERVICE, (guint) result); - g_dbus_connection_unregister_object (priv->main_dbus_connection, registration_id); - return FALSE; - } - - priv->objmgr_registration_id = registration_id; - - _LOGI ("acquired D-Bus service \"%s\"", NM_DBUS_SERVICE); - - return TRUE; + NMDBusManagerPrivate *priv; + gs_free_error GError *error = NULL; + gs_unref_variant GVariant *ret = NULL; + guint32 result; + guint registration_id; + + g_return_val_if_fail(NM_IS_DBUS_MANAGER(self), FALSE); + + priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + + /* Create the D-Bus connection and registering the name synchronously. + * That is necessary because we need to exit right away if we can't + * acquire the name despite connecting to the bus successfully. + * It means that something is gravely broken -- such as another NetworkManager + * instance running. */ + priv->main_dbus_connection = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &error); + if (!priv->main_dbus_connection) { + _LOGE("cannot connect to D-Bus: %s", error->message); + return FALSE; + } + + g_dbus_connection_set_exit_on_close(priv->main_dbus_connection, FALSE); + + if (!request_name) { + _LOGD("D-Bus connection created"); + return TRUE; + } + + registration_id = g_dbus_connection_register_object( + priv->main_dbus_connection, + OBJECT_MANAGER_SERVER_BASE_PATH, + NM_UNCONST_PTR(GDBusInterfaceInfo, &interface_info_objmgr), + &dbus_vtable_objmgr, + self, + NULL, + &error); + if (!registration_id) { + _LOGE("failure to register object manager: %s", error->message); + return FALSE; + } + + ret = g_dbus_connection_call_sync( + priv->main_dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "RequestName", + g_variant_new("(su)", NM_DBUS_SERVICE, DBUS_NAME_FLAG_DO_NOT_QUEUE), + G_VARIANT_TYPE("(u)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + &error); + if (!ret) { + _LOGE("fatal failure to acquire D-Bus service \"%s" + ": %s", + NM_DBUS_SERVICE, + error->message); + g_dbus_connection_unregister_object(priv->main_dbus_connection, registration_id); + return FALSE; + } + + g_variant_get(ret, "(u)", &result); + if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) { + _LOGE("fatal failure to acquire D-Bus service \"%s\" (%u). Service already taken", + NM_DBUS_SERVICE, + (guint) result); + g_dbus_connection_unregister_object(priv->main_dbus_connection, registration_id); + return FALSE; + } + + priv->objmgr_registration_id = registration_id; + + _LOGI("acquired D-Bus service \"%s\"", NM_DBUS_SERVICE); + + return TRUE; } void -nm_dbus_manager_stop (NMDBusManager *self) +nm_dbus_manager_stop(NMDBusManager *self) { - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); - priv->shutting_down = TRUE; + priv->shutting_down = TRUE; - /* during shutdown we also clear the set-property-handler. It's no longer - * possible to set a property, because doing so would require authorization, - * which is async, which is just complicated to get right. No more property - * setting from now on. */ - priv->set_property_handler = NULL; - priv->set_property_handler_data = NULL; + /* during shutdown we also clear the set-property-handler. It's no longer + * possible to set a property, because doing so would require authorization, + * which is async, which is just complicated to get right. No more property + * setting from now on. */ + priv->set_property_handler = NULL; + priv->set_property_handler_data = NULL; } gboolean -nm_dbus_manager_is_stopping (NMDBusManager *self) +nm_dbus_manager_is_stopping(NMDBusManager *self) { - return NM_DBUS_MANAGER_GET_PRIVATE (self)->shutting_down; + return NM_DBUS_MANAGER_GET_PRIVATE(self)->shutting_down; } /*****************************************************************************/ static void -nm_dbus_manager_init (NMDBusManager *self) +nm_dbus_manager_init(NMDBusManager *self) { - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); - c_list_init (&priv->private_servers_lst_head); - c_list_init (&priv->objects_lst_head); + c_list_init(&priv->private_servers_lst_head); + c_list_init(&priv->objects_lst_head); - priv->objects_by_path = g_hash_table_new ((GHashFunc) _objects_by_path_hash, (GEqualFunc) _objects_by_path_equal); + priv->objects_by_path = + g_hash_table_new((GHashFunc) _objects_by_path_hash, (GEqualFunc) _objects_by_path_equal); - c_list_init (&priv->caller_info_lst_head); + c_list_init(&priv->caller_info_lst_head); } static void -dispose (GObject *object) +dispose(GObject *object) { - NMDBusManager *self = NM_DBUS_MANAGER (object); - NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - PrivateServer *s, *s_safe; - CallerInfo *caller_info; + NMDBusManager * self = NM_DBUS_MANAGER(object); + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE(self); + PrivateServer * s, *s_safe; + CallerInfo * caller_info; - /* All exported NMDBusObject instances keep the manager alive, so we don't - * expect any remaining objects. */ - nm_assert (!priv->objects_by_path || g_hash_table_size (priv->objects_by_path) == 0); - nm_assert (c_list_is_empty (&priv->objects_lst_head)); + /* All exported NMDBusObject instances keep the manager alive, so we don't + * expect any remaining objects. */ + nm_assert(!priv->objects_by_path || g_hash_table_size(priv->objects_by_path) == 0); + nm_assert(c_list_is_empty(&priv->objects_lst_head)); - nm_clear_pointer (&priv->objects_by_path, g_hash_table_destroy); + nm_clear_pointer(&priv->objects_by_path, g_hash_table_destroy); - c_list_for_each_entry_safe (s, s_safe, &priv->private_servers_lst_head, private_servers_lst) - private_server_free (s); + c_list_for_each_entry_safe (s, s_safe, &priv->private_servers_lst_head, private_servers_lst) + private_server_free(s); - if (priv->objmgr_registration_id) { - g_dbus_connection_unregister_object (priv->main_dbus_connection, - nm_steal_int (&priv->objmgr_registration_id)); - } + if (priv->objmgr_registration_id) { + g_dbus_connection_unregister_object(priv->main_dbus_connection, + nm_steal_int(&priv->objmgr_registration_id)); + } - g_clear_object (&priv->main_dbus_connection); + g_clear_object(&priv->main_dbus_connection); - G_OBJECT_CLASS (nm_dbus_manager_parent_class)->dispose (object); + G_OBJECT_CLASS(nm_dbus_manager_parent_class)->dispose(object); - while ((caller_info = c_list_first_entry (&priv->caller_info_lst_head, CallerInfo, caller_info_lst))) - _caller_info_free (caller_info); + while ((caller_info = + c_list_first_entry(&priv->caller_info_lst_head, CallerInfo, caller_info_lst))) + _caller_info_free(caller_info); } static void -nm_dbus_manager_class_init (NMDBusManagerClass *klass) +nm_dbus_manager_class_init(NMDBusManagerClass *klass) { - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = dispose; - - signals[PRIVATE_CONNECTION_NEW] = - g_signal_new (NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 2, G_TYPE_DBUS_CONNECTION, G_TYPE_DBUS_OBJECT_MANAGER_SERVER); - - signals[PRIVATE_CONNECTION_DISCONNECTED] = - g_signal_new (NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 1, G_TYPE_POINTER); + GObjectClass *object_class = G_OBJECT_CLASS(klass); + + object_class->dispose = dispose; + + signals[PRIVATE_CONNECTION_NEW] = g_signal_new(NM_DBUS_MANAGER_PRIVATE_CONNECTION_NEW, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 2, + G_TYPE_DBUS_CONNECTION, + G_TYPE_DBUS_OBJECT_MANAGER_SERVER); + + signals[PRIVATE_CONNECTION_DISCONNECTED] = + g_signal_new(NM_DBUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, + G_OBJECT_CLASS_TYPE(object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED, + 0, + NULL, + NULL, + NULL, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); } static NMAuthSubject * -_new_unix_process (GDBusMethodInvocation *context, - GDBusConnection *connection, - GDBusMessage *message) +_new_unix_process(GDBusMethodInvocation *context, + GDBusConnection * connection, + GDBusMessage * message) { - NMAuthSubject *self; - const char *dbus_sender = NULL; - gulong uid = 0; - gulong pid = 0; - gboolean success; - - g_return_val_if_fail (context || (connection && message), NULL); - - if (context) { - success = nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), - context, - &dbus_sender, - &uid, - &pid); - } else { - nm_assert (message); - success = nm_dbus_manager_get_caller_info_from_message (nm_dbus_manager_get (), - connection, - message, - &dbus_sender, - &uid, - &pid); - } - - if (!success) - return NULL; - - g_return_val_if_fail (dbus_sender && *dbus_sender, NULL); - /* polkit glib library stores uid and pid as int. There might be some - * pitfalls if the id ever happens to be larger then that. Just assert against - * it here. */ - g_return_val_if_fail (uid <= MIN (G_MAXINT, G_MAXINT32), NULL); - g_return_val_if_fail (pid > 0 && pid <= MIN (G_MAXINT, G_MAXINT32), NULL); - - self = nm_auth_subject_new_unix_process (dbus_sender, pid, uid); - - if (nm_auth_subject_get_subject_type (self) != NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) { - /* this most likely happened because the process is gone (start_time==0). - * Either that is not assert-worthy, or constructed() already asserted. - * Just return NULL. */ - g_clear_object (&self); - } - return self; + NMAuthSubject *self; + const char * dbus_sender = NULL; + gulong uid = 0; + gulong pid = 0; + gboolean success; + + g_return_val_if_fail(context || (connection && message), NULL); + + if (context) { + success = nm_dbus_manager_get_caller_info(nm_dbus_manager_get(), + context, + &dbus_sender, + &uid, + &pid); + } else { + nm_assert(message); + success = nm_dbus_manager_get_caller_info_from_message(nm_dbus_manager_get(), + connection, + message, + &dbus_sender, + &uid, + &pid); + } + + if (!success) + return NULL; + + g_return_val_if_fail(dbus_sender && *dbus_sender, NULL); + /* polkit glib library stores uid and pid as int. There might be some + * pitfalls if the id ever happens to be larger then that. Just assert against + * it here. */ + g_return_val_if_fail(uid <= MIN(G_MAXINT, G_MAXINT32), NULL); + g_return_val_if_fail(pid > 0 && pid <= MIN(G_MAXINT, G_MAXINT32), NULL); + + self = nm_auth_subject_new_unix_process(dbus_sender, pid, uid); + + if (nm_auth_subject_get_subject_type(self) != NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) { + /* this most likely happened because the process is gone (start_time==0). + * Either that is not assert-worthy, or constructed() already asserted. + * Just return NULL. */ + g_clear_object(&self); + } + return self; } NMAuthSubject * -nm_dbus_manager_new_auth_subject_from_context (GDBusMethodInvocation *context) +nm_dbus_manager_new_auth_subject_from_context(GDBusMethodInvocation *context) { - return _new_unix_process (context, NULL, NULL); + return _new_unix_process(context, NULL, NULL); } NMAuthSubject * -nm_dbus_manager_new_auth_subject_from_message (GDBusConnection *connection, - GDBusMessage *message) +nm_dbus_manager_new_auth_subject_from_message(GDBusConnection *connection, GDBusMessage *message) { - return _new_unix_process (NULL, connection, message); + return _new_unix_process(NULL, connection, message); } |