dns,dbus: merge branch 'th/systemd-resolved-dbus-activated'

https://github.com/NetworkManager/NetworkManager/pull/336
This commit is contained in:
Thomas Haller 2019-04-09 20:40:42 +02:00
commit 3a2e002a2e
7 changed files with 435 additions and 182 deletions

View file

@ -347,13 +347,20 @@ gboolean
nm_dns_manager_has_systemd_resolved (NMDnsManager *self) nm_dns_manager_has_systemd_resolved (NMDnsManager *self)
{ {
NMDnsManagerPrivate *priv; NMDnsManagerPrivate *priv;
NMDnsSystemdResolved *plugin = NULL;
g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE); g_return_val_if_fail (NM_IS_DNS_MANAGER (self), FALSE);
priv = NM_DNS_MANAGER_GET_PRIVATE (self); priv = NM_DNS_MANAGER_GET_PRIVATE (self);
return priv->sd_resolve_plugin if (priv->sd_resolve_plugin) {
|| NM_IS_DNS_SYSTEMD_RESOLVED (priv->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);
} }
/*****************************************************************************/ /*****************************************************************************/

View file

@ -42,9 +42,11 @@
#include "nm-setting-connection.h" #include "nm-setting-connection.h"
#include "devices/nm-device.h" #include "devices/nm-device.h"
#include "NetworkManagerUtils.h" #include "NetworkManagerUtils.h"
#include "nm-dbus-compat.h"
#define SYSTEMD_RESOLVED_DBUS_SERVICE "org.freedesktop.resolve1" #define SYSTEMD_RESOLVED_DBUS_SERVICE "org.freedesktop.resolve1"
#define SYSTEMD_RESOLVED_DBUS_PATH "/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 { typedef struct {
GDBusProxy *resolve; GDBusConnection *dbus_connection;
GCancellable *init_cancellable; GCancellable *cancellable;
GCancellable *update_cancellable;
CList request_queue_lst_head; 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; } NMDnsSystemdResolvedPrivate;
struct _NMDnsSystemdResolved { struct _NMDnsSystemdResolved {
@ -121,16 +127,26 @@ _interface_config_free (InterfaceConfig *config)
static void static void
call_done (GObject *source, GAsyncResult *r, gpointer user_data) call_done (GObject *source, GAsyncResult *r, gpointer user_data)
{ {
GVariant *v; gs_unref_variant GVariant *v = NULL;
gs_free_error GError *error = NULL; gs_free_error GError *error = NULL;
NMDnsSystemdResolved *self = (NMDnsSystemdResolved *) user_data; 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 (!v) {
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) if (!priv->send_updates_warn_ratelimited) {
return; priv->send_updates_warn_ratelimited = TRUE;
_LOGW ("Failed: %s", error->message); _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 static void
@ -174,12 +190,11 @@ static void
free_pending_updates (NMDnsSystemdResolved *self) free_pending_updates (NMDnsSystemdResolved *self)
{ {
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (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, while ((request_item = c_list_first_entry (&priv->request_queue_lst_head,
request_item_safe, RequestItem,
&priv->request_queue_lst_head, request_queue_lst)))
request_queue_lst)
_request_item_free (request_item); _request_item_free (request_item);
} }
@ -266,27 +281,74 @@ static void
send_updates (NMDnsSystemdResolved *self) send_updates (NMDnsSystemdResolved *self)
{ {
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self);
RequestItem *request_item, *request_item_safe; RequestItem *request_item;
nm_clear_g_cancellable (&priv->update_cancellable); if (c_list_is_empty (&priv->request_queue_lst_head)) {
/* nothing to do. */
if (!priv->resolve)
return; return;
}
priv->update_cancellable = g_cancellable_new (); if (!priv->dbus_initied) {
_LOGT ("send-updates: D-Bus connection not ready");
return;
}
c_list_for_each_entry_safe (request_item, if (!priv->dbus_has_owner) {
request_item_safe, if (priv->try_start_blocked) {
&priv->request_queue_lst_head, /* we have no name owner and we already tried poking the service to
request_queue_lst) { * autostart. */
g_dbus_proxy_call (priv->resolve, _LOGT ("send-updates: no name owner");
request_item->operation, return;
request_item->argument, }
G_DBUS_CALL_FLAGS_NONE,
-1, _LOGT ("send-updates: no name owner. Try start service...");
priv->update_cancellable, priv->try_start_blocked = TRUE;
call_done,
self); 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;
}
_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); _request_item_free (request_item);
} }
} }
@ -360,28 +422,100 @@ get_name (NMDnsPlugin *plugin)
/*****************************************************************************/ /*****************************************************************************/
static void 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);
NMDnsSystemdResolvedPrivate *priv;
gs_free_error GError *error = NULL;
GDBusProxy *resolve;
resolve = g_dbus_proxy_new_finish (r, &error); owner = nm_str_not_empty (owner);
if ( !resolve
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;
const char *owner = NULL;
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)) && g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
return; return;
priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); if (ret)
g_clear_object (&priv->init_cancellable); g_variant_get (ret, "(&s)", &owner);
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; self = user_data;
send_updates (self); priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (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); c_list_init (&priv->request_queue_lst_head);
priv->init_cancellable = g_cancellable_new (); priv->dbus_connection = nm_g_object_ref (nm_dbus_manager_get_dbus_connection (nm_dbus_manager_get ()));
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM, if (!priv->dbus_connection) {
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | _LOGD ("no D-Bus connection");
G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, return;
NULL, }
SYSTEMD_RESOLVED_DBUS_SERVICE,
SYSTEMD_RESOLVED_DBUS_PATH, priv->name_owner_changed_id = g_dbus_connection_signal_subscribe (priv->dbus_connection,
SYSTEMD_RESOLVED_DBUS_SERVICE ".Manager", DBUS_SERVICE_DBUS,
priv->init_cancellable, DBUS_INTERFACE_DBUS,
resolved_proxy_created, "NameOwnerChanged",
self); 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 * NMDnsPlugin *
@ -419,9 +571,15 @@ dispose (GObject *object)
NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self); NMDnsSystemdResolvedPrivate *priv = NM_DNS_SYSTEMD_RESOLVED_GET_PRIVATE (self);
free_pending_updates (self); free_pending_updates (self);
g_clear_object (&priv->resolve);
nm_clear_g_cancellable (&priv->init_cancellable); if (priv->name_owner_changed_id != 0) {
nm_clear_g_cancellable (&priv->update_cancellable); 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); G_OBJECT_CLASS (nm_dns_systemd_resolved_parent_class)->dispose (object);
} }

View file

@ -36,4 +36,6 @@ GType nm_dns_systemd_resolved_get_type (void);
NMDnsPlugin *nm_dns_systemd_resolved_new (void); NMDnsPlugin *nm_dns_systemd_resolved_new (void);
gboolean nm_dns_systemd_resolved_is_running (NMDnsSystemdResolved *self);
#endif /* __NETWORKMANAGER_DNS_SYSTEMD_RESOLVED_H__ */ #endif /* __NETWORKMANAGER_DNS_SYSTEMD_RESOLVED_H__ */

View file

@ -173,9 +173,10 @@ _new_unix_process (GDBusMethodInvocation *context,
GDBusMessage *message) GDBusMessage *message)
{ {
NMAuthSubject *self; NMAuthSubject *self;
gboolean success = FALSE; const char *dbus_sender = NULL;
gulong pid = 0, uid = 0; gulong uid = 0;
gs_free char *dbus_sender = NULL; gulong pid = 0;
gboolean success;
g_return_val_if_fail (context || (connection && message), NULL); g_return_val_if_fail (context || (connection && message), NULL);

View file

@ -840,7 +840,18 @@ nm_connectivity_check_start (NMConnectivity *self,
* *
* Yes, this makes NMConnectivity singleton dependent on NMDnsManager singleton. * Yes, this makes NMConnectivity singleton dependent on NMDnsManager singleton.
* Well, not really: it makes connectivity-check-start dependent on NMDnsManager * 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 ()); has_systemd_resolved = nm_dns_manager_has_systemd_resolved (nm_dns_manager_get ());
if (has_systemd_resolved) { if (has_systemd_resolved) {

View file

@ -28,6 +28,7 @@
#include <sys/types.h> #include <sys/types.h>
#include "c-list/src/c-list.h" #include "c-list/src/c-list.h"
#include "nm-utils/nm-c-list.h"
#include "nm-dbus-interface.h" #include "nm-dbus-interface.h"
#include "nm-core-internal.h" #include "nm-core-internal.h"
#include "nm-dbus-compat.h" #include "nm-dbus-compat.h"
@ -43,6 +44,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 { typedef struct {
GVariant *value; GVariant *value;
} PropertyCacheData; } PropertyCacheData;
@ -78,8 +90,10 @@ typedef struct {
NMDBusManagerSetPropertyHandler set_property_handler; NMDBusManagerSetPropertyHandler set_property_handler;
gpointer set_property_handler_data; gpointer set_property_handler_data;
GDBusConnection *connection; GDBusConnection *main_dbus_connection;
GDBusProxy *proxy;
CList caller_info_lst_head;
guint objmgr_registration_id; guint objmgr_registration_id;
bool started:1; bool started:1;
bool shutting_down: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 static gboolean
_bus_get_unix_pid (NMDBusManager *self, _bus_get_unix_pid (NMDBusManager *self,
const char *sender, const char *sender,
gulong *out_pid, gulong *out_pid)
GError **error)
{ {
NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
guint32 unix_pid = G_MAXUINT32; guint32 unix_pid = G_MAXUINT32;
gs_unref_variant GVariant *ret = NULL; gs_unref_variant GVariant *ret = NULL;
ret = _nm_dbus_proxy_call_sync (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, ret = g_dbus_connection_call_sync (priv->main_dbus_connection,
"GetConnectionUnixProcessID", DBUS_SERVICE_DBUS,
g_variant_new ("(s)", sender), DBUS_PATH_DBUS,
G_VARIANT_TYPE ("(u)"), DBUS_INTERFACE_DBUS,
G_DBUS_CALL_FLAGS_NONE, 2000, "GetConnectionUnixProcessID",
NULL, error); g_variant_new ("(s)", sender),
G_VARIANT_TYPE ("(u)"),
G_DBUS_CALL_FLAGS_NONE,
2000,
NULL,
NULL);
if (!ret) if (!ret)
return FALSE; return FALSE;
@ -468,18 +494,23 @@ _bus_get_unix_pid (NMDBusManager *self,
static gboolean static gboolean
_bus_get_unix_user (NMDBusManager *self, _bus_get_unix_user (NMDBusManager *self,
const char *sender, const char *sender,
gulong *out_user, gulong *out_user)
GError **error)
{ {
NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
guint32 unix_uid = G_MAXUINT32; guint32 unix_uid = G_MAXUINT32;
gs_unref_variant GVariant *ret = NULL; gs_unref_variant GVariant *ret = NULL;
ret = _nm_dbus_proxy_call_sync (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy, ret = g_dbus_connection_call_sync (priv->main_dbus_connection,
"GetConnectionUnixUser", DBUS_SERVICE_DBUS,
g_variant_new ("(s)", sender), DBUS_PATH_DBUS,
G_VARIANT_TYPE ("(u)"), DBUS_INTERFACE_DBUS,
G_DBUS_CALL_FLAGS_NONE, 2000, "GetConnectionUnixUser",
NULL, error); g_variant_new ("(s)", sender),
G_VARIANT_TYPE ("(u)"),
G_DBUS_CALL_FLAGS_NONE,
2000,
NULL,
NULL);
if (!ret) if (!ret)
return FALSE; return FALSE;
@ -489,34 +520,102 @@ _bus_get_unix_user (NMDBusManager *self,
return TRUE; return TRUE;
} }
/** static const CallerInfo *
* _get_caller_info(): _get_caller_info_ensure (NMDBusManager *self,
* const char *sender,
* Given a GDBus method invocation, or a GDBusConnection + GDBusMessage, gboolean ensure_uid,
* return the sender and the UID of the sender. 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 static gboolean
_get_caller_info (NMDBusManager *self, _get_caller_info (NMDBusManager *self,
GDBusMethodInvocation *context, GDBusMethodInvocation *context,
GDBusConnection *connection, GDBusConnection *connection,
GDBusMessage *message, GDBusMessage *message,
char **out_sender, const char **out_sender,
gulong *out_uid, gulong *out_uid,
gulong *out_pid) gulong *out_pid)
{ {
NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
const CallerInfo *caller_info;
const char *sender; const char *sender;
if (context) { if (context) {
nm_assert (G_IS_DBUS_METHOD_INVOCATION (context));
connection = g_dbus_method_invocation_get_connection (context); connection = g_dbus_method_invocation_get_connection (context);
/* only bus connections will have a sender */ /* only bus connections will have a sender */
sender = g_dbus_method_invocation_get_sender (context); sender = g_dbus_method_invocation_get_sender (context);
} else { } else {
g_assert (message); nm_assert (G_IS_DBUS_MESSAGE (message));
sender = g_dbus_message_get_sender (message); sender = g_dbus_message_get_sender (message);
} }
g_assert (connection); nm_assert (G_IS_DBUS_CONNECTION (connection));
if (!sender) { if (!sender) {
PrivateServer *s; 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) { c_list_for_each_entry (s, &priv->private_servers_lst_head, private_servers_lst) {
sender = private_server_get_connection_owner (s, connection); sender = private_server_get_connection_owner (s, connection);
if (sender) { if (sender) {
if (out_uid) NM_SET_OUT (out_uid, 0);
*out_uid = 0; NM_SET_OUT (out_sender, sender);
if (out_sender)
*out_sender = g_strdup (sender);
if (out_pid) { if (out_pid) {
GCredentials *creds; GCredentials *creds;
@ -547,35 +644,29 @@ _get_caller_info (NMDBusManager *self,
return TRUE; return TRUE;
} }
} }
NM_SET_OUT (out_sender, NULL);
NM_SET_OUT (out_uid, G_MAXULONG);
NM_SET_OUT (out_pid, G_MAXULONG);
return FALSE; return FALSE;
} }
/* Bus connections always have a sender */ caller_info = _get_caller_info_ensure (self, sender, !!out_uid, !!out_pid);
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) { NM_SET_OUT (out_sender, caller_info->sender);
if (!_bus_get_unix_pid (self, sender, out_pid, NULL)) { NM_SET_OUT (out_uid, caller_info->uid);
*out_pid = G_MAXULONG; NM_SET_OUT (out_pid, caller_info->pid);
return FALSE;
}
}
if (out_sender)
*out_sender = g_strdup (sender);
if (out_uid && !caller_info->uid_valid)
return FALSE;
if (out_pid && !caller_info->pid_valid)
return FALSE;
return TRUE; return TRUE;
} }
gboolean gboolean
nm_dbus_manager_get_caller_info (NMDBusManager *self, nm_dbus_manager_get_caller_info (NMDBusManager *self,
GDBusMethodInvocation *context, GDBusMethodInvocation *context,
char **out_sender, const char **out_sender,
gulong *out_uid, gulong *out_uid,
gulong *out_pid) gulong *out_pid)
{ {
@ -586,7 +677,7 @@ gboolean
nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self, nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self,
GDBusConnection *connection, GDBusConnection *connection,
GDBusMessage *message, GDBusMessage *message,
char **out_sender, const char **out_sender,
gulong *out_uid, gulong *out_uid,
gulong *out_pid) gulong *out_pid)
{ {
@ -647,8 +738,8 @@ nm_dbus_manager_get_unix_user (NMDBusManager *self,
gulong *out_uid) gulong *out_uid)
{ {
NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
const CallerInfo *caller_info;
PrivateServer *s; PrivateServer *s;
GError *error = NULL;
g_return_val_if_fail (sender != NULL, FALSE); g_return_val_if_fail (sender != NULL, FALSE);
g_return_val_if_fail (out_uid != 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 */ /* Otherwise, a bus connection */
if (!_bus_get_unix_user (self, sender, out_uid, &error)) { caller_info = _get_caller_info_ensure (self, sender, TRUE, FALSE);
_LOGW ("failed to get unix user for dbus sender '%s': %s", *out_uid = caller_info->uid;
sender, error->message); if (!caller_info->uid_valid) {
g_error_free (error); _LOGW ("failed to get unix user for dbus sender '%s'", sender);
return FALSE; return FALSE;
} }
return TRUE; 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 * static const NMDBusInterfaceInfoExtended *
_reg_data_get_interface_info (RegistrationData *reg_data) _reg_data_get_interface_info (RegistrationData *reg_data)
{ {
@ -943,7 +1023,7 @@ _obj_register (NMDBusManager *self,
GVariantBuilder builder; GVariantBuilder builder;
nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); 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); nm_assert (priv->started);
n_klasses = 0; n_klasses = 0;
@ -980,7 +1060,7 @@ _obj_register (NMDBusManager *self,
reg_data = g_malloc0 (sizeof (RegistrationData) + (sizeof (PropertyCacheData) * prop_len)); 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, obj->internal.path,
NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info->parent), NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info->parent),
&dbus_vtable, &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 * 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. */ * 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, NULL,
OBJECT_MANAGER_SERVER_BASE_PATH, OBJECT_MANAGER_SERVER_BASE_PATH,
interface_info_objmgr.name, interface_info_objmgr.name,
@ -1040,7 +1120,7 @@ _obj_unregister (NMDBusManager *self,
nm_assert (NM_IS_DBUS_OBJECT (obj)); nm_assert (NM_IS_DBUS_OBJECT (obj));
if (!priv->connection) { if (!priv->main_dbus_connection) {
/* nothing to do for the moment. */ /* nothing to do for the moment. */
nm_assert (c_list_is_empty (&obj->internal.registration_lst_head)); nm_assert (c_list_is_empty (&obj->internal.registration_lst_head));
return; return;
@ -1059,7 +1139,7 @@ _obj_unregister (NMDBusManager *self,
"s", "s",
interface_info->parent.name); interface_info->parent.name);
c_list_unlink_stale (&reg_data->registration_lst); c_list_unlink_stale (&reg_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 (); nm_assert_not_reached ();
if (interface_info->parent.properties) { if (interface_info->parent.properties) {
@ -1071,7 +1151,7 @@ _obj_unregister (NMDBusManager *self,
g_free (reg_data); g_free (reg_data);
} }
g_dbus_connection_emit_signal (priv->connection, g_dbus_connection_emit_signal (priv->main_dbus_connection,
NULL, NULL,
OBJECT_MANAGER_SERVER_BASE_PATH, OBJECT_MANAGER_SERVER_BASE_PATH,
interface_info_objmgr.name, interface_info_objmgr.name,
@ -1122,7 +1202,7 @@ _nm_dbus_manager_obj_export (NMDBusObject *obj)
nm_assert_not_reached (); nm_assert_not_reached ();
c_list_link_tail (&priv->objects_lst_head, &obj->internal.objects_lst); 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); _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_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, NULL,
obj->internal.path, obj->internal.path,
"org.freedesktop.DBus.Properties", "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, /* this is a special interface: it has a legacy PropertiesChanged signal,
* however, contrary to other interfaces with ~regular~ legacy signals, * however, contrary to other interfaces with ~regular~ legacy signals,
* we only notify about properties that actually belong to this interface. */ * 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, NULL,
obj->internal.path, obj->internal.path,
nm_interface_info_device_statistics.parent.name, 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); const NMDBusInterfaceInfoExtended *interface_info = _reg_data_get_interface_info (reg_data);
if (interface_info->legacy_property_changed) { if (interface_info->legacy_property_changed) {
g_dbus_connection_emit_signal (priv->connection, g_dbus_connection_emit_signal (priv->main_dbus_connection,
NULL, NULL,
obj->internal.path, obj->internal.path,
interface_info->parent.name, interface_info->parent.name,
@ -1321,12 +1401,12 @@ _nm_dbus_manager_obj_emit_signal (NMDBusObject *obj,
self = obj->internal.bus_manager; self = obj->internal.bus_manager;
priv = NM_DBUS_MANAGER_GET_PRIVATE (self); 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); nm_g_variant_unref_floating (args);
return; return;
} }
g_dbus_connection_emit_signal (priv->connection, g_dbus_connection_emit_signal (priv->main_dbus_connection,
NULL, NULL,
obj->internal.path, obj->internal.path,
interface_info->parent.name, 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); 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 void
@ -1487,7 +1567,7 @@ nm_dbus_manager_start (NMDBusManager *self,
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);
if (!priv->connection) { if (!priv->main_dbus_connection) {
/* Do nothing. We're presumably in the configure-and-quit mode. */ /* Do nothing. We're presumably in the configure-and-quit mode. */
return; return;
} }
@ -1507,7 +1587,6 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self)
gs_free_error GError *error = NULL; gs_free_error GError *error = NULL;
gs_unref_variant GVariant *ret = NULL; gs_unref_variant GVariant *ret = NULL;
gs_unref_object GDBusConnection *connection = NULL; gs_unref_object GDBusConnection *connection = NULL;
gs_unref_object GDBusProxy *proxy = NULL;
guint32 result; guint32 result;
guint registration_id; guint registration_id;
@ -1530,20 +1609,6 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self)
g_dbus_connection_set_exit_on_close (connection, FALSE); 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, registration_id = g_dbus_connection_register_object (connection,
OBJECT_MANAGER_SERVER_BASE_PATH, OBJECT_MANAGER_SERVER_BASE_PATH,
NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info_objmgr), NM_UNCONST_PTR (GDBusInterfaceInfo, &interface_info_objmgr),
@ -1556,15 +1621,22 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self)
return FALSE; return FALSE;
} }
ret = _nm_dbus_proxy_call_sync (proxy, ret = g_dbus_connection_call_sync (connection,
"RequestName", DBUS_SERVICE_DBUS,
g_variant_new ("(su)", DBUS_PATH_DBUS,
NM_DBUS_SERVICE, DBUS_INTERFACE_DBUS,
DBUS_NAME_FLAG_DO_NOT_QUEUE), "RequestName",
G_VARIANT_TYPE ("(u)"), g_variant_new ("(su)",
G_DBUS_CALL_FLAGS_NONE, -1, NM_DBUS_SERVICE,
NULL, DBUS_NAME_FLAG_DO_NOT_QUEUE),
&error); G_VARIANT_TYPE ("(u)"),
G_DBUS_CALL_FLAGS_NONE,
-1,
NULL,
&error);
if (!ret)
return FALSE;
if (!ret) { if (!ret) {
_LOGE ("fatal failure to acquire D-Bus service \"%s"": %s", _LOGE ("fatal failure to acquire D-Bus service \"%s"": %s",
NM_DBUS_SERVICE, error->message); NM_DBUS_SERVICE, error->message);
@ -1581,8 +1653,7 @@ nm_dbus_manager_acquire_bus (NMDBusManager *self)
} }
priv->objmgr_registration_id = registration_id; priv->objmgr_registration_id = registration_id;
priv->connection = g_steal_pointer (&connection); priv->main_dbus_connection = g_steal_pointer (&connection);
priv->proxy = g_steal_pointer (&proxy);
_LOGI ("acquired D-Bus service \"%s\"", NM_DBUS_SERVICE); _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->private_servers_lst_head);
c_list_init (&priv->objects_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);
} }
static void static void
@ -1628,6 +1701,7 @@ dispose (GObject *object)
NMDBusManager *self = NM_DBUS_MANAGER (object); NMDBusManager *self = NM_DBUS_MANAGER (object);
NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self); NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
PrivateServer *s, *s_safe; PrivateServer *s, *s_safe;
CallerInfo *caller_info;
/* All exported NMDBusObject instances keep the manager alive, so we don't /* All exported NMDBusObject instances keep the manager alive, so we don't
* expect any remaining objects. */ * expect any remaining objects. */
@ -1640,14 +1714,16 @@ dispose (GObject *object)
private_server_free (s); private_server_free (s);
if (priv->objmgr_registration_id) { 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)); nm_steal_int (&priv->objmgr_registration_id));
} }
g_clear_object (&priv->proxy); g_clear_object (&priv->main_dbus_connection);
g_clear_object (&priv->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);
} }
static void static void

View file

@ -61,8 +61,6 @@ void nm_dbus_manager_stop (NMDBusManager *self);
gboolean nm_dbus_manager_is_stopping (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); gpointer nm_dbus_manager_lookup_object (NMDBusManager *self, const char *path);
void _nm_dbus_manager_obj_export (NMDBusObject *obj); 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, gboolean nm_dbus_manager_get_caller_info (NMDBusManager *self,
GDBusMethodInvocation *context, GDBusMethodInvocation *context,
char **out_sender, const char **out_sender,
gulong *out_uid, gulong *out_uid,
gulong *out_pid); 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, gboolean nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self,
GDBusConnection *connection, GDBusConnection *connection,
GDBusMessage *message, GDBusMessage *message,
char **out_sender, const char **out_sender,
gulong *out_uid, gulong *out_uid,
gulong *out_pid); gulong *out_pid);