NetworkManager/src/core/nm-sudo-call.c
Thomas Haller de5dddccbe
core: get file descriptor to ovsdb unix socket from nm-sudo
To talk to ovsdb, we use the unix socket at
/var/run/openvswitch/db.sock. But that socket is owned by another user
and NetworkManager would need dac_override capability to open it.

We want to drop dac_override, but we still need to talk to ovsdb. Add a
GetFD() method to nm-sudo.

We still first try to open the socket directly. Maybe it just works.

Note that SELinux may block passing file descriptors from nm-sudo. If it
doesn't work for you, test with SELinux permissive mode and wait for an
SELinux update.
2021-07-26 15:31:46 +02:00

99 lines
3.6 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include "src/core/nm-default-daemon.h"
#include "nm-sudo-call.h"
#include <gio/gunixfdlist.h>
#include "nm-dbus-manager.h"
/*****************************************************************************/
static void
_nm_sudo_call_get_fd_cb(GObject *source, GAsyncResult *res, gpointer user_data)
{
NMSudoCallGetFDCallback callback;
gpointer callback_data;
gs_unref_variant GVariant *ret = NULL;
gs_free_error GError *error = NULL;
gs_unref_object GUnixFDList *fd_list = NULL;
gs_free int * fd_arr = NULL;
nm_utils_user_data_unpack(user_data, &callback, &callback_data);
ret = g_dbus_connection_call_with_unix_fd_list_finish(G_DBUS_CONNECTION(source),
&fd_list,
res,
&error);
if (error) {
callback(-1, error, callback_data);
return;
}
if (!fd_list || g_unix_fd_list_get_length(fd_list) != 1) {
nm_utils_error_set(&error,
NM_UTILS_ERROR_UNKNOWN,
"Unexpectedly not one FD is returned by nm-sudo GetFD()");
callback(-1, error, callback_data);
return;
}
fd_arr = g_unix_fd_list_steal_fds(fd_list, NULL);
/* we transfer ownership of the file descriptor! */
callback(fd_arr[0], NULL, callback_data);
}
static gboolean
_nm_sudo_call_get_fd_fail_on_idle(gpointer user_data)
{
gs_unref_object GCancellable *cancellable = NULL;
NMSudoCallGetFDCallback callback;
gpointer callback_data;
gs_free_error GError *error = NULL;
nm_utils_user_data_unpack(user_data, &cancellable, &callback, &callback_data);
if (!g_cancellable_set_error_if_cancelled(cancellable, &error))
nm_utils_error_set(&error, NM_UTILS_ERROR_UNKNOWN, "Cannot talk to nm-sudo without D-Bus");
callback(-1, error, callback_data);
return G_SOURCE_REMOVE;
}
void
nm_sudo_call_get_fd(NMSudoGetFDType fd_type,
GCancellable * cancellable,
NMSudoCallGetFDCallback callback,
gpointer user_data)
{
GDBusConnection *dbus_connection;
nm_assert(NM_IN_SET(fd_type, NM_SUDO_GET_FD_TYPE_OVSDB_SOCKET));
nm_assert(!cancellable || G_IS_CANCELLABLE(cancellable));
nm_assert(callback);
dbus_connection = NM_MAIN_DBUS_CONNECTION_GET;
if (!dbus_connection) {
nm_g_idle_add(_nm_sudo_call_get_fd_fail_on_idle,
nm_utils_user_data_pack(g_object_ref(cancellable), callback, user_data));
return;
}
g_dbus_connection_call_with_unix_fd_list(dbus_connection,
NM_SUDO_DBUS_BUS_NAME,
NM_SUDO_DBUS_OBJECT_PATH,
NM_SUDO_DBUS_IFACE_NAME,
"GetFD",
g_variant_new("(u)", fd_type),
G_VARIANT_TYPE("()"),
G_DBUS_CALL_FLAGS_NONE,
10000,
NULL,
cancellable,
_nm_sudo_call_get_fd_cb,
nm_utils_user_data_pack(callback, user_data));
}