sudo: introduce nm-sudo D-Bus service
NetworkManager runs as root and has lots of capabilities.
We want to reduce the attach surface by dropping capabilities,
but there is a genuine need to do certain things.
For example, we currently require dac_override capability, to open
the unix socket of ovsdb. Most users wouldn't use OVS, so we should
find a way to not require that dac_override capability. The solution
is to have a separate, D-Bus activate service (nm-sudo), which
has the capability to open and provide the file descriptor.
For authentication, we only rely on D-Bus. We watch the name owner
of NetworkManager, and only accept requests from that service. We trust
D-Bus to get it right a request from that name owner is really coming
from NetworkManager. If we couldn't trust that, how could PolicyKit
or any authentication via D-Bus work? For testing, the user can set
NM_SUDO_NO_AUTH_FOR_TESTING=1.
https://bugzilla.redhat.com/show_bug.cgi?id=1921826
2021-07-18 08:53:43 +02:00
|
|
|
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
|
|
|
|
|
|
|
|
|
#include "src/core/nm-default-daemon.h"
|
|
|
|
|
|
|
|
|
|
#include "nm-sudo-call.h"
|
2021-07-21 16:31:48 +02:00
|
|
|
|
|
|
|
|
#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));
|
|
|
|
|
}
|