diff options
author | Thomas Haller <thaller@redhat.com> | 2019-04-09 20:40:42 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-04-09 20:40:42 +0200 |
commit | 3a2e002a2ebed799d4caa3b1b2d913d3684c47e5 (patch) | |
tree | f5facac1ff4676fcb7062e177f664ca93c198e08 | |
parent | 9c96d0a8c344e37fb1a07ffed07b2da36d325619 (diff) | |
parent | e04dc445ec00f8e82bbc1b9ef614b50c906d6606 (diff) | |
download | NetworkManager-3a2e002a2ebed799d4caa3b1b2d913d3684c47e5.tar.gz |
dns,dbus: merge branch 'th/systemd-resolved-dbus-activated'
https://github.com/NetworkManager/NetworkManager/pull/336
-rw-r--r-- | src/dns/nm-dns-manager.c | 11 | ||||
-rw-r--r-- | src/dns/nm-dns-systemd-resolved.c | 278 | ||||
-rw-r--r-- | src/dns/nm-dns-systemd-resolved.h | 2 | ||||
-rw-r--r-- | src/nm-auth-subject.c | 7 | ||||
-rw-r--r-- | src/nm-connectivity.c | 13 | ||||
-rw-r--r-- | src/nm-dbus-manager.c | 294 | ||||
-rw-r--r-- | src/nm-dbus-manager.h | 6 |
7 files changed, 432 insertions, 179 deletions
diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index c7c561c459..27c3e7109c 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -347,13 +347,20 @@ gboolean nm_dns_manager_has_systemd_resolved (NMDnsManager *self) { NMDnsManagerPrivate *priv; + NMDnsSystemdResolved *plugin = NULL; g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); priv = NM_DNS_MANAGER_GET_PRIVATE (self); - return priv->sd_resolve_plugin - || NM_IS_DNS_SYSTEMD_RESOLVED (priv->plugin); + if (priv->sd_resolve_plugin) { + nm_assert (!NM_IS_DNS_SYSTEMD_RESOLVED (priv->plugin)); + plugin = NM_DNS_SYSTEMD_RESOLVED (priv->sd_resolve_plugin); + } else if (NM_IS_DNS_SYSTEMD_RESOLVED (priv->plugin)) + plugin = NM_DNS_SYSTEMD_RESOLVED (priv->plugin); + + return plugin + && nm_dns_systemd_resolved_is_running (plugin); } /*****************************************************************************/ diff --git a/src/dns/nm-dns-systemd-resolved.c b/src/dns/nm-dns-systemd-resolved.c index 4718e74037..573f047b47 100644 --- a/src/dns/nm-dns-systemd-resolved.c +++ b/src/dns/nm-dns-systemd-resolved.c @@ -42,9 +42,11 @@ #include "nm-setting-connection.h" #include "devices/nm-device.h" #include "NetworkManagerUtils.h" +#include "nm-dbus-compat.h" -#define SYSTEMD_RESOLVED_DBUS_SERVICE "org.freedesktop.resolve1" -#define SYSTEMD_RESOLVED_DBUS_PATH "/org/freedesktop/resolve1" +#define SYSTEMD_RESOLVED_DBUS_SERVICE "org.freedesktop.resolve1" +#define SYSTEMD_RESOLVED_MANAGER_IFACE "org.freedesktop.resolve1.Manager" +#define SYSTEMD_RESOLVED_DBUS_PATH "/org/freedesktop/resolve1" /*****************************************************************************/ @@ -62,10 +64,14 @@ typedef struct { /*****************************************************************************/ typedef struct { - GDBusProxy *resolve; - GCancellable *init_cancellable; - GCancellable *update_cancellable; + GDBusConnection *dbus_connection; + GCancellable *cancellable; CList request_queue_lst_head; + guint name_owner_changed_id; + bool send_updates_warn_ratelimited:1; + bool try_start_blocked:1; + bool dbus_has_owner:1; + bool dbus_initied:1; } NMDnsSystemdResolvedPrivate; struct _NMDnsSystemdResolved { @@ -121,16 +127,26 @@ _interface_config_free (InterfaceConfig *config) static void call_done (GObject *source, GAsyncResult *r, gpointer user_data) { - GVariant *v; + gs_unref_variant GVariant *v = NULL; gs_free_error GError *error = NULL; NMDnsSystemdResolved *self = (NMDnsSystemdResolved *) user_data; + NMDnsSystemdResolvedPrivate *priv; + + v = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), r, &error); + if ( !v + && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - v = g_dbus_proxy_call_finish (G_DBUS_PROXY (source), r, &error); if (!v) { - if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) - return; - _LOGW ("Failed: %s", error->message); - } + if (!priv->send_updates_warn_ratelimited) { + priv->send_updates_warn_ratelimited = TRUE; + _LOGW ("send-updates failed to update systemd-resolved: %s", error->message); + } else + _LOGD ("send-updates failed: %s", error->message); + } else + priv->send_updates_warn_ratelimited = FALSE; } static void @@ -174,12 +190,11 @@ static void free_pending_updates (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - RequestItem *request_item, *request_item_safe; + RequestItem *request_item; - c_list_for_each_entry_safe (request_item, - request_item_safe, - &priv->request_queue_lst_head, - request_queue_lst) + while ((request_item = c_list_first_entry (&priv->request_queue_lst_head, + RequestItem, + request_queue_lst))) _request_item_free (request_item); } @@ -266,27 +281,74 @@ static void send_updates (NMDnsSystemdResolved *self) { NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - RequestItem *request_item, *request_item_safe; + RequestItem *request_item; + + if (c_list_is_empty (&priv->request_queue_lst_head)) { + /* nothing to do. */ + return; + } + + if (!priv->dbus_initied) { + _LOGT ("send-updates: D-Bus connection not ready"); + return; + } - nm_clear_g_cancellable (&priv->update_cancellable); + if (!priv->dbus_has_owner) { + if (priv->try_start_blocked) { + /* we have no name owner and we already tried poking the service to + * autostart. */ + _LOGT ("send-updates: no name owner"); + return; + } - if (!priv->resolve) + _LOGT ("send-updates: no name owner. Try start service..."); + priv->try_start_blocked = TRUE; + + g_dbus_connection_call (priv->dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "StartServiceByName", + g_variant_new ("(su)", SYSTEMD_RESOLVED_DBUS_SERVICE, 0u), + G_VARIANT_TYPE ("(u)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, + NULL, + NULL); return; + } - priv->update_cancellable = g_cancellable_new (); - - c_list_for_each_entry_safe (request_item, - request_item_safe, - &priv->request_queue_lst_head, - request_queue_lst) { - g_dbus_proxy_call (priv->resolve, - request_item->operation, - request_item->argument, - G_DBUS_CALL_FLAGS_NONE, - -1, - priv->update_cancellable, - call_done, - self); + _LOGT ("send-updates: start %lu requests", + c_list_length (&priv->request_queue_lst_head)); + + nm_clear_g_cancellable (&priv->cancellable); + + priv->cancellable = g_cancellable_new (); + + while ((request_item = c_list_first_entry (&priv->request_queue_lst_head, + RequestItem, + request_queue_lst))) { + /* Above we explicitly call "StartServiceByName" trying to avoid D-Bus activating systmd-resolved + * multiple times. There is still a race, were we might hit this line although actually + * the service just quit this very moment. In that case, we would try to D-Bus activate the + * service multiple times during each call (something we wanted to avoid). + * + * But this is hard to avoid, because we'd have to check the error failure to detect the reason + * and retry. The race is not critical, because at worst it results in logging a warning + * about failure to start systemd.resolved. */ + g_dbus_connection_call (priv->dbus_connection, + SYSTEMD_RESOLVED_DBUS_SERVICE, + SYSTEMD_RESOLVED_DBUS_PATH, + SYSTEMD_RESOLVED_MANAGER_IFACE, + request_item->operation, + request_item->argument, + NULL, + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + call_done, + self); _request_item_free (request_item); } } @@ -360,28 +422,100 @@ get_name (NMDnsPlugin *plugin) /*****************************************************************************/ static void -resolved_proxy_created (GObject *source, GAsyncResult *r, gpointer user_data) +name_owner_changed (NMDnsSystemdResolved *self, + const char *owner) { - NMDnsSystemdResolved *self = (NMDnsSystemdResolved *) user_data; + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); + + owner = nm_str_not_empty (owner); + + if (!owner) + _LOGT ("D-Bus name for systemd-resolved has no owner"); + else + _LOGT ("D-Bus name for systemd-resolved has owner %s", owner); + + priv->dbus_has_owner = !!owner; + if (owner) + priv->try_start_blocked = FALSE; + + send_updates (self); +} + +static void +name_owner_changed_cb (GDBusConnection *connection, + const char *sender_name, + const char *object_path, + const char *interface_name, + const char *signal_name, + GVariant *parameters, + gpointer user_data) +{ + NMDnsSystemdResolved *self = user_data; + NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); + const char *new_owner; + + if (!g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) + return; + + g_variant_get (parameters, + "(&s&s&s)", + NULL, + NULL, + &new_owner); + + if (!priv->dbus_initied) { + /* There was a race and we got a NameOwnerChanged signal before GetNameOwner + * returns. */ + priv->dbus_initied = TRUE; + nm_clear_g_cancellable (&priv->cancellable); + } + + name_owner_changed (user_data, new_owner); +} + +static void +get_name_owner_cb (GObject *source, + GAsyncResult *res, + gpointer user_data) +{ + NMDnsSystemdResolved *self; NMDnsSystemdResolvedPrivate *priv; + gs_unref_variant GVariant *ret = NULL; gs_free_error GError *error = NULL; - GDBusProxy *resolve; + const char *owner = NULL; - resolve = g_dbus_proxy_new_finish (r, &error); - if ( !resolve + ret = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source), res, &error); + if ( !ret && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) return; + if (ret) + g_variant_get (ret, "(&s)", &owner); + + self = user_data; priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); - g_clear_object (&priv->init_cancellable); - if (!resolve) { - _LOGW ("failed to connect to resolved via DBus: %s", error->message); - g_signal_emit_by_name (self, NM_DNS_PLUGIN_FAILED); - return; - } - priv->resolve = resolve; - send_updates (self); + g_clear_object (&priv->cancellable); + + priv->dbus_initied = TRUE; + + name_owner_changed (self, owner); +} + +/*****************************************************************************/ + +gboolean +nm_dns_systemd_resolved_is_running (NMDnsSystemdResolved *self) +{ + NMDnsSystemdResolvedPrivate *priv; + + g_return_val_if_fail (NM_IS_DNS_SYSTEMD_RESOLVED (self), FALSE); + + priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); + + return priv->dbus_initied + && ( priv->dbus_has_owner + || !priv->try_start_blocked); } /*****************************************************************************/ @@ -393,17 +527,35 @@ nm_dns_systemd_resolved_init (NMDnsSystemdResolved *self) c_list_init (&priv->request_queue_lst_head); - priv->init_cancellable = g_cancellable_new (); - g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | - G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - NULL, - SYSTEMD_RESOLVED_DBUS_SERVICE, - SYSTEMD_RESOLVED_DBUS_PATH, - SYSTEMD_RESOLVED_DBUS_SERVICE ".Manager", - priv->init_cancellable, - resolved_proxy_created, - self); + priv->dbus_connection = nm_g_object_ref (nm_dbus_manager_get_dbus_connection (nm_dbus_manager_get ())); + if (!priv->dbus_connection) { + _LOGD ("no D-Bus connection"); + return; + } + + priv->name_owner_changed_id = g_dbus_connection_signal_subscribe (priv->dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_INTERFACE_DBUS, + "NameOwnerChanged", + DBUS_PATH_DBUS, + SYSTEMD_RESOLVED_DBUS_SERVICE, + G_DBUS_SIGNAL_FLAGS_NONE, + name_owner_changed_cb, + self, + NULL); + priv->cancellable = g_cancellable_new (); + g_dbus_connection_call (priv->dbus_connection, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + "GetNameOwner", + g_variant_new ("(s)", SYSTEMD_RESOLVED_DBUS_SERVICE), + G_VARIANT_TYPE ("(s)"), + G_DBUS_CALL_FLAGS_NONE, + -1, + priv->cancellable, + get_name_owner_cb, + self); } NMDnsPlugin * @@ -419,9 +571,15 @@ dispose (GObject *object) NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); free_pending_updates (self); - g_clear_object (&priv->resolve); - nm_clear_g_cancellable (&priv->init_cancellable); - nm_clear_g_cancellable (&priv->update_cancellable); + + if (priv->name_owner_changed_id != 0) { + g_dbus_connection_signal_unsubscribe (priv->dbus_connection, + nm_steal_int (&priv->name_owner_changed_id)); + } + + nm_clear_g_cancellable (&priv->cancellable); + + g_clear_object (&priv->dbus_connection); G_OBJECT_CLASS (nm_dns_systemd_resolved_parent_class)->dispose (object); } diff --git a/src/dns/nm-dns-systemd-resolved.h b/src/dns/nm-dns-systemd-resolved.h index 800a60c154..b79ff5e4ec 100644 --- a/src/dns/nm-dns-systemd-resolved.h +++ b/src/dns/nm-dns-systemd-resolved.h @@ -36,4 +36,6 @@ GType nm_dns_systemd_resolved_get_type (void); NMDnsPlugin *nm_dns_systemd_resolved_new (void); +gboolean nm_dns_systemd_resolved_is_running (NMDnsSystemdResolved *self); + #endif /* __NETWORKMANAGER_DNS_SYSTEMD_RESOLVED_H__ */ diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c index dff331a8d8..5599201ef7 100644 --- a/src/nm-auth-subject.c +++ b/src/nm-auth-subject.c @@ -173,9 +173,10 @@ _new_unix_process (GDBusMethodInvocation *context, GDBusMessage *message) { NMAuthSubject *self; - gboolean success = FALSE; - gulong pid = 0, uid = 0; - gs_free char *dbus_sender = NULL; + const char *dbus_sender = NULL; + gulong uid = 0; + gulong pid = 0; + gboolean success; g_return_val_if_fail (context || (connection && message), NULL); diff --git a/src/nm-connectivity.c b/src/nm-connectivity.c index b72413d2f3..2aab23862b 100644 --- a/src/nm-connectivity.c +++ b/src/nm-connectivity.c @@ -840,7 +840,18 @@ nm_connectivity_check_start (NMConnectivity *self, * * Yes, this makes NMConnectivity singleton dependent on NMDnsManager singleton. * Well, not really: it makes connectivity-check-start dependent on NMDnsManager - * which merely means, not to start a connectivity check, late during shutdown. */ + * which merely means, not to start a connectivity check, late during shutdown. + * + * NMDnsSystemdResolved tries to D-Bus activate systemd-resolved only once, + * to not spam syslog with failures messages from dbus-daemon. + * Note that unless NMDnsSystemdResolved tried and failed to start systemd-resolved, + * it guesses that systemd-resolved is activatable and returns %TRUE here. That + * means, while NMDnsSystemdResolved would not try to D-Bus activate systemd-resolved + * more than once, NMConnectivity might -- until NMDnsSystemdResolved tried itself + * and noticed that systemd-resolved is not available. + * This is relatively cumbersome to avoid, because we would have to go through + * NMDnsSystemdResolved trying to asynchronously start the service, to ensure there + * is only one attempt to start the service. */ has_systemd_resolved = nm_dns_manager_has_systemd_resolved (nm_dns_manager_get ()); if (has_systemd_resolved) { diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c index 00fa6617b5..1c4be50d54 100644 --- a/src/nm-dbus-manager.c +++ b/src/nm-dbus-manager.c @@ -28,6 +28,7 @@ #include <sys/types.h> #include "c-list/src/c-list.h" +#include "nm-utils/nm-c-list.h" #include "nm-dbus-interface.h" #include "nm-core-internal.h" #include "nm-dbus-compat.h" @@ -44,6 +45,17 @@ /*****************************************************************************/ 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]; +} CallerInfo; + +typedef struct { GVariant *value; } PropertyCacheData; @@ -78,8 +90,10 @@ typedef struct { NMDBusManagerSetPropertyHandler set_property_handler; gpointer set_property_handler_data; - GDBusConnection *connection; - GDBusProxy *proxy; + GDBusConnection *main_dbus_connection; + + CList caller_info_lst_head; + guint objmgr_registration_id; bool started:1; bool shutting_down:1; @@ -441,21 +455,33 @@ private_server_get_connection_by_owner (PrivateServer *s, const char *owner) /*****************************************************************************/ +static void +_caller_info_free (CallerInfo *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, - GError **error) + gulong *out_pid) { + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); guint32 unix_pid = G_MAXUINT32; gs_unref_variant GVariant *ret = NULL; - ret = _nm_dbus_proxy_call_sync (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, - "GetConnectionUnixProcessID", - g_variant_new ("(s)", sender), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, 2000, - NULL, error); + 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; @@ -468,18 +494,23 @@ _bus_get_unix_pid (NMDBusManager *self, static gboolean _bus_get_unix_user (NMDBusManager *self, const char *sender, - gulong *out_user, - GError **error) + gulong *out_user) { + NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); guint32 unix_uid = G_MAXUINT32; gs_unref_variant GVariant *ret = NULL; - ret = _nm_dbus_proxy_call_sync (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, - "GetConnectionUnixUser", - g_variant_new ("(s)", sender), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, 2000, - NULL, error); + 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; @@ -489,34 +520,102 @@ _bus_get_unix_user (NMDBusManager *self, return TRUE; } -/** - * _get_caller_info(): - * - * Given a GDBus method invocation, or a GDBusConnection + GDBusMessage, - * return the sender and the UID of the sender. - */ +static const CallerInfo * +_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_NS_PER_SECOND * 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_ns (); + + 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, - char **out_sender, + 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 { - g_assert (message); + nm_assert (G_IS_DBUS_MESSAGE (message)); sender = g_dbus_message_get_sender (message); } - g_assert (connection); + nm_assert (G_IS_DBUS_CONNECTION (connection)); if (!sender) { PrivateServer *s; @@ -525,10 +624,8 @@ _get_caller_info (NMDBusManager *self, c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) { sender = private_server_get_connection_owner (s, connection); if (sender) { - if (out_uid) - *out_uid = 0; - if (out_sender) - *out_sender = g_strdup (sender); + NM_SET_OUT (out_uid, 0); + NM_SET_OUT (out_sender, sender); if (out_pid) { GCredentials *creds; @@ -547,35 +644,29 @@ _get_caller_info (NMDBusManager *self, return TRUE; } } + NM_SET_OUT (out_sender, NULL); + NM_SET_OUT (out_uid, G_MAXULONG); + NM_SET_OUT (out_pid, G_MAXULONG); return FALSE; } - /* Bus connections always have a sender */ - g_assert (sender); - if (out_uid) { - if (!_bus_get_unix_user (self, sender, out_uid, NULL)) { - *out_uid = G_MAXULONG; - return FALSE; - } - } - - if (out_pid) { - if (!_bus_get_unix_pid (self, sender, out_pid, NULL)) { - *out_pid = G_MAXULONG; - return FALSE; - } - } + caller_info = _get_caller_info_ensure (self, sender, !!out_uid, !!out_pid); - if (out_sender) - *out_sender = g_strdup (sender); + 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, - char **out_sender, + const char **out_sender, gulong *out_uid, gulong *out_pid) { @@ -586,7 +677,7 @@ gboolean nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, GDBusConnection *connection, GDBusMessage *message, - char **out_sender, + const char **out_sender, gulong *out_uid, gulong *out_pid) { @@ -647,8 +738,8 @@ nm_dbus_manager_get_unix_user (NMDBusManager *self, gulong *out_uid) { NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); + const CallerInfo *caller_info; PrivateServer *s; - GError *error = NULL; g_return_val_if_fail (sender != NULL, FALSE); g_return_val_if_fail (out_uid != NULL, FALSE); @@ -665,13 +756,12 @@ nm_dbus_manager_get_unix_user (NMDBusManager *self, } /* Otherwise, a bus connection */ - if (!_bus_get_unix_user (self, sender, out_uid, &error)) { - _LOGW ("failed to get unix user for dbus sender '%s': %s", - sender, error->message); - g_error_free (error); + 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; } @@ -757,16 +847,6 @@ nm_dbus_manager_new_proxy (NMDBusManager *self, /*****************************************************************************/ -GDBusConnection * -nm_dbus_manager_get_connection (NMDBusManager *self) -{ - g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL); - - return NM_DBUS_MANAGER_GET_PRIVATE (self)->connection; -} - -/*****************************************************************************/ - static const NMDBusInterfaceInfoExtended * _reg_data_get_interface_info (RegistrationData *reg_data) { @@ -943,7 +1023,7 @@ _obj_register (NMDBusManager *self, GVariantBuilder builder; nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); - nm_assert (priv->connection); + nm_assert (priv->main_dbus_connection); nm_assert (priv->started); n_klasses = 0; @@ -980,7 +1060,7 @@ _obj_register (NMDBusManager *self, reg_data = g_malloc0 (sizeof (RegistrationData) + (sizeof (PropertyCacheData) * prop_len)); - registration_id = g_dbus_connection_register_object (priv->connection, + registration_id = g_dbus_connection_register_object (priv->main_dbus_connection, obj->internal.path, NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info->parent), &dbus_vtable, @@ -1019,7 +1099,7 @@ _obj_register (NMDBusManager *self, * * 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->connection, + g_dbus_connection_emit_signal (priv->main_dbus_connection, NULL, OBJECT_MANAGER_SERVER_BASE_PATH, interface_info_objmgr.name, @@ -1040,7 +1120,7 @@ _obj_unregister (NMDBusManager *self, nm_assert (NM_IS_DBUS_OBJECT (obj)); - if (!priv->connection) { + if (!priv->main_dbus_connection) { /* nothing to do for the moment. */ nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); return; @@ -1059,7 +1139,7 @@ _obj_unregister (NMDBusManager *self, "s", interface_info->parent.name); c_list_unlink_stale (®_data->registration_lst); - if (!g_dbus_connection_unregister_object (priv->connection, reg_data->registration_id)) + if (!g_dbus_connection_unregister_object (priv->main_dbus_connection, reg_data->registration_id)) nm_assert_not_reached (); if (interface_info->parent.properties) { @@ -1071,7 +1151,7 @@ _obj_unregister (NMDBusManager *self, g_free (reg_data); } - g_dbus_connection_emit_signal (priv->connection, + g_dbus_connection_emit_signal (priv->main_dbus_connection, NULL, OBJECT_MANAGER_SERVER_BASE_PATH, interface_info_objmgr.name, @@ -1122,7 +1202,7 @@ _nm_dbus_manager_obj_export (NMDBusObject *obj) nm_assert_not_reached (); c_list_link_tail (&priv->objects_lst_head, &obj->internal.objects_lst); - if (priv->connection && priv->started) + if (priv->main_dbus_connection && priv->started) _obj_register (self, obj); } @@ -1239,7 +1319,7 @@ _nm_dbus_manager_obj_notify (NMDBusObject *obj, } g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as")); - g_dbus_connection_emit_signal (priv->connection, + g_dbus_connection_emit_signal (priv->main_dbus_connection, NULL, obj->internal.path, "org.freedesktop.DBus.Properties", @@ -1255,7 +1335,7 @@ _nm_dbus_manager_obj_notify (NMDBusObject *obj, /* 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->connection, + g_dbus_connection_emit_signal (priv->main_dbus_connection, NULL, obj->internal.path, nm_interface_info_device_statistics.parent.name, @@ -1292,7 +1372,7 @@ _nm_dbus_manager_obj_notify (NMDBusObject *obj, const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data); if (interface_info->legacy_property_changed) { - g_dbus_connection_emit_signal (priv->connection, + g_dbus_connection_emit_signal (priv->main_dbus_connection, NULL, obj->internal.path, interface_info->parent.name, @@ -1321,12 +1401,12 @@ _nm_dbus_manager_obj_emit_signal (NMDBusObject *obj, self = obj->internal.bus_manager; priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - if (!priv->connection || !priv->started) { + if (!priv->main_dbus_connection || !priv->started) { nm_g_variant_unref_floating (args); return; } - g_dbus_connection_emit_signal (priv->connection, + g_dbus_connection_emit_signal (priv->main_dbus_connection, NULL, obj->internal.path, interface_info->parent.name, @@ -1473,7 +1553,7 @@ nm_dbus_manager_get_dbus_connection (NMDBusManager *self) { g_return_val_if_fail (NM_IS_DBUS_MANAGER (self), NULL); - return NM_DBUS_MANAGER_GET_PRIVATE (self)->connection; + return NM_DBUS_MANAGER_GET_PRIVATE (self)->main_dbus_connection; } void @@ -1487,7 +1567,7 @@ nm_dbus_manager_start (NMDBusManager *self, g_return_if_fail (NM_IS_DBUS_MANAGER (self)); priv = NM_DBUS_MANAGER_GET_PRIVATE (self); - if (!priv->connection) { + if (!priv->main_dbus_connection) { /* Do nothing. We're presumably in the configure-and-quit mode. */ return; } @@ -1507,7 +1587,6 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self) gs_free_error GError *error = NULL; gs_unref_variant GVariant *ret = NULL; gs_unref_object GDBusConnection *connection = NULL; - gs_unref_object GDBusProxy *proxy = NULL; guint32 result; guint registration_id; @@ -1530,20 +1609,6 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self) g_dbus_connection_set_exit_on_close (connection, FALSE); - proxy = g_dbus_proxy_new_sync (connection, - G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, - NULL, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - NULL, - &error); - if (!proxy) { - _LOGE ("fatal failure to initialize D-Bus: %s", error->message); - return FALSE; - } - registration_id = g_dbus_connection_register_object (connection, OBJECT_MANAGER_SERVER_BASE_PATH, NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info_objmgr), @@ -1556,15 +1621,22 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self) return FALSE; } - ret = _nm_dbus_proxy_call_sync (proxy, - "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); + ret = g_dbus_connection_call_sync (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) + return FALSE; + if (!ret) { _LOGE ("fatal failure to acquire D-Bus service \"%s"": %s", NM_DBUS_SERVICE, error->message); @@ -1581,8 +1653,7 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self) } priv->objmgr_registration_id = registration_id; - priv->connection = g_steal_pointer (&connection); - priv->proxy = g_steal_pointer (&proxy); + priv->main_dbus_connection = g_steal_pointer (&connection); _LOGI ("acquired D-Bus service \"%s\"", NM_DBUS_SERVICE); @@ -1620,6 +1691,8 @@ nm_dbus_manager_init (NMDBusManager *self) 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); + + c_list_init (&priv->caller_info_lst_head); } static void @@ -1628,6 +1701,7 @@ dispose (GObject *object) 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. */ @@ -1640,14 +1714,16 @@ dispose (GObject *object) private_server_free (s); if (priv->objmgr_registration_id) { - g_dbus_connection_unregister_object (priv->connection, + g_dbus_connection_unregister_object (priv->main_dbus_connection, nm_steal_int (&priv->objmgr_registration_id)); } - g_clear_object (&priv->proxy); - g_clear_object (&priv->connection); + g_clear_object (&priv->main_dbus_connection); 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); } static void diff --git a/src/nm-dbus-manager.h b/src/nm-dbus-manager.h index 89acd7c855..2de6ff0ba7 100644 --- a/src/nm-dbus-manager.h +++ b/src/nm-dbus-manager.h @@ -61,8 +61,6 @@ void nm_dbus_manager_stop (NMDBusManager *self); gboolean nm_dbus_manager_is_stopping (NMDBusManager *self); -GDBusConnection *nm_dbus_manager_get_connection (NMDBusManager *self); - gpointer nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path); void _nm_dbus_manager_obj_export (NMDBusObject *obj); @@ -77,7 +75,7 @@ void _nm_dbus_manager_obj_emit_signal (NMDBusObject *obj, gboolean nm_dbus_manager_get_caller_info (NMDBusManager *self, GDBusMethodInvocation *context, - char **out_sender, + const char **out_sender, gulong *out_uid, gulong *out_pid); @@ -97,7 +95,7 @@ gboolean nm_dbus_manager_get_unix_user (NMDBusManager *self, gboolean nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, GDBusConnection *connection, GDBusMessage *message, - char **out_sender, + const char **out_sender, gulong *out_uid, gulong *out_pid); |