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