Blame src/nm-dbus-manager.c

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(&reg_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, &reg_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(&reg_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(&reg_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
}