mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-10-06 16:21:50 +00:00
auth: rework polkit autorization to use DBUS interface directly
This makes NetworkManager independent of <polkit/polkit.h> development headers and libpolkit-gobject-1.so library. Instead communicate directly with polkit using its DBUS interface. PolicyKit support is now always compiled in. You can control polkit authorization with the configuration option [main] auth-polkit=yes|no If the configure option is omitted, a build time default value is used. This default value can be set with the configure option --enable-polkit. This commit adds a new class NMAuthManager that reimplements the relevant DBUS client parts. It takes source code from the polkit library. https://bugzilla.gnome.org/show_bug.cgi?id=734146 Signed-off-by: Thomas Haller <thaller@redhat.com>
This commit is contained in:
parent
63a8c6a184
commit
eabe7d856c
32
configure.ac
32
configure.ac
|
@ -457,27 +457,21 @@ else
|
|||
fi
|
||||
AM_CONDITIONAL(WITH_TEAMDCTL, test "${enable_teamdctl}" = "yes")
|
||||
|
||||
PKG_CHECK_MODULES(POLKIT, [polkit-gobject-1 >= 0.97], [have_polkit=yes],[have_polkit=no])
|
||||
AC_ARG_ENABLE(polkit, AS_HELP_STRING([--enable-polkit], [enable PolicyKit support]),
|
||||
[enable_polkit=${enableval}], [enable_polkit=${have_polkit}])
|
||||
if (test "${enable_polkit}" = "yes"); then
|
||||
if test x"$have_polkit" = x"no"; then
|
||||
AC_MSG_ERROR(PolicyKit development headers are required)
|
||||
fi
|
||||
AC_SUBST(POLKIT_CFLAGS)
|
||||
AC_SUBST(POLKIT_LIBS)
|
||||
AC_DEFINE(WITH_POLKIT, 1, [Define if you have PolicyKit support])
|
||||
AC_ARG_ENABLE(polkit, AS_HELP_STRING([--enable-polkit], [set default value for auth-polkit configuration option]),
|
||||
[enable_polkit=${enableval}], [enable_polkit=yes])
|
||||
if (test "${enable_polkit}" != "no"); then
|
||||
enable_polkit=yes
|
||||
AC_DEFINE(NM_CONFIG_DEFAULT_AUTH_POLKIT, TRUE, [The default value of the auth-polkit configuration option])
|
||||
NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT='true'
|
||||
else
|
||||
AC_DEFINE(WITH_POLKIT, 0, [Define if you have PolicyKit support])
|
||||
AC_DEFINE(NM_CONFIG_DEFAULT_AUTH_POLKIT, FALSE, [The default value of the auth-polkit configuration option])
|
||||
NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT='false'
|
||||
fi
|
||||
AM_CONDITIONAL(WITH_POLKIT, test "${enable_polkit}" = "yes")
|
||||
AC_SUBST(NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT)
|
||||
|
||||
AC_ARG_ENABLE(modify-system,
|
||||
AS_HELP_STRING([--enable-modify-system], [Allow users to modify system connections]))
|
||||
if test "${enable_modify_system}" = "yes"; then
|
||||
if ! test "${enable_polkit}" = "yes"; then
|
||||
AC_MSG_ERROR([--enable-modify-system requires --enable-polkit])
|
||||
fi
|
||||
NM_MODIFY_SYSTEM_POLICY="yes"
|
||||
else
|
||||
NM_MODIFY_SYSTEM_POLICY="auth_admin_keep"
|
||||
|
@ -967,14 +961,10 @@ echo
|
|||
echo "Platform:"
|
||||
echo " session tracking: $with_session_tracking"
|
||||
echo " suspend/resume: $with_suspend_resume"
|
||||
if test "${enable_polkit}" = "yes"; then
|
||||
if test "${enable_modify_system}" = "yes"; then
|
||||
echo " policykit: yes (permissive modify.system)"
|
||||
echo " policykit: yes (permissive modify.system) (default=${enable_polkit})"
|
||||
else
|
||||
echo " policykit: yes (restrictive modify.system)"
|
||||
fi
|
||||
else
|
||||
echo " policykit: no"
|
||||
echo " policykit: yes (restrictive modify.system) (default=${enable_polkit})"
|
||||
fi
|
||||
echo " selinux: $have_selinux"
|
||||
echo
|
||||
|
|
|
@ -139,7 +139,6 @@ BuildRequires: automake autoconf intltool libtool
|
|||
BuildRequires: ppp = %{ppp_version}
|
||||
BuildRequires: ppp-devel = %{ppp_version}
|
||||
BuildRequires: nss-devel >= 3.11.7
|
||||
BuildRequires: polkit-devel
|
||||
BuildRequires: dhclient
|
||||
BuildRequires: readline-devel
|
||||
%if %{regen_docs}
|
||||
|
|
|
@ -122,6 +122,14 @@ Copyright (C) 2010 - 2013 Red Hat, Inc.
|
|||
'<literal>true</literal>', then NetworkManager will reload
|
||||
connection files any time they changed.</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>auth-polkit</varname></term>
|
||||
<listitem><para>Whether the system uses PolicyKit for authorization.
|
||||
If <literal>false</literal>, all requests will be allowed. If
|
||||
<literal>true</literal>, non-root requests are authorized using PolicyKit.
|
||||
The default value is <literal>@NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@</literal>.
|
||||
</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term><varname>dhcp</varname></term>
|
||||
<listitem><para>This key sets up what DHCP client
|
||||
|
|
|
@ -230,6 +230,8 @@ nm_sources = \
|
|||
nm-ip6-config.h \
|
||||
nm-logging.c \
|
||||
nm-logging.h \
|
||||
nm-auth-manager.c \
|
||||
nm-auth-manager.h \
|
||||
nm-auth-subject.c \
|
||||
nm-auth-subject.h \
|
||||
nm-auth-utils.c \
|
||||
|
@ -328,7 +330,6 @@ AM_CPPFLAGS += \
|
|||
$(LIBNL_CFLAGS) \
|
||||
$(LIBNDP_CFLAGS) \
|
||||
$(LIBSOUP_CFLAGS) \
|
||||
$(POLKIT_CFLAGS) \
|
||||
$(SYSTEMD_LOGIN_CFLAGS) \
|
||||
\
|
||||
-DBINDIR=\"$(bindir)\" \
|
||||
|
@ -365,7 +366,6 @@ libNetworkManager_la_LIBADD = \
|
|||
$(GLIB_LIBS) \
|
||||
$(GUDEV_LIBS) \
|
||||
$(LIBNL_LIBS) \
|
||||
$(POLKIT_LIBS) \
|
||||
$(SYSTEMD_LOGIN_LIBS) \
|
||||
$(LIBNDP_LIBS) \
|
||||
$(LIBDL) \
|
||||
|
|
|
@ -56,6 +56,7 @@
|
|||
#include "nm-session-monitor.h"
|
||||
#include "nm-dispatcher.h"
|
||||
#include "nm-settings.h"
|
||||
#include "nm-auth-manager.h"
|
||||
|
||||
#if !defined(NM_DIST_VERSION)
|
||||
# define NM_DIST_VERSION VERSION
|
||||
|
@ -592,6 +593,8 @@ main (int argc, char *argv[])
|
|||
/* Set up platform interaction layer */
|
||||
nm_linux_platform_setup ();
|
||||
|
||||
nm_auth_manager_setup (nm_config_get_auth_polkit (config));
|
||||
|
||||
/* Initialize our DBus service & connection */
|
||||
dbus_mgr = nm_dbus_manager_get ();
|
||||
g_assert (dbus_mgr != NULL);
|
||||
|
|
|
@ -319,7 +319,7 @@ nm_active_connection_get_user_requested (NMActiveConnection *self)
|
|||
{
|
||||
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
|
||||
|
||||
return !nm_auth_subject_get_internal (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject);
|
||||
return nm_auth_subject_is_unix_process (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject);
|
||||
}
|
||||
|
||||
NMDevice *
|
||||
|
|
643
src/nm-auth-manager.c
Normal file
643
src/nm-auth-manager.c
Normal file
|
@ -0,0 +1,643 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* NetworkManager -- Network link manager
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "nm-auth-manager.h"
|
||||
|
||||
#include "nm-logging.h"
|
||||
|
||||
|
||||
#define POLKIT_SERVICE "org.freedesktop.PolicyKit1"
|
||||
#define POLKIT_OBJECT_PATH "/org/freedesktop/PolicyKit1/Authority"
|
||||
#define POLKIT_INTERFACE "org.freedesktop.PolicyKit1.Authority"
|
||||
|
||||
|
||||
#define _LOG_DEFAULT_DOMAIN LOGD_CORE
|
||||
|
||||
#define _LOG(level, domain, ...) \
|
||||
G_STMT_START { \
|
||||
if (nm_logging_enabled ((level), (domain))) { \
|
||||
char __prefix[30] = "auth"; \
|
||||
\
|
||||
if ((self) != _instance) \
|
||||
g_snprintf (__prefix, sizeof (__prefix), "auth[%p]", (self)); \
|
||||
nm_log ((level), (domain), \
|
||||
"%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
||||
__prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define _LOGD(...) _LOG (LOGL_DEBUG, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
|
||||
#define _LOGI(...) _LOG (LOGL_INFO, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
|
||||
#define _LOGW(...) _LOG (LOGL_WARN, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
|
||||
#define _LOGE(...) _LOG (LOGL_ERR, _LOG_DEFAULT_DOMAIN, __VA_ARGS__)
|
||||
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_POLKIT_ENABLED,
|
||||
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
enum {
|
||||
CHANGED_SIGNAL,
|
||||
|
||||
LAST_SIGNAL,
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = {0};
|
||||
|
||||
typedef struct {
|
||||
gboolean polkit_enabled;
|
||||
guint call_id_counter;
|
||||
GCancellable *new_proxy_cancellable;
|
||||
GSList *queued_calls;
|
||||
GDBusProxy *proxy;
|
||||
} NMAuthManagerPrivate;
|
||||
|
||||
static NMAuthManager *_instance = NULL;
|
||||
|
||||
G_DEFINE_TYPE (NMAuthManager, nm_auth_manager, G_TYPE_OBJECT)
|
||||
|
||||
#define NM_AUTH_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUTH_MANAGER, NMAuthManagerPrivate))
|
||||
|
||||
GQuark
|
||||
nm_auth_manager_error_quark (void)
|
||||
{
|
||||
static GQuark quark = 0;
|
||||
|
||||
if (G_UNLIKELY (quark == 0))
|
||||
quark = g_quark_from_static_string ("nm-auth-manager-error-quark");
|
||||
return quark;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
gboolean
|
||||
nm_auth_manager_get_polkit_enabled (NMAuthManager *self)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), FALSE);
|
||||
|
||||
return NM_AUTH_MANAGER_GET_PRIVATE (self)->polkit_enabled;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef enum {
|
||||
POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE = 0,
|
||||
POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION = (1<<0),
|
||||
} PolkitCheckAuthorizationFlags;
|
||||
|
||||
typedef struct {
|
||||
guint call_id;
|
||||
NMAuthManager *self;
|
||||
GSimpleAsyncResult *simple;
|
||||
gchar *cancellation_id;
|
||||
GVariant *dbus_parameters;
|
||||
GCancellable *cancellable;
|
||||
} CheckAuthData;
|
||||
|
||||
static void
|
||||
_check_auth_data_free (CheckAuthData *data)
|
||||
{
|
||||
if (data->dbus_parameters)
|
||||
g_variant_unref (data->dbus_parameters);
|
||||
g_object_unref (data->self);
|
||||
g_object_unref (data->simple);
|
||||
g_clear_object (&data->cancellable);
|
||||
g_free (data->cancellation_id);
|
||||
g_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
_call_check_authorization_complete_with_error (CheckAuthData *data,
|
||||
const char *error_message)
|
||||
{
|
||||
NMAuthManager *self = data->self;
|
||||
GError *error = NULL;
|
||||
|
||||
_LOGD ("call[%u]: CheckAuthorization failed due to internal error: %s", data->call_id, error_message);
|
||||
g_set_error_literal (&error, NM_AUTH_MANAGER_ERROR, NM_AUTH_MANAGER_ERROR_DBUS_FAILURE, error_message);
|
||||
g_simple_async_result_set_from_error (data->simple, error);
|
||||
g_clear_error (&error);
|
||||
|
||||
g_simple_async_result_complete_in_idle (data->simple);
|
||||
|
||||
_check_auth_data_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
cancel_check_authorization_cb (GDBusProxy *proxy,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAuthManager *self = user_data;
|
||||
GVariant *value;
|
||||
GError *error= NULL;
|
||||
|
||||
value = g_dbus_proxy_call_finish (proxy, res, &error);
|
||||
if (value == NULL) {
|
||||
_LOGD ("Error cancelling authorization check: %s", error->message);
|
||||
g_error_free (error);
|
||||
} else
|
||||
g_variant_unref (value);
|
||||
|
||||
g_object_unref (self);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
gboolean is_authorized;
|
||||
gboolean is_challenge;
|
||||
} CheckAuthorizationResult;
|
||||
|
||||
static void
|
||||
check_authorization_cb (GDBusProxy *proxy,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
CheckAuthData *data = user_data;
|
||||
NMAuthManager *self = data->self;
|
||||
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
|
||||
GVariant *value;
|
||||
GError *error = NULL;
|
||||
|
||||
value = g_dbus_proxy_call_finish (proxy, res, &error);
|
||||
if (value == NULL) {
|
||||
if (data->cancellation_id != NULL &&
|
||||
(!g_dbus_error_is_remote_error (error) &&
|
||||
error->domain == G_IO_ERROR &&
|
||||
error->code == G_IO_ERROR_CANCELLED)) {
|
||||
_LOGD ("call[%u]: CheckAuthorization cancelled", data->call_id);
|
||||
g_dbus_proxy_call (priv->proxy,
|
||||
"CancelCheckAuthorization",
|
||||
g_variant_new ("(s)", data->cancellation_id),
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
-1,
|
||||
NULL, /* GCancellable */
|
||||
(GAsyncReadyCallback) cancel_check_authorization_cb,
|
||||
g_object_ref (self));
|
||||
} else
|
||||
_LOGD ("call[%u]: CheckAuthorization failed: %s", data->call_id, error->message);
|
||||
g_simple_async_result_set_from_error (data->simple, error);
|
||||
g_error_free (error);
|
||||
} else {
|
||||
GVariant *result_value;
|
||||
CheckAuthorizationResult *result;
|
||||
|
||||
result = g_new0 (CheckAuthorizationResult, 1);
|
||||
|
||||
result_value = g_variant_get_child_value (value, 0);
|
||||
g_variant_get (result_value,
|
||||
"(bb@a{ss})",
|
||||
&result->is_authorized,
|
||||
&result->is_challenge,
|
||||
NULL);
|
||||
g_variant_unref (result_value);
|
||||
g_variant_unref (value);
|
||||
|
||||
_LOGD ("call[%u]: CheckAuthorization succeeded: (is_authorized=%d, is_challenge=%d)", data->call_id, result->is_authorized, result->is_challenge);
|
||||
g_simple_async_result_set_op_res_gpointer (data->simple, result, g_free);
|
||||
}
|
||||
|
||||
g_simple_async_result_complete (data->simple);
|
||||
|
||||
_check_auth_data_free (data);
|
||||
}
|
||||
|
||||
static void
|
||||
_call_check_authorization (CheckAuthData *data)
|
||||
{
|
||||
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (data->self);
|
||||
|
||||
g_dbus_proxy_call (priv->proxy,
|
||||
"CheckAuthorization",
|
||||
data->dbus_parameters,
|
||||
G_DBUS_CALL_FLAGS_NONE,
|
||||
G_MAXINT, /* no timeout */
|
||||
data->cancellable,
|
||||
(GAsyncReadyCallback) check_authorization_cb,
|
||||
data);
|
||||
g_clear_object (&data->cancellable);
|
||||
data->dbus_parameters = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
nm_auth_manager_polkit_authority_check_authorization (NMAuthManager *self,
|
||||
NMAuthSubject *subject,
|
||||
const char *action_id,
|
||||
gboolean allow_user_interaction,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAuthManagerPrivate *priv;
|
||||
char subject_buf[64];
|
||||
GVariantBuilder builder;
|
||||
PolkitCheckAuthorizationFlags flags;
|
||||
GVariant *subject_value;
|
||||
GVariant *details_value;
|
||||
CheckAuthData *data;
|
||||
|
||||
g_return_if_fail (NM_IS_AUTH_MANAGER (self));
|
||||
g_return_if_fail (NM_IS_AUTH_SUBJECT (subject));
|
||||
g_return_if_fail (nm_auth_subject_is_unix_process (subject));
|
||||
g_return_if_fail (action_id != NULL);
|
||||
g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
|
||||
|
||||
priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
g_return_if_fail (priv->polkit_enabled);
|
||||
|
||||
flags = allow_user_interaction
|
||||
? POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION
|
||||
: POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
|
||||
|
||||
subject_value = nm_auth_subject_unix_process_to_polkit_gvariant (subject);
|
||||
g_assert (g_variant_is_floating (subject_value));
|
||||
|
||||
/* ((PolkitDetails *)NULL) */
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}"));
|
||||
details_value = g_variant_builder_end (&builder);
|
||||
|
||||
data = g_new0 (CheckAuthData, 1);
|
||||
data->call_id = ++priv->call_id_counter;
|
||||
data->self = g_object_ref (self);
|
||||
data->simple = g_simple_async_result_new (G_OBJECT (self),
|
||||
callback,
|
||||
user_data,
|
||||
nm_auth_manager_polkit_authority_check_authorization);
|
||||
if (cancellable != NULL) {
|
||||
data->cancellation_id = g_strdup_printf ("cancellation-id-%u", data->call_id);
|
||||
data->cancellable = g_object_ref (cancellable);
|
||||
}
|
||||
|
||||
data->dbus_parameters = g_variant_new ("(@(sa{sv})s@a{ss}us)",
|
||||
subject_value,
|
||||
action_id,
|
||||
details_value,
|
||||
(guint32) flags,
|
||||
data->cancellation_id != NULL ? data->cancellation_id : "");
|
||||
|
||||
if (priv->new_proxy_cancellable) {
|
||||
_LOGD ("call[%u]: CheckAuthorization(%s), subject=%s (wait for proxy)", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
|
||||
|
||||
priv->queued_calls = g_slist_prepend (priv->queued_calls, data);
|
||||
} else if (!priv->proxy) {
|
||||
_LOGD ("call[%u]: CheckAuthorization(%s), subject=%s (fails due to invalid DBUS proxy)", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
|
||||
|
||||
_call_check_authorization_complete_with_error (data, "invalid DBUS proxy");
|
||||
} else {
|
||||
_LOGD ("call[%u]: CheckAuthorization(%s), subject=%s", data->call_id, action_id, nm_auth_subject_to_string (subject, subject_buf, sizeof (subject_buf)));
|
||||
|
||||
_call_check_authorization (data);
|
||||
}
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_auth_manager_polkit_authority_check_authorization_finish (NMAuthManager *self,
|
||||
GAsyncResult *res,
|
||||
gboolean *out_is_authorized,
|
||||
gboolean *out_is_challenge,
|
||||
GError **error)
|
||||
{
|
||||
gboolean success = FALSE;
|
||||
gboolean is_authorized = FALSE;
|
||||
gboolean is_challenge = FALSE;
|
||||
|
||||
g_return_val_if_fail (NM_IS_AUTH_MANAGER (self), FALSE);
|
||||
g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
if (!g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (res), error)) {
|
||||
CheckAuthorizationResult *result;
|
||||
|
||||
result = g_simple_async_result_get_op_res_gpointer (G_SIMPLE_ASYNC_RESULT (res));
|
||||
is_authorized = !!result->is_authorized;
|
||||
is_challenge = !!result->is_challenge;
|
||||
success = TRUE;
|
||||
}
|
||||
g_assert ((success && !error) || (!success || error));
|
||||
|
||||
if (out_is_authorized)
|
||||
*out_is_authorized = is_authorized;
|
||||
if (out_is_challenge)
|
||||
*out_is_challenge = is_challenge;
|
||||
return success;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
_emit_changed_signal (NMAuthManager *self)
|
||||
{
|
||||
_LOGD ("emit changed signal");
|
||||
g_signal_emit_by_name (self, NM_AUTH_MANAGER_SIGNAL_CHANGED);
|
||||
}
|
||||
|
||||
static void
|
||||
_log_name_owner (NMAuthManager *self, char **out_name_owner)
|
||||
{
|
||||
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
|
||||
char *name_owner;
|
||||
|
||||
name_owner = g_dbus_proxy_get_name_owner (priv->proxy);
|
||||
if (name_owner)
|
||||
_LOGD ("dbus name owner: '%s'", name_owner);
|
||||
else
|
||||
_LOGD ("dbus name owner: none");
|
||||
|
||||
if (out_name_owner)
|
||||
*out_name_owner = name_owner;
|
||||
else
|
||||
g_free (name_owner);
|
||||
}
|
||||
|
||||
static void
|
||||
_dbus_on_name_owner_notify_cb (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAuthManager *self = user_data;
|
||||
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
|
||||
char *name_owner;
|
||||
|
||||
g_return_if_fail (priv->proxy == (void *) object);
|
||||
|
||||
_log_name_owner (self, &name_owner);
|
||||
|
||||
if (!name_owner) {
|
||||
/* when the name disappears, we also want to raise a emit signal.
|
||||
* When it appears, we raise one already. */
|
||||
_emit_changed_signal (self);
|
||||
}
|
||||
|
||||
g_free (name_owner);
|
||||
}
|
||||
|
||||
static void
|
||||
_dbus_on_g_signal_cb (GDBusProxy *proxy,
|
||||
const gchar *sender_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAuthManager *self = user_data;
|
||||
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
g_return_if_fail (priv->proxy == proxy);
|
||||
|
||||
_LOGD ("dbus signal: \"%s\"", signal_name ? signal_name : "(null)");
|
||||
|
||||
if (g_strcmp0 (signal_name, "Changed") == 0)
|
||||
_emit_changed_signal (self);
|
||||
}
|
||||
|
||||
static void
|
||||
_dbus_new_proxy_cb (GObject *source_object,
|
||||
GAsyncResult *res,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAuthManager **p_self = user_data;
|
||||
NMAuthManager *self = NULL;
|
||||
NMAuthManagerPrivate *priv;
|
||||
GError *error = NULL;
|
||||
GDBusProxy *proxy;
|
||||
CheckAuthData *data;
|
||||
|
||||
proxy = g_dbus_proxy_new_for_bus_finish (res, &error);
|
||||
|
||||
if (!*p_self) {
|
||||
_LOGD ("_dbus_new_proxy_cb(): manager destroyed before callback finished. Abort");
|
||||
g_clear_object (&proxy);
|
||||
g_clear_error (&error);
|
||||
g_free (p_self);
|
||||
return;
|
||||
}
|
||||
self = *p_self;
|
||||
g_object_remove_weak_pointer (G_OBJECT (self), (void **)p_self);
|
||||
g_free (p_self);
|
||||
|
||||
priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
g_return_if_fail (priv->new_proxy_cancellable);
|
||||
g_return_if_fail (!priv->proxy);
|
||||
|
||||
g_clear_object (&priv->new_proxy_cancellable);
|
||||
|
||||
priv->queued_calls = g_slist_reverse (priv->queued_calls);
|
||||
|
||||
priv->proxy = proxy;
|
||||
if (!priv->proxy) {
|
||||
_LOGE ("could not get polkit proxy: %s", error->message);
|
||||
g_clear_error (&error);
|
||||
|
||||
while (priv->queued_calls) {
|
||||
data = priv->queued_calls->data;
|
||||
priv->queued_calls = g_slist_remove (priv->queued_calls, data);
|
||||
|
||||
_call_check_authorization_complete_with_error (data, "error creating DBUS proxy");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
g_signal_connect (priv->proxy,
|
||||
"notify::g-name-owner",
|
||||
G_CALLBACK (_dbus_on_name_owner_notify_cb),
|
||||
self);
|
||||
g_signal_connect (priv->proxy,
|
||||
"g-signal",
|
||||
G_CALLBACK (_dbus_on_g_signal_cb),
|
||||
self);
|
||||
|
||||
_log_name_owner (self, NULL);
|
||||
|
||||
while (priv->queued_calls) {
|
||||
data = priv->queued_calls->data;
|
||||
priv->queued_calls = g_slist_remove (priv->queued_calls, data);
|
||||
_LOGD ("call[%u]: CheckAuthorization invoke now", data->call_id);
|
||||
_call_check_authorization (data);
|
||||
}
|
||||
_emit_changed_signal (self);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMAuthManager *
|
||||
nm_auth_manager_get ()
|
||||
{
|
||||
g_return_val_if_fail (_instance, NULL);
|
||||
|
||||
return _instance;
|
||||
}
|
||||
|
||||
NMAuthManager *
|
||||
nm_auth_manager_setup (gboolean polkit_enabled)
|
||||
{
|
||||
NMAuthManager *self;
|
||||
|
||||
g_return_val_if_fail (!_instance, _instance);
|
||||
|
||||
self = g_object_new (NM_TYPE_AUTH_MANAGER,
|
||||
NM_AUTH_MANAGER_POLKIT_ENABLED, polkit_enabled,
|
||||
NULL);
|
||||
_LOGD ("set instance");
|
||||
|
||||
return (_instance = self);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_POLKIT_ENABLED:
|
||||
g_value_set_boolean (value, priv->polkit_enabled);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_POLKIT_ENABLED:
|
||||
/* construct only */
|
||||
priv->polkit_enabled = !!g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nm_auth_manager_init (NMAuthManager *self)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
constructed (GObject *object)
|
||||
{
|
||||
NMAuthManager *self = NM_AUTH_MANAGER (object);
|
||||
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
G_OBJECT_CLASS (nm_auth_manager_parent_class)->constructed (object);
|
||||
|
||||
_LOGD ("create auth-manager: polkit %s", priv->polkit_enabled ? "enabled" : "disabled");
|
||||
|
||||
if (priv->polkit_enabled) {
|
||||
NMAuthManager **p_self;
|
||||
|
||||
priv->new_proxy_cancellable = g_cancellable_new ();
|
||||
p_self = g_new (NMAuthManager *, 1);
|
||||
*p_self = self;
|
||||
g_object_add_weak_pointer (G_OBJECT (self), (void **) p_self);
|
||||
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES,
|
||||
NULL,
|
||||
POLKIT_SERVICE,
|
||||
POLKIT_OBJECT_PATH,
|
||||
POLKIT_INTERFACE,
|
||||
priv->new_proxy_cancellable,
|
||||
_dbus_new_proxy_cb,
|
||||
p_self);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
NMAuthManager* self = NM_AUTH_MANAGER (object);
|
||||
NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
_LOGD ("dispose");
|
||||
|
||||
/* since we take a reference for each queued call, we don't expect to have any queued calls in dispose() */
|
||||
g_assert (!priv->queued_calls);
|
||||
|
||||
if (priv->new_proxy_cancellable) {
|
||||
g_cancellable_cancel (priv->new_proxy_cancellable);
|
||||
g_clear_object (&priv->new_proxy_cancellable);
|
||||
}
|
||||
|
||||
if (priv->proxy) {
|
||||
g_signal_handlers_disconnect_by_func (priv->proxy, _dbus_on_name_owner_notify_cb, self);
|
||||
g_signal_handlers_disconnect_by_func (priv->proxy, _dbus_on_g_signal_cb, self);
|
||||
g_clear_object (&priv->proxy);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (nm_auth_manager_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
finalize (GObject *object)
|
||||
{
|
||||
NMAuthManager* self = NM_AUTH_MANAGER (object);
|
||||
|
||||
G_OBJECT_CLASS (nm_auth_manager_parent_class)->finalize (object);
|
||||
|
||||
if (self == _instance) {
|
||||
_instance = NULL;
|
||||
_LOGD ("unset instance");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nm_auth_manager_class_init (NMAuthManagerClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
g_type_class_add_private (klass, sizeof (NMAuthManagerPrivate));
|
||||
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
object_class->constructed = constructed;
|
||||
object_class->dispose = dispose;
|
||||
object_class->finalize = finalize;
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_POLKIT_ENABLED,
|
||||
g_param_spec_boolean (NM_AUTH_MANAGER_POLKIT_ENABLED, "", "",
|
||||
FALSE,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
signals[CHANGED_SIGNAL] = g_signal_new (NM_AUTH_MANAGER_SIGNAL_CHANGED,
|
||||
NM_TYPE_AUTH_MANAGER,
|
||||
G_SIGNAL_RUN_LAST,
|
||||
0, /* class offset */
|
||||
NULL, /* accumulator */
|
||||
NULL, /* accumulator data */
|
||||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE,
|
||||
0);
|
||||
|
||||
}
|
||||
|
82
src/nm-auth-manager.h
Normal file
82
src/nm-auth-manager.h
Normal file
|
@ -0,0 +1,82 @@
|
|||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/* NetworkManager -- Network link manager
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef NM_AUTH_MANAGER_H
|
||||
#define NM_AUTH_MANAGER_H
|
||||
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "nm-auth-subject.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
#define NM_TYPE_AUTH_MANAGER (nm_auth_manager_get_type ())
|
||||
#define NM_AUTH_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUTH_MANAGER, NMAuthManager))
|
||||
#define NM_AUTH_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUTH_MANAGER, NMAuthManagerClass))
|
||||
#define NM_IS_AUTH_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_AUTH_MANAGER))
|
||||
#define NM_IS_AUTH_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AUTH_MANAGER))
|
||||
#define NM_AUTH_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AUTH_MANAGER, NMAuthManagerClass))
|
||||
|
||||
|
||||
#define NM_AUTH_MANAGER_POLKIT_ENABLED "polkit-enabled"
|
||||
|
||||
#define NM_AUTH_MANAGER_SIGNAL_CHANGED "changed"
|
||||
|
||||
#define NM_AUTH_MANAGER_ERROR (nm_auth_manager_error_quark ())
|
||||
|
||||
typedef enum {
|
||||
NM_AUTH_MANAGER_ERROR_DBUS_FAILURE = 1,
|
||||
} NMAuthManagerError;
|
||||
|
||||
typedef struct {
|
||||
GObject parent;
|
||||
} NMAuthManager;
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent;
|
||||
} NMAuthManagerClass;
|
||||
|
||||
GType nm_auth_manager_get_type (void);
|
||||
GQuark nm_auth_manager_error_quark (void);
|
||||
|
||||
NMAuthManager *nm_auth_manager_setup (gboolean polkit_enabled);
|
||||
NMAuthManager *nm_auth_manager_get (void);
|
||||
|
||||
gboolean nm_auth_manager_get_polkit_enabled (NMAuthManager *self);
|
||||
|
||||
void nm_auth_manager_polkit_authority_check_authorization (NMAuthManager *self,
|
||||
NMAuthSubject *subject,
|
||||
const char *action_id,
|
||||
gboolean allow_user_interaction,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean nm_auth_manager_polkit_authority_check_authorization_finish (NMAuthManager *self,
|
||||
GAsyncResult *res,
|
||||
gboolean *out_is_authorized,
|
||||
gboolean *out_is_challenge,
|
||||
GError **error);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* NM_AUTH_MANAGER_H */
|
||||
|
|
@ -15,7 +15,7 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Copyright (C) 2013 Red Hat, Inc.
|
||||
* Copyright (C) 2013 - 2014 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
/**
|
||||
|
@ -26,108 +26,262 @@
|
|||
* makes requests, like process identifier and user UID.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <glib.h>
|
||||
#include <string.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#if WITH_POLKIT
|
||||
#include <polkit/polkit.h>
|
||||
#endif
|
||||
|
||||
#include "nm-auth-subject.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#include "nm-dbus-manager.h"
|
||||
#include "nm-enum-types.h"
|
||||
|
||||
G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT)
|
||||
|
||||
#define NM_AUTH_SUBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectPrivate))
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_SUBJECT_TYPE,
|
||||
PROP_UNIX_PROCESS_DBUS_SENDER,
|
||||
PROP_UNIX_PROCESS_PID,
|
||||
PROP_UNIX_PROCESS_UID,
|
||||
|
||||
PROP_LAST,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
NMAuthSubjectType subject_type;
|
||||
struct {
|
||||
gulong pid;
|
||||
gulong uid;
|
||||
guint64 start_time;
|
||||
char *dbus_sender;
|
||||
|
||||
#if WITH_POLKIT
|
||||
PolkitSubject *pk_subject;
|
||||
#endif
|
||||
} unix_process;
|
||||
} NMAuthSubjectPrivate;
|
||||
|
||||
static NMAuthSubject *
|
||||
_new_common (DBusGMethodInvocation *context,
|
||||
DBusConnection *connection,
|
||||
DBusMessage *message,
|
||||
gboolean internal)
|
||||
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/* copied from polkit source (src/polkit/polkitunixprocess.c)
|
||||
* and adjusted.
|
||||
*/
|
||||
static guint64
|
||||
get_start_time_for_pid (pid_t pid)
|
||||
{
|
||||
NMAuthSubject *subject;
|
||||
NMAuthSubjectPrivate *priv;
|
||||
NMDBusManager *dbus_mgr;
|
||||
gboolean success = FALSE;
|
||||
guint64 start_time;
|
||||
gchar *filename;
|
||||
gchar *contents;
|
||||
size_t length;
|
||||
gchar **tokens;
|
||||
guint num_tokens;
|
||||
gchar *p;
|
||||
gchar *endp;
|
||||
|
||||
g_return_val_if_fail (context || (connection && message) || internal, NULL);
|
||||
if (internal)
|
||||
g_return_val_if_fail (context == NULL && connection == NULL && message == NULL, NULL);
|
||||
start_time = 0;
|
||||
contents = NULL;
|
||||
|
||||
subject = NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT, NULL));
|
||||
priv = NM_AUTH_SUBJECT_GET_PRIVATE (subject);
|
||||
filename = g_strdup_printf ("/proc/%d/stat", pid);
|
||||
|
||||
dbus_mgr = nm_dbus_manager_get ();
|
||||
if (!g_file_get_contents (filename, &contents, &length, NULL))
|
||||
goto out;
|
||||
|
||||
if (internal) {
|
||||
priv->uid = 0;
|
||||
priv->pid = 0;
|
||||
return subject;
|
||||
/* start time is the token at index 19 after the '(process name)' entry - since only this
|
||||
* field can contain the ')' character, search backwards for this to avoid malicious
|
||||
* processes trying to fool us
|
||||
*/
|
||||
p = strrchr (contents, ')');
|
||||
if (p == NULL)
|
||||
goto out;
|
||||
p += 2; /* skip ') ' */
|
||||
if (p - contents >= (int) length)
|
||||
goto out;
|
||||
|
||||
tokens = g_strsplit (p, " ", 0);
|
||||
|
||||
num_tokens = g_strv_length (tokens);
|
||||
|
||||
if (num_tokens < 20)
|
||||
goto out;
|
||||
|
||||
start_time = strtoull (tokens[19], &endp, 10);
|
||||
if (endp == tokens[19])
|
||||
goto out;
|
||||
|
||||
g_strfreev (tokens);
|
||||
|
||||
out:
|
||||
g_free (filename);
|
||||
g_free (contents);
|
||||
|
||||
return start_time;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
#define CHECK_SUBJECT(self, error_value) \
|
||||
NMAuthSubjectPrivate *priv; \
|
||||
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (self), error_value); \
|
||||
priv = NM_AUTH_SUBJECT_GET_PRIVATE (self); \
|
||||
|
||||
#define CHECK_SUBJECT_TYPED(self, expected_subject_type, error_value) \
|
||||
CHECK_SUBJECT (self, error_value); \
|
||||
g_return_val_if_fail (priv->subject_type == (expected_subject_type), error_value);
|
||||
|
||||
const char *
|
||||
nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len)
|
||||
{
|
||||
CHECK_SUBJECT (self, NULL);
|
||||
|
||||
switch (priv->subject_type) {
|
||||
case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
|
||||
g_snprintf (buf, buf_len, "unix-process[pid=%lu, uid=%lu, start=%llu]",
|
||||
(long unsigned) priv->unix_process.pid,
|
||||
(long unsigned) priv->unix_process.uid,
|
||||
(long long unsigned) priv->unix_process.start_time);
|
||||
break;
|
||||
case NM_AUTH_SUBJECT_TYPE_INTERNAL:
|
||||
g_strlcat (buf, "internal", buf_len);
|
||||
break;
|
||||
default:
|
||||
g_strlcat (buf, "invalid", buf_len);
|
||||
break;
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
|
||||
/* returns a floating variant */
|
||||
GVariant *
|
||||
nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self)
|
||||
{
|
||||
GVariantBuilder builder;
|
||||
GVariant *dict;
|
||||
GVariant *ret;
|
||||
CHECK_SUBJECT_TYPED (self, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL);
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
|
||||
g_variant_builder_add (&builder, "{sv}", "pid",
|
||||
g_variant_new_uint32 (priv->unix_process.pid));
|
||||
g_variant_builder_add (&builder, "{sv}", "start-time",
|
||||
g_variant_new_uint64 (priv->unix_process.start_time));
|
||||
g_variant_builder_add (&builder, "{sv}", "uid",
|
||||
g_variant_new_int32 (priv->unix_process.uid));
|
||||
dict = g_variant_builder_end (&builder);
|
||||
ret = g_variant_new ("(s@a{sv})", "unix-process", dict);
|
||||
return ret;
|
||||
}
|
||||
|
||||
NMAuthSubjectType
|
||||
nm_auth_subject_get_subject_type (NMAuthSubject *subject)
|
||||
{
|
||||
CHECK_SUBJECT (subject, NM_AUTH_SUBJECT_TYPE_INVALID);
|
||||
|
||||
return priv->subject_type;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_auth_subject_is_internal (NMAuthSubject *subject)
|
||||
{
|
||||
return nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_INTERNAL;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_auth_subject_is_unix_process (NMAuthSubject *subject)
|
||||
{
|
||||
return nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
|
||||
}
|
||||
|
||||
gulong
|
||||
nm_auth_subject_get_unix_process_pid (NMAuthSubject *subject)
|
||||
{
|
||||
CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
|
||||
|
||||
return priv->unix_process.pid;
|
||||
}
|
||||
|
||||
gulong
|
||||
nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject)
|
||||
{
|
||||
CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, G_MAXULONG);
|
||||
|
||||
return priv->unix_process.uid;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject)
|
||||
{
|
||||
CHECK_SUBJECT_TYPED (subject, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS, NULL);
|
||||
|
||||
return priv->unix_process.dbus_sender;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
static NMAuthSubject *
|
||||
_new_unix_process (DBusGMethodInvocation *context,
|
||||
DBusConnection *connection,
|
||||
DBusMessage *message)
|
||||
{
|
||||
NMAuthSubject *self;
|
||||
gboolean success = FALSE;
|
||||
gulong pid = 0, uid = 0;
|
||||
char *dbus_sender = NULL;
|
||||
|
||||
g_return_val_if_fail (context || (connection && message), NULL);
|
||||
|
||||
if (context) {
|
||||
success = nm_dbus_manager_get_caller_info (dbus_mgr,
|
||||
success = nm_dbus_manager_get_caller_info (nm_dbus_manager_get (),
|
||||
context,
|
||||
&priv->dbus_sender,
|
||||
&priv->uid,
|
||||
&priv->pid);
|
||||
&dbus_sender,
|
||||
&uid,
|
||||
&pid);
|
||||
} else if (message) {
|
||||
success = nm_dbus_manager_get_caller_info_from_message (dbus_mgr,
|
||||
success = nm_dbus_manager_get_caller_info_from_message (nm_dbus_manager_get (),
|
||||
connection,
|
||||
message,
|
||||
&priv->dbus_sender,
|
||||
&priv->uid,
|
||||
&priv->pid);
|
||||
&dbus_sender,
|
||||
&uid,
|
||||
&pid);
|
||||
} else
|
||||
g_assert_not_reached ();
|
||||
|
||||
if (!success) {
|
||||
g_object_unref (subject);
|
||||
if (!success)
|
||||
return NULL;
|
||||
|
||||
g_return_val_if_fail (dbus_sender && *dbus_sender, NULL);
|
||||
/* polkit glib library stores uid and pid as gint. There might be some
|
||||
* pitfalls if the id ever happens to be larger then that. Just assert against
|
||||
* it here. */
|
||||
g_return_val_if_fail (uid <= MIN (G_MAXINT, G_MAXINT32), NULL);
|
||||
g_return_val_if_fail (pid > 0 && pid <= MIN (G_MAXINT, G_MAXINT32), NULL);
|
||||
|
||||
self = NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
|
||||
NM_AUTH_SUBJECT_SUBJECT_TYPE, NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS,
|
||||
NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, dbus_sender,
|
||||
NM_AUTH_SUBJECT_UNIX_PROCESS_PID, (gulong) pid,
|
||||
NM_AUTH_SUBJECT_UNIX_PROCESS_UID, (gulong) uid,
|
||||
NULL));
|
||||
|
||||
if (NM_AUTH_SUBJECT_GET_PRIVATE (self)->subject_type != NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS) {
|
||||
/* this most likely happened because the process is gone (start_time==0).
|
||||
* Either that is not assert-worthy, or constructed() already asserted.
|
||||
* Just return NULL. */
|
||||
g_clear_object (&self);
|
||||
}
|
||||
|
||||
g_assert (priv->dbus_sender);
|
||||
g_assert_cmpuint (priv->pid, !=, 0);
|
||||
|
||||
#if WITH_POLKIT
|
||||
/* FIXME: should we use polkit_unix_session_new() to store the session ID
|
||||
* of a short-lived process, so that the process can exit but we can still
|
||||
* ask that user for authorization?
|
||||
*/
|
||||
priv->pk_subject = polkit_unix_process_new_for_owner (priv->pid, 0, priv->uid);
|
||||
if (!priv->pk_subject)
|
||||
return NULL;
|
||||
#endif
|
||||
|
||||
return subject;
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
NMAuthSubject *
|
||||
nm_auth_subject_new_from_context (DBusGMethodInvocation *context)
|
||||
nm_auth_subject_new_unix_process_from_context (DBusGMethodInvocation *context)
|
||||
{
|
||||
return _new_common (context, NULL, NULL, FALSE);
|
||||
return _new_unix_process (context, NULL, NULL);
|
||||
}
|
||||
|
||||
NMAuthSubject *
|
||||
nm_auth_subject_new_from_message (DBusConnection *connection,
|
||||
nm_auth_subject_new_unix_process_from_message (DBusConnection *connection,
|
||||
DBusMessage *message)
|
||||
{
|
||||
return _new_common (NULL, connection, message, FALSE);
|
||||
return _new_unix_process (NULL, connection, message);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -140,53 +294,135 @@ nm_auth_subject_new_from_message (DBusConnection *connection,
|
|||
NMAuthSubject *
|
||||
nm_auth_subject_new_internal (void)
|
||||
{
|
||||
return _new_common (NULL, NULL, NULL, TRUE);
|
||||
return NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT,
|
||||
NM_AUTH_SUBJECT_SUBJECT_TYPE, NM_AUTH_SUBJECT_TYPE_INTERNAL,
|
||||
NULL));
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
gulong
|
||||
nm_auth_subject_get_uid (NMAuthSubject *subject)
|
||||
static void
|
||||
get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->uid;
|
||||
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_SUBJECT_TYPE:
|
||||
g_value_set_enum (value, priv->subject_type);
|
||||
break;
|
||||
case PROP_UNIX_PROCESS_DBUS_SENDER:
|
||||
g_value_set_string (value, priv->unix_process.dbus_sender);
|
||||
break;
|
||||
case PROP_UNIX_PROCESS_PID:
|
||||
g_value_set_ulong (value, priv->unix_process.pid);
|
||||
break;
|
||||
case PROP_UNIX_PROCESS_UID:
|
||||
g_value_set_ulong (value, priv->unix_process.uid);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
gulong
|
||||
nm_auth_subject_get_pid (NMAuthSubject *subject)
|
||||
static void
|
||||
set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->pid;
|
||||
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
|
||||
NMAuthSubjectType subject_type;
|
||||
const char *str;
|
||||
gulong id;
|
||||
|
||||
/* all properties are construct-only */
|
||||
switch (prop_id) {
|
||||
case PROP_SUBJECT_TYPE:
|
||||
subject_type = g_value_get_enum (value);
|
||||
g_return_if_fail (subject_type != NM_AUTH_SUBJECT_TYPE_INVALID);
|
||||
priv->subject_type |= subject_type;
|
||||
g_return_if_fail (priv->subject_type == subject_type);
|
||||
break;
|
||||
case PROP_UNIX_PROCESS_DBUS_SENDER:
|
||||
if ((str = g_value_get_string (value))) {
|
||||
priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
|
||||
g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
|
||||
priv->unix_process.dbus_sender = g_strdup (str);
|
||||
}
|
||||
break;
|
||||
case PROP_UNIX_PROCESS_PID:
|
||||
if ((id = g_value_get_ulong (value)) != G_MAXULONG) {
|
||||
priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
|
||||
g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
|
||||
priv->unix_process.pid = id;
|
||||
}
|
||||
break;
|
||||
case PROP_UNIX_PROCESS_UID:
|
||||
if ((id = g_value_get_ulong (value)) != G_MAXULONG) {
|
||||
priv->subject_type |= NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS;
|
||||
g_return_if_fail (priv->subject_type == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
|
||||
priv->unix_process.uid = id;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_auth_subject_get_dbus_sender (NMAuthSubject *subject)
|
||||
static void
|
||||
_clear_private (NMAuthSubjectPrivate *priv)
|
||||
{
|
||||
return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender;
|
||||
priv->subject_type = NM_AUTH_SUBJECT_TYPE_INVALID;
|
||||
priv->unix_process.pid = G_MAXULONG;
|
||||
priv->unix_process.uid = G_MAXULONG;
|
||||
g_clear_pointer (&priv->unix_process.dbus_sender, g_free);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_auth_subject_get_internal (NMAuthSubject *subject)
|
||||
{
|
||||
/* internal requests will have no dbus sender */
|
||||
return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender ? FALSE : TRUE;
|
||||
}
|
||||
|
||||
#if WITH_POLKIT
|
||||
PolkitSubject *
|
||||
nm_auth_subject_get_polkit_subject (NMAuthSubject *subject)
|
||||
{
|
||||
return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->pk_subject;
|
||||
}
|
||||
#endif
|
||||
|
||||
/******************************************************************/
|
||||
|
||||
static void
|
||||
nm_auth_subject_init (NMAuthSubject *self)
|
||||
{
|
||||
_clear_private (NM_AUTH_SUBJECT_GET_PRIVATE (self));
|
||||
}
|
||||
|
||||
static void
|
||||
constructed (GObject *object)
|
||||
{
|
||||
NMAuthSubject *self = NM_AUTH_SUBJECT (object);
|
||||
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self);
|
||||
|
||||
priv->pid = G_MAXULONG;
|
||||
priv->uid = G_MAXULONG;
|
||||
/* validate that the created instance. */
|
||||
|
||||
switch (priv->subject_type) {
|
||||
case NM_AUTH_SUBJECT_TYPE_INTERNAL:
|
||||
priv->unix_process.pid = G_MAXULONG;
|
||||
priv->unix_process.uid = 0; /* internal uses 'root' user */
|
||||
return;
|
||||
case NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS:
|
||||
/* Ensure pid and uid to be representable as int32.
|
||||
* DBUS treats them as uint32, polkit library as gint. */
|
||||
if (priv->unix_process.pid > MIN (G_MAXINT, G_MAXINT32))
|
||||
break;
|
||||
if (priv->unix_process.uid > MIN (G_MAXINT, G_MAXINT32)) {
|
||||
/* for uid==-1, libpolkit-gobject-1 detects the user based on the process id.
|
||||
* Don't bother and require the user id as parameter. */
|
||||
break;
|
||||
}
|
||||
if (!priv->unix_process.dbus_sender || !*priv->unix_process.dbus_sender)
|
||||
break;
|
||||
|
||||
priv->unix_process.start_time = get_start_time_for_pid (priv->unix_process.pid);
|
||||
|
||||
if (!priv->unix_process.start_time) {
|
||||
/* could not detect the process start time. The subject is invalid, but don't
|
||||
* assert against it. */
|
||||
_clear_private (priv);
|
||||
}
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
_clear_private (priv);
|
||||
g_return_if_reached ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -194,12 +430,7 @@ finalize (GObject *object)
|
|||
{
|
||||
NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
|
||||
|
||||
g_free (priv->dbus_sender);
|
||||
|
||||
#if WITH_POLKIT
|
||||
if (priv->pk_subject)
|
||||
g_object_unref (priv->pk_subject);
|
||||
#endif
|
||||
_clear_private (priv);
|
||||
|
||||
G_OBJECT_CLASS (nm_auth_subject_parent_class)->finalize (object);
|
||||
}
|
||||
|
@ -212,5 +443,42 @@ nm_auth_subject_class_init (NMAuthSubjectClass *config_class)
|
|||
g_type_class_add_private (config_class, sizeof (NMAuthSubjectPrivate));
|
||||
|
||||
/* virtual methods */
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
object_class->constructed = constructed;
|
||||
object_class->finalize = finalize;
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_SUBJECT_TYPE,
|
||||
g_param_spec_enum (NM_AUTH_SUBJECT_SUBJECT_TYPE, "", "",
|
||||
NM_TYPE_AUTH_SUBJECT_TYPE,
|
||||
NM_AUTH_SUBJECT_TYPE_INVALID,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_UNIX_PROCESS_DBUS_SENDER,
|
||||
g_param_spec_string (NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER, "", "",
|
||||
NULL,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_UNIX_PROCESS_PID,
|
||||
g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_PID, "", "",
|
||||
0, G_MAXULONG, G_MAXULONG,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_UNIX_PROCESS_UID,
|
||||
g_param_spec_ulong (NM_AUTH_SUBJECT_UNIX_PROCESS_UID, "", "",
|
||||
0, G_MAXULONG, G_MAXULONG,
|
||||
G_PARAM_READWRITE |
|
||||
G_PARAM_CONSTRUCT_ONLY |
|
||||
G_PARAM_STATIC_STRINGS));
|
||||
|
||||
}
|
||||
|
|
|
@ -27,10 +27,6 @@
|
|||
#include <dbus/dbus.h>
|
||||
#include <dbus/dbus-glib.h>
|
||||
|
||||
#if WITH_POLKIT
|
||||
#include <polkit/polkit.h>
|
||||
#endif
|
||||
|
||||
#include "nm-types.h"
|
||||
|
||||
#define NM_TYPE_AUTH_SUBJECT (nm_auth_subject_get_type ())
|
||||
|
@ -40,33 +36,52 @@
|
|||
#define NM_IS_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AUTH_SUBJECT))
|
||||
#define NM_AUTH_SUBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass))
|
||||
|
||||
typedef enum {
|
||||
NM_AUTH_SUBJECT_TYPE_INVALID = 0,
|
||||
NM_AUTH_SUBJECT_TYPE_INTERNAL = 1,
|
||||
NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS = 2,
|
||||
} NMAuthSubjectType;
|
||||
|
||||
#define NM_AUTH_SUBJECT_SUBJECT_TYPE "subject-type"
|
||||
#define NM_AUTH_SUBJECT_UNIX_PROCESS_DBUS_SENDER "unix-process-dbus-sender"
|
||||
#define NM_AUTH_SUBJECT_UNIX_PROCESS_PID "unix-process-pid"
|
||||
#define NM_AUTH_SUBJECT_UNIX_PROCESS_UID "unix-process-uid"
|
||||
|
||||
struct _NMAuthSubject {
|
||||
GObject parent;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent;
|
||||
|
||||
} NMAuthSubjectClass;
|
||||
|
||||
GType nm_auth_subject_get_type (void);
|
||||
|
||||
NMAuthSubject *nm_auth_subject_new_from_context (DBusGMethodInvocation *context);
|
||||
|
||||
NMAuthSubject *nm_auth_subject_new_from_message (DBusConnection *connection, DBusMessage *message);
|
||||
|
||||
NMAuthSubject *nm_auth_subject_new_internal (void);
|
||||
|
||||
gulong nm_auth_subject_get_uid (NMAuthSubject *subject);
|
||||
NMAuthSubject *nm_auth_subject_new_unix_process_from_context (DBusGMethodInvocation *context);
|
||||
|
||||
gulong nm_auth_subject_get_pid (NMAuthSubject *subject);
|
||||
NMAuthSubject *nm_auth_subject_new_unix_process_from_message (DBusConnection *connection, DBusMessage *message);
|
||||
|
||||
const char *nm_auth_subject_get_dbus_sender (NMAuthSubject *subject);
|
||||
|
||||
gboolean nm_auth_subject_get_internal (NMAuthSubject *subject);
|
||||
NMAuthSubjectType nm_auth_subject_get_subject_type (NMAuthSubject *subject);
|
||||
|
||||
#if WITH_POLKIT
|
||||
PolkitSubject *nm_auth_subject_get_polkit_subject (NMAuthSubject *subject);
|
||||
#endif
|
||||
|
||||
gboolean nm_auth_subject_is_internal (NMAuthSubject *subject);
|
||||
|
||||
|
||||
gboolean nm_auth_subject_is_unix_process (NMAuthSubject *subject);
|
||||
|
||||
gulong nm_auth_subject_get_unix_process_pid (NMAuthSubject *subject);
|
||||
|
||||
const char *nm_auth_subject_get_unix_process_dbus_sender (NMAuthSubject *subject);
|
||||
|
||||
|
||||
gulong nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject);
|
||||
|
||||
|
||||
const char *nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len);
|
||||
|
||||
GVariant * nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self);
|
||||
|
||||
#endif /* __NETWORKMANAGER_AUTH_SUBJECT_H__ */
|
||||
|
|
|
@ -22,28 +22,21 @@
|
|||
#include <string.h>
|
||||
#include <gio/gio.h>
|
||||
|
||||
#if WITH_POLKIT
|
||||
#include <polkit/polkit.h>
|
||||
#endif
|
||||
|
||||
#include "gsystem-local-alloc.h"
|
||||
#include "nm-setting-connection.h"
|
||||
#include "nm-auth-utils.h"
|
||||
#include "nm-logging.h"
|
||||
#include "nm-dbus-manager.h"
|
||||
#include "nm-auth-subject.h"
|
||||
#include "nm-auth-manager.h"
|
||||
#include "nm-session-monitor.h"
|
||||
|
||||
struct NMAuthChain {
|
||||
guint32 refcount;
|
||||
#if WITH_POLKIT
|
||||
PolkitAuthority *authority;
|
||||
#endif
|
||||
GSList *calls;
|
||||
GHashTable *data;
|
||||
|
||||
DBusGMethodInvocation *context;
|
||||
char *owner;
|
||||
gulong user_uid;
|
||||
NMAuthSubject *subject;
|
||||
GError *error;
|
||||
|
||||
|
@ -90,69 +83,6 @@ auth_chain_finish (gpointer user_data)
|
|||
return FALSE;
|
||||
}
|
||||
|
||||
#if WITH_POLKIT
|
||||
static PolkitAuthority *
|
||||
pk_authority_get (GError **error)
|
||||
{
|
||||
static PolkitAuthority *authority = NULL;
|
||||
|
||||
if (authority == NULL)
|
||||
authority = polkit_authority_get_sync (NULL, error);
|
||||
|
||||
/* Yes, ref every time; we want to keep the object alive */
|
||||
g_warn_if_fail (authority);
|
||||
return authority ? g_object_ref (authority) : NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
static NMAuthChain *
|
||||
_auth_chain_new (NMAuthSubject *subject,
|
||||
const char *dbus_sender,
|
||||
gulong user_uid,
|
||||
DBusGMethodInvocation *context,
|
||||
NMAuthChainResultFunc done_func,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAuthChain *self;
|
||||
|
||||
g_return_val_if_fail (subject || user_uid == 0 || dbus_sender, NULL);
|
||||
|
||||
self = g_malloc0 (sizeof (NMAuthChain));
|
||||
self->refcount = 1;
|
||||
#if WITH_POLKIT
|
||||
self->authority = pk_authority_get (&self->error);
|
||||
#endif
|
||||
self->data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_data);
|
||||
self->done_func = done_func;
|
||||
self->user_data = user_data;
|
||||
self->context = context;
|
||||
|
||||
if (subject) {
|
||||
self->user_uid = nm_auth_subject_get_uid (subject);
|
||||
self->subject = g_object_ref (subject);
|
||||
} else {
|
||||
self->user_uid = user_uid;
|
||||
self->owner = g_strdup (dbus_sender);
|
||||
if (user_uid > 0 && !self->owner) {
|
||||
/* Need an owner */
|
||||
g_warn_if_fail (self->owner);
|
||||
nm_auth_chain_unref (self);
|
||||
self = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
NMAuthChain *
|
||||
nm_auth_chain_new_dbus_sender (const char *dbus_sender,
|
||||
gulong user_uid,
|
||||
NMAuthChainResultFunc done_func,
|
||||
gpointer user_data)
|
||||
{
|
||||
return _auth_chain_new (NULL, dbus_sender, user_uid, NULL, done_func, user_data);
|
||||
}
|
||||
|
||||
/* Creates the NMAuthSubject automatically */
|
||||
NMAuthChain *
|
||||
nm_auth_chain_new_context (DBusGMethodInvocation *context,
|
||||
|
@ -164,7 +94,7 @@ nm_auth_chain_new_context (DBusGMethodInvocation *context,
|
|||
|
||||
g_return_val_if_fail (context != NULL, NULL);
|
||||
|
||||
subject = nm_auth_subject_new_from_context (context);
|
||||
subject = nm_auth_subject_new_unix_process_from_context (context);
|
||||
if (!subject)
|
||||
return NULL;
|
||||
|
||||
|
@ -183,16 +113,20 @@ nm_auth_chain_new_subject (NMAuthSubject *subject,
|
|||
NMAuthChainResultFunc done_func,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAuthChain *chain;
|
||||
NMAuthChain *self;
|
||||
|
||||
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
|
||||
chain = _auth_chain_new (subject, NULL, G_MAXULONG, context, done_func, user_data);
|
||||
g_return_val_if_fail (nm_auth_subject_is_unix_process (subject) || nm_auth_subject_is_internal (subject), NULL);
|
||||
|
||||
/* Chains creation from a valid NMAuthSubject cannot fail since the
|
||||
* subject already has all the necessary auth info.
|
||||
*/
|
||||
g_assert (chain);
|
||||
return chain;
|
||||
self = g_malloc0 (sizeof (NMAuthChain));
|
||||
self->refcount = 1;
|
||||
self->data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_data);
|
||||
self->done_func = done_func;
|
||||
self->user_data = user_data;
|
||||
self->context = context;
|
||||
self->subject = g_object_ref (subject);
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
gpointer
|
||||
|
@ -364,128 +298,86 @@ auth_call_cancel (gpointer user_data)
|
|||
}
|
||||
}
|
||||
|
||||
#if WITH_POLKIT
|
||||
static void
|
||||
pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
AuthCall *call = user_data;
|
||||
PolkitAuthorizationResult *pk_result;
|
||||
GError *error = NULL;
|
||||
gboolean is_authorized, is_challenge;
|
||||
|
||||
pk_result = polkit_authority_check_authorization_finish ((PolkitAuthority *) object, result, &error);
|
||||
nm_auth_manager_polkit_authority_check_authorization_finish (NM_AUTH_MANAGER (object),
|
||||
result,
|
||||
&is_authorized,
|
||||
&is_challenge,
|
||||
&error);
|
||||
|
||||
/* If the call is already canceled do nothing */
|
||||
if (!call->cancellable) {
|
||||
nm_log_dbg (LOGD_CORE, "callback already cancelled");
|
||||
g_clear_error (&error);
|
||||
g_clear_object (&pk_result);
|
||||
auth_call_free (call);
|
||||
return;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
if (!call->chain->error)
|
||||
call->chain->error = g_error_copy (error);
|
||||
|
||||
nm_log_warn (LOGD_CORE, "error requesting auth for %s: (%d) %s",
|
||||
call->permission, error->code, error->message);
|
||||
|
||||
if (!call->chain->error) {
|
||||
call->chain->error = error;
|
||||
error = NULL;
|
||||
} else
|
||||
g_clear_error (&error);
|
||||
} else {
|
||||
guint call_result = NM_AUTH_CALL_RESULT_UNKNOWN;
|
||||
|
||||
if (polkit_authorization_result_get_is_authorized (pk_result)) {
|
||||
if (is_authorized) {
|
||||
/* Caller has the permission */
|
||||
call_result = NM_AUTH_CALL_RESULT_YES;
|
||||
} else if (polkit_authorization_result_get_is_challenge (pk_result)) {
|
||||
} else if (is_challenge) {
|
||||
/* Caller could authenticate to get the permission */
|
||||
call_result = NM_AUTH_CALL_RESULT_AUTH;
|
||||
} else
|
||||
call_result = NM_AUTH_CALL_RESULT_NO;
|
||||
|
||||
nm_auth_chain_set_data (call->chain, call->permission, GUINT_TO_POINTER (call_result), NULL);
|
||||
g_object_unref (pk_result);
|
||||
}
|
||||
|
||||
auth_call_complete (call);
|
||||
}
|
||||
|
||||
static void
|
||||
auth_call_schedule_complete_with_error (AuthCall *call, const char *msg)
|
||||
{
|
||||
if (!call->chain->error)
|
||||
call->chain->error = g_error_new_literal (DBUS_GERROR, DBUS_GERROR_FAILED, msg);
|
||||
call->call_idle_id = g_idle_add ((GSourceFunc) auth_call_complete, call);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_add_call_polkit (NMAuthChain *self,
|
||||
const char *permission,
|
||||
gboolean allow_interaction)
|
||||
{
|
||||
PolkitSubject *subject;
|
||||
PolkitCheckAuthorizationFlags flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE;
|
||||
AuthCall *call;
|
||||
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
g_return_val_if_fail (self->owner || self->subject, FALSE);
|
||||
g_return_val_if_fail (permission != NULL, FALSE);
|
||||
|
||||
call = auth_call_new (self, permission);
|
||||
|
||||
if (self->authority == NULL) {
|
||||
/* No polkit, no authorization */
|
||||
auth_call_schedule_complete_with_error (call, "PolicyKit not running");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (self->subject) {
|
||||
subject = g_object_ref (nm_auth_subject_get_polkit_subject (self->subject));
|
||||
g_assert (subject);
|
||||
} else {
|
||||
g_assert (self->owner);
|
||||
subject = polkit_system_bus_name_new (self->owner);
|
||||
if (!subject) {
|
||||
auth_call_schedule_complete_with_error (call, "Failed to create polkit subject");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
if (allow_interaction)
|
||||
flags = POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION;
|
||||
|
||||
call->cancellable = g_cancellable_new ();
|
||||
polkit_authority_check_authorization (self->authority,
|
||||
subject,
|
||||
permission,
|
||||
NULL,
|
||||
flags,
|
||||
call->cancellable,
|
||||
pk_call_cb,
|
||||
call);
|
||||
g_object_unref (subject);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
gboolean
|
||||
void
|
||||
nm_auth_chain_add_call (NMAuthChain *self,
|
||||
const char *permission,
|
||||
gboolean allow_interaction)
|
||||
{
|
||||
AuthCall *call;
|
||||
NMAuthManager *auth_manager = nm_auth_manager_get ();
|
||||
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
g_return_if_fail (self != NULL);
|
||||
g_return_if_fail (permission && *permission);
|
||||
g_return_if_fail (self->subject);
|
||||
g_return_if_fail (nm_auth_subject_is_unix_process (self->subject) || nm_auth_subject_is_internal (self->subject));
|
||||
|
||||
#if WITH_POLKIT
|
||||
/* Non-root always gets authenticated when using polkit */
|
||||
if (self->user_uid > 0)
|
||||
return _add_call_polkit (self, permission, allow_interaction);
|
||||
#endif
|
||||
|
||||
/* Root user or non-polkit always gets the permission */
|
||||
call = auth_call_new (self, permission);
|
||||
|
||||
if ( nm_auth_subject_is_internal (self->subject)
|
||||
|| nm_auth_subject_get_unix_process_uid (self->subject) == 0
|
||||
|| !nm_auth_manager_get_polkit_enabled (auth_manager)) {
|
||||
/* Root user or non-polkit always gets the permission */
|
||||
nm_auth_chain_set_data (self, permission, GUINT_TO_POINTER (NM_AUTH_CALL_RESULT_YES), NULL);
|
||||
call->call_idle_id = g_idle_add ((GSourceFunc) auth_call_complete, call);
|
||||
return TRUE;
|
||||
} else {
|
||||
/* Non-root always gets authenticated when using polkit */
|
||||
call->cancellable = g_cancellable_new ();
|
||||
nm_auth_manager_polkit_authority_check_authorization (auth_manager,
|
||||
self->subject,
|
||||
permission,
|
||||
allow_interaction,
|
||||
call->cancellable,
|
||||
pk_call_cb,
|
||||
call);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -500,11 +392,6 @@ nm_auth_chain_unref (NMAuthChain *self)
|
|||
if (self->idle_id)
|
||||
g_source_remove (self->idle_id);
|
||||
|
||||
#if WITH_POLKIT
|
||||
if (self->authority)
|
||||
g_object_unref (self->authority);
|
||||
#endif
|
||||
g_free (self->owner);
|
||||
g_object_unref (self->subject);
|
||||
|
||||
g_slist_free_full (self->calls, auth_call_cancel);
|
||||
|
@ -519,17 +406,25 @@ nm_auth_chain_unref (NMAuthChain *self)
|
|||
/************ utils **************/
|
||||
|
||||
gboolean
|
||||
nm_auth_uid_in_acl (NMConnection *connection,
|
||||
nm_auth_is_subject_in_acl (NMConnection *connection,
|
||||
NMSessionMonitor *smon,
|
||||
gulong uid,
|
||||
NMAuthSubject *subject,
|
||||
char **out_error_desc)
|
||||
{
|
||||
NMSettingConnection *s_con;
|
||||
const char *user = NULL;
|
||||
GError *local = NULL;
|
||||
gulong uid;
|
||||
|
||||
g_return_val_if_fail (connection != NULL, FALSE);
|
||||
g_return_val_if_fail (smon != NULL, FALSE);
|
||||
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), FALSE);
|
||||
g_return_val_if_fail (nm_auth_subject_is_internal (subject) || nm_auth_subject_is_unix_process (subject), FALSE);
|
||||
|
||||
if (nm_auth_subject_is_internal (subject))
|
||||
return TRUE;
|
||||
|
||||
uid = nm_auth_subject_get_unix_process_uid (subject);
|
||||
|
||||
/* Root gets a free pass */
|
||||
if (0 == uid)
|
||||
|
@ -570,87 +465,4 @@ nm_auth_uid_in_acl (NMConnection *connection,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
GDestroyNotify changed_callback;
|
||||
gpointer changed_data;
|
||||
} PkChangedInfo;
|
||||
|
||||
static GSList *funcs = NULL;
|
||||
|
||||
#if WITH_POLKIT
|
||||
static void
|
||||
pk_authority_changed_cb (GObject *object, gpointer unused)
|
||||
{
|
||||
GSList *iter;
|
||||
|
||||
for (iter = funcs; iter; iter = g_slist_next (iter)) {
|
||||
PkChangedInfo *info = iter->data;
|
||||
|
||||
info->changed_callback (info->changed_data);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void
|
||||
nm_auth_changed_func_register (GDestroyNotify callback, gpointer callback_data)
|
||||
{
|
||||
#if WITH_POLKIT
|
||||
PolkitAuthority *authority;
|
||||
static guint32 changed_id = 0;
|
||||
#endif
|
||||
PkChangedInfo *info;
|
||||
GSList *iter;
|
||||
gboolean found = FALSE;
|
||||
|
||||
#if WITH_POLKIT
|
||||
authority = pk_authority_get (NULL);
|
||||
if (!authority)
|
||||
return;
|
||||
|
||||
/* Hook up the changed signal the first time a callback is registered */
|
||||
if (changed_id == 0) {
|
||||
changed_id = g_signal_connect (authority,
|
||||
"changed",
|
||||
G_CALLBACK (pk_authority_changed_cb),
|
||||
&funcs);
|
||||
}
|
||||
#endif
|
||||
|
||||
/* No duplicates */
|
||||
for (iter = funcs; iter; iter = g_slist_next (iter)) {
|
||||
info = iter->data;
|
||||
if ((callback == info->changed_callback) && (callback_data == info->changed_data)) {
|
||||
found = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_warn_if_fail (found == FALSE);
|
||||
if (found == FALSE) {
|
||||
info = g_malloc0 (sizeof (*info));
|
||||
info->changed_callback = callback;
|
||||
info->changed_data = callback_data;
|
||||
funcs = g_slist_append (funcs, info);
|
||||
}
|
||||
|
||||
#if WITH_POLKIT
|
||||
g_object_unref (authority);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nm_auth_changed_func_unregister (GDestroyNotify callback, gpointer callback_data)
|
||||
{
|
||||
GSList *iter;
|
||||
|
||||
for (iter = funcs; iter; iter = g_slist_next (iter)) {
|
||||
PkChangedInfo *info = iter->data;
|
||||
|
||||
if ((callback == info->changed_callback) && (callback_data == info->changed_data)) {
|
||||
g_free (info);
|
||||
funcs = g_slist_delete_link (funcs, iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -54,11 +54,6 @@ typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain,
|
|||
DBusGMethodInvocation *context,
|
||||
gpointer user_data);
|
||||
|
||||
NMAuthChain *nm_auth_chain_new_dbus_sender (const char *dbus_sender,
|
||||
gulong user_uid,
|
||||
NMAuthChainResultFunc done_func,
|
||||
gpointer user_data);
|
||||
|
||||
NMAuthChain *nm_auth_chain_new_context (DBusGMethodInvocation *context,
|
||||
NMAuthChainResultFunc done_func,
|
||||
gpointer user_data);
|
||||
|
@ -86,21 +81,17 @@ gulong nm_auth_chain_get_data_ulong (NMAuthChain *chain, const char *tag);
|
|||
NMAuthCallResult nm_auth_chain_get_result (NMAuthChain *chain,
|
||||
const char *permission);
|
||||
|
||||
gboolean nm_auth_chain_add_call (NMAuthChain *chain,
|
||||
void nm_auth_chain_add_call (NMAuthChain *chain,
|
||||
const char *permission,
|
||||
gboolean allow_interaction);
|
||||
|
||||
void nm_auth_chain_unref (NMAuthChain *chain);
|
||||
|
||||
/* Caller must free returned error description */
|
||||
gboolean nm_auth_uid_in_acl (NMConnection *connection,
|
||||
gboolean nm_auth_is_subject_in_acl (NMConnection *connection,
|
||||
NMSessionMonitor *smon,
|
||||
gulong uid,
|
||||
NMAuthSubject *subect,
|
||||
char **out_error_desc);
|
||||
|
||||
void nm_auth_changed_func_register (GDestroyNotify callback, gpointer callback_data);
|
||||
|
||||
void nm_auth_changed_func_unregister (GDestroyNotify callback, gpointer callback_data);
|
||||
|
||||
#endif /* __NETWORKMANAGER_MANAGER_AUTH_H__ */
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ typedef struct {
|
|||
|
||||
char **plugins;
|
||||
gboolean monitor_connection_files;
|
||||
gboolean auth_polkit;
|
||||
char *dhcp_client;
|
||||
char *dns_mode;
|
||||
|
||||
|
@ -142,6 +143,14 @@ nm_config_get_monitor_connection_files (NMConfig *config)
|
|||
return NM_CONFIG_GET_PRIVATE (config)->monitor_connection_files;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_config_get_auth_polkit (NMConfig *config)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_CONFIG (config), NM_CONFIG_DEFAULT_AUTH_POLKIT);
|
||||
|
||||
return NM_CONFIG_GET_PRIVATE (config)->auth_polkit;
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_config_get_dhcp_client (NMConfig *config)
|
||||
{
|
||||
|
@ -580,6 +589,16 @@ nm_config_new (GError **error)
|
|||
g_free (value);
|
||||
}
|
||||
|
||||
value = g_key_file_get_value (priv->keyfile, "main", "auth-polkit", NULL);
|
||||
priv->auth_polkit = NM_CONFIG_DEFAULT_AUTH_POLKIT;
|
||||
if (value) {
|
||||
if (!_parse_bool_str (value, &priv->auth_polkit)) {
|
||||
nm_log_warn (LOGD_CORE, "Unrecognized value for main.auth-polkit: %s. Assuming '%s'", value,
|
||||
NM_CONFIG_DEFAULT_AUTH_POLKIT ? "true" : "false");
|
||||
}
|
||||
g_free (value);
|
||||
}
|
||||
|
||||
priv->dhcp_client = g_key_file_get_value (priv->keyfile, "main", "dhcp", NULL);
|
||||
priv->dns_mode = g_key_file_get_value (priv->keyfile, "main", "dns", NULL);
|
||||
|
||||
|
@ -610,6 +629,8 @@ nm_config_init (NMConfig *config)
|
|||
{
|
||||
NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config);
|
||||
|
||||
priv->auth_polkit = NM_CONFIG_DEFAULT_AUTH_POLKIT;
|
||||
|
||||
priv->keyfile = g_key_file_new ();
|
||||
g_key_file_set_list_separator (priv->keyfile, ',');
|
||||
|
||||
|
|
|
@ -52,6 +52,7 @@ const char *nm_config_get_path (NMConfig *config);
|
|||
const char *nm_config_get_description (NMConfig *config);
|
||||
const char **nm_config_get_plugins (NMConfig *config);
|
||||
gboolean nm_config_get_monitor_connection_files (NMConfig *config);
|
||||
gboolean nm_config_get_auth_polkit (NMConfig *config);
|
||||
const char *nm_config_get_dhcp_client (NMConfig *config);
|
||||
const char *nm_config_get_dns_mode (NMConfig *config);
|
||||
const char *nm_config_get_log_level (NMConfig *config);
|
||||
|
|
|
@ -50,6 +50,7 @@
|
|||
#include "nm-settings.h"
|
||||
#include "nm-settings-connection.h"
|
||||
#include "nm-auth-utils.h"
|
||||
#include "nm-auth-manager.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-utils.h"
|
||||
#include "nm-device-factory.h"
|
||||
|
@ -1452,7 +1453,7 @@ device_auth_request_cb (NMDevice *device,
|
|||
NMAuthChain *chain;
|
||||
|
||||
/* Validate the caller */
|
||||
subject = nm_auth_subject_new_from_context (context);
|
||||
subject = nm_auth_subject_new_unix_process_from_context (context);
|
||||
if (!subject) {
|
||||
error = g_error_new_literal (NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
||||
|
@ -1461,9 +1462,9 @@ device_auth_request_cb (NMDevice *device,
|
|||
}
|
||||
|
||||
/* Ensure the subject has permissions for this connection */
|
||||
if (connection && !nm_auth_uid_in_acl (connection,
|
||||
if (connection && !nm_auth_is_subject_in_acl (connection,
|
||||
nm_session_monitor_get (),
|
||||
nm_auth_subject_get_uid (subject),
|
||||
subject,
|
||||
&error_desc)) {
|
||||
error = g_error_new_literal (NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
||||
|
@ -2662,9 +2663,9 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
|
|||
existing_connection = nm_device_get_connection (device);
|
||||
subject = nm_active_connection_get_subject (active);
|
||||
if (existing_connection &&
|
||||
!nm_auth_uid_in_acl (existing_connection,
|
||||
!nm_auth_is_subject_in_acl (existing_connection,
|
||||
nm_session_monitor_get (),
|
||||
nm_auth_subject_get_uid (subject),
|
||||
subject,
|
||||
&error_desc)) {
|
||||
g_set_error (error,
|
||||
NM_MANAGER_ERROR,
|
||||
|
@ -2954,9 +2955,9 @@ nm_manager_activate_connection (NMManager *self,
|
|||
g_return_val_if_fail (*error == NULL, NULL);
|
||||
|
||||
/* Ensure the subject has permissions for this connection */
|
||||
if (!nm_auth_uid_in_acl (connection,
|
||||
if (!nm_auth_is_subject_in_acl (connection,
|
||||
nm_session_monitor_get (),
|
||||
nm_auth_subject_get_uid (subject),
|
||||
subject,
|
||||
&error_desc)) {
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR,
|
||||
|
@ -2998,7 +2999,7 @@ validate_activation_request (NMManager *self,
|
|||
g_assert (out_vpn);
|
||||
|
||||
/* Validate the caller */
|
||||
subject = nm_auth_subject_new_from_context (context);
|
||||
subject = nm_auth_subject_new_unix_process_from_context (context);
|
||||
if (!subject) {
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR,
|
||||
|
@ -3008,9 +3009,9 @@ validate_activation_request (NMManager *self,
|
|||
}
|
||||
|
||||
/* Ensure the subject has permissions for this connection */
|
||||
if (!nm_auth_uid_in_acl (connection,
|
||||
if (!nm_auth_is_subject_in_acl (connection,
|
||||
nm_session_monitor_get (),
|
||||
nm_auth_subject_get_uid (subject),
|
||||
subject,
|
||||
&error_desc)) {
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR,
|
||||
|
@ -3528,7 +3529,7 @@ impl_manager_deactivate_connection (NMManager *self,
|
|||
}
|
||||
|
||||
/* Validate the caller */
|
||||
subject = nm_auth_subject_new_from_context (context);
|
||||
subject = nm_auth_subject_new_unix_process_from_context (context);
|
||||
if (!subject) {
|
||||
error = g_error_new_literal (NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
||||
|
@ -3537,9 +3538,9 @@ impl_manager_deactivate_connection (NMManager *self,
|
|||
}
|
||||
|
||||
/* Ensure the subject has permissions for this connection */
|
||||
if (!nm_auth_uid_in_acl (connection,
|
||||
if (!nm_auth_is_subject_in_acl (connection,
|
||||
nm_session_monitor_get (),
|
||||
nm_auth_subject_get_uid (subject),
|
||||
subject,
|
||||
&error_desc)) {
|
||||
error = g_error_new_literal (NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
||||
|
@ -4434,7 +4435,7 @@ prop_filter (DBusConnection *connection,
|
|||
goto out;
|
||||
}
|
||||
|
||||
subject = nm_auth_subject_new_from_message (connection, message);
|
||||
subject = nm_auth_subject_new_unix_process_from_message (connection, message);
|
||||
if (!subject) {
|
||||
reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR,
|
||||
"Could not determine request UID.");
|
||||
|
@ -4469,7 +4470,7 @@ out:
|
|||
}
|
||||
|
||||
static void
|
||||
authority_changed_cb (gpointer user_data)
|
||||
authority_changed_cb (NMAuthManager *auth_manager, gpointer user_data)
|
||||
{
|
||||
/* Let clients know they should re-check their authorization */
|
||||
g_signal_emit (NM_MANAGER (user_data), signals[CHECK_PERMISSIONS], 0);
|
||||
|
@ -4834,7 +4835,11 @@ nm_manager_init (NMManager *manager)
|
|||
G_CALLBACK (resuming_cb), manager);
|
||||
|
||||
/* Listen for authorization changes */
|
||||
nm_auth_changed_func_register (authority_changed_cb, manager);
|
||||
g_signal_connect (nm_auth_manager_get (),
|
||||
NM_AUTH_MANAGER_SIGNAL_CHANGED,
|
||||
G_CALLBACK (authority_changed_cb),
|
||||
manager);
|
||||
|
||||
|
||||
/* Monitor the firmware directory */
|
||||
if (strlen (KERNEL_FIRMWARE_DIR)) {
|
||||
|
@ -4986,7 +4991,9 @@ dispose (GObject *object)
|
|||
g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref);
|
||||
priv->auth_chains = NULL;
|
||||
|
||||
nm_auth_changed_func_unregister (authority_changed_cb, manager);
|
||||
g_signal_handlers_disconnect_by_func (nm_auth_manager_get (),
|
||||
G_CALLBACK (authority_changed_cb),
|
||||
manager);
|
||||
|
||||
/* Remove all devices */
|
||||
while (priv->devices)
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
#include "nm-setting-vpn.h"
|
||||
#include "nm-setting-connection.h"
|
||||
#include "nm-enum-types.h"
|
||||
#include "nm-auth-subject.h"
|
||||
#include "nm-auth-manager.h"
|
||||
#include "nm-dbus-manager.h"
|
||||
#include "nm-session-monitor.h"
|
||||
#include "nm-simple-connection.h"
|
||||
|
@ -290,14 +290,14 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
|
|||
NMSecretAgent *agent;
|
||||
NMAuthChain *chain;
|
||||
|
||||
subject = nm_auth_subject_new_from_context (context);
|
||||
subject = nm_auth_subject_new_unix_process_from_context (context);
|
||||
if (!subject) {
|
||||
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
||||
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
|
||||
"Unable to determine request sender and UID.");
|
||||
goto done;
|
||||
}
|
||||
sender_uid = nm_auth_subject_get_uid (subject);
|
||||
sender_uid = nm_auth_subject_get_unix_process_uid (subject);
|
||||
|
||||
if ( 0 != sender_uid
|
||||
&& !nm_session_monitor_uid_has_session (nm_session_monitor_get (),
|
||||
|
@ -529,8 +529,8 @@ agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data)
|
|||
gulong a_pid, b_pid, requester;
|
||||
|
||||
/* Prefer agents in the process the request came from */
|
||||
requester = nm_auth_subject_get_pid (req->subject);
|
||||
if (requester != G_MAXULONG) {
|
||||
if (nm_auth_subject_is_unix_process (req->subject)) {
|
||||
requester = nm_auth_subject_get_unix_process_pid (req->subject);
|
||||
a_pid = nm_secret_agent_get_pid (a);
|
||||
b_pid = nm_secret_agent_get_pid (b);
|
||||
|
||||
|
@ -572,11 +572,11 @@ request_add_agent (Request *req, NMSecretAgent *agent)
|
|||
return;
|
||||
|
||||
/* If the request should filter agents by UID, do that now */
|
||||
if (!nm_auth_subject_get_internal (req->subject)) {
|
||||
if (nm_auth_subject_is_unix_process (req->subject)) {
|
||||
uid_t agent_uid, subject_uid;
|
||||
|
||||
agent_uid = nm_secret_agent_get_owner_uid (agent);
|
||||
subject_uid = nm_auth_subject_get_uid (req->subject);
|
||||
subject_uid = nm_auth_subject_get_unix_process_uid (req->subject);
|
||||
if (agent_uid != subject_uid) {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s "
|
||||
"(uid %ld not required %ld)",
|
||||
|
@ -713,12 +713,12 @@ static gboolean
|
|||
connection_request_add_agent (Request *parent, NMSecretAgent *agent)
|
||||
{
|
||||
ConnectionRequest *req = (ConnectionRequest *) parent;
|
||||
uid_t agent_uid = nm_secret_agent_get_owner_uid (agent);
|
||||
NMAuthSubject *subject = nm_secret_agent_get_subject(agent);
|
||||
|
||||
/* Ensure the caller's username exists in the connection's permissions,
|
||||
* or that the permissions is empty (ie, visible by everyone).
|
||||
*/
|
||||
if (!nm_auth_uid_in_acl (req->connection, nm_session_monitor_get (), agent_uid, NULL)) {
|
||||
if (!nm_auth_is_subject_in_acl (req->connection, nm_session_monitor_get (), subject, NULL)) {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s (not in ACL)",
|
||||
nm_secret_agent_get_description (agent),
|
||||
parent, parent->detail);
|
||||
|
@ -1454,11 +1454,13 @@ nm_agent_manager_all_agents_have_capability (NMAgentManager *manager,
|
|||
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (manager);
|
||||
GHashTableIter iter;
|
||||
NMSecretAgent *agent;
|
||||
gboolean subject_is_unix_process = nm_auth_subject_is_unix_process (subject);
|
||||
gulong subject_uid = subject_is_unix_process ? nm_auth_subject_get_unix_process_uid (subject) : 0;
|
||||
|
||||
g_hash_table_iter_init (&iter, priv->agents);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) {
|
||||
if ( !nm_auth_subject_get_internal (subject)
|
||||
&& nm_secret_agent_get_owner_uid (agent) != nm_auth_subject_get_uid (subject))
|
||||
if ( subject_is_unix_process
|
||||
&& nm_secret_agent_get_owner_uid (agent) != subject_uid)
|
||||
continue;
|
||||
|
||||
if (!(nm_secret_agent_get_capabilities (agent) & capability))
|
||||
|
@ -1519,9 +1521,8 @@ agent_permissions_changed_done (NMAuthChain *chain,
|
|||
}
|
||||
|
||||
static void
|
||||
authority_changed_cb (gpointer user_data)
|
||||
authority_changed_cb (NMAuthManager *auth_manager, NMAgentManager *self)
|
||||
{
|
||||
NMAgentManager *self = NM_AGENT_MANAGER (user_data);
|
||||
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
||||
GHashTableIter iter;
|
||||
NMSecretAgent *agent;
|
||||
|
@ -1572,7 +1573,10 @@ nm_agent_manager_get (void)
|
|||
G_CALLBACK (name_owner_changed_cb),
|
||||
singleton);
|
||||
|
||||
nm_auth_changed_func_register (authority_changed_cb, singleton);
|
||||
g_signal_connect (nm_auth_manager_get (),
|
||||
NM_AUTH_MANAGER_SIGNAL_CHANGED,
|
||||
G_CALLBACK (authority_changed_cb),
|
||||
singleton);
|
||||
|
||||
return singleton;
|
||||
}
|
||||
|
@ -1597,7 +1601,9 @@ dispose (GObject *object)
|
|||
if (!priv->disposed) {
|
||||
priv->disposed = TRUE;
|
||||
|
||||
nm_auth_changed_func_unregister (authority_changed_cb, NM_AGENT_MANAGER (object));
|
||||
g_signal_handlers_disconnect_by_func (nm_auth_manager_get (),
|
||||
G_CALLBACK (authority_changed_cb),
|
||||
object);
|
||||
|
||||
g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_unref);
|
||||
|
||||
|
|
|
@ -108,9 +108,9 @@ nm_secret_agent_get_description (NMSecretAgent *agent)
|
|||
priv = NM_SECRET_AGENT_GET_PRIVATE (agent);
|
||||
if (!priv->description) {
|
||||
priv->description = g_strdup_printf ("%s/%s/%lu",
|
||||
nm_auth_subject_get_dbus_sender (priv->subject),
|
||||
nm_auth_subject_get_unix_process_dbus_sender (priv->subject),
|
||||
priv->identifier,
|
||||
nm_auth_subject_get_uid (priv->subject));
|
||||
nm_auth_subject_get_unix_process_uid (priv->subject));
|
||||
}
|
||||
|
||||
return priv->description;
|
||||
|
@ -121,7 +121,7 @@ nm_secret_agent_get_dbus_owner (NMSecretAgent *agent)
|
|||
{
|
||||
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
|
||||
|
||||
return nm_auth_subject_get_dbus_sender (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
|
||||
return nm_auth_subject_get_unix_process_dbus_sender (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
|
||||
}
|
||||
|
||||
const char *
|
||||
|
@ -137,7 +137,7 @@ nm_secret_agent_get_owner_uid (NMSecretAgent *agent)
|
|||
{
|
||||
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXULONG);
|
||||
|
||||
return nm_auth_subject_get_uid (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
|
||||
return nm_auth_subject_get_unix_process_uid (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
|
||||
}
|
||||
|
||||
const char *
|
||||
|
@ -153,7 +153,7 @@ nm_secret_agent_get_pid (NMSecretAgent *agent)
|
|||
{
|
||||
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXULONG);
|
||||
|
||||
return nm_auth_subject_get_pid (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
|
||||
return nm_auth_subject_get_unix_process_pid (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
|
||||
}
|
||||
|
||||
NMSecretAgentCapabilities
|
||||
|
@ -477,9 +477,10 @@ nm_secret_agent_new (DBusGMethodInvocation *context,
|
|||
|
||||
g_return_val_if_fail (context != NULL, NULL);
|
||||
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
|
||||
g_return_val_if_fail (nm_auth_subject_is_unix_process (subject), NULL);
|
||||
g_return_val_if_fail (identifier != NULL, NULL);
|
||||
|
||||
pw = getpwuid (nm_auth_subject_get_uid (subject));
|
||||
pw = getpwuid (nm_auth_subject_get_unix_process_uid (subject));
|
||||
g_return_val_if_fail (pw != NULL, NULL);
|
||||
g_return_val_if_fail (pw->pw_name[0] != '\0', NULL);
|
||||
username = g_strdup (pw->pw_name);
|
||||
|
@ -492,13 +493,13 @@ nm_secret_agent_new (DBusGMethodInvocation *context,
|
|||
priv->capabilities = capabilities;
|
||||
priv->subject = g_object_ref (subject);
|
||||
|
||||
hash_str = g_strdup_printf ("%16lu%s", nm_auth_subject_get_uid (subject), identifier);
|
||||
hash_str = g_strdup_printf ("%16lu%s", nm_auth_subject_get_unix_process_uid (subject), identifier);
|
||||
priv->hash = g_str_hash (hash_str);
|
||||
g_free (hash_str);
|
||||
|
||||
priv->proxy = nm_dbus_manager_new_proxy (nm_dbus_manager_get (),
|
||||
context,
|
||||
nm_auth_subject_get_dbus_sender (subject),
|
||||
nm_auth_subject_get_unix_process_dbus_sender (subject),
|
||||
NM_DBUS_PATH_SECRET_AGENT,
|
||||
NM_DBUS_INTERFACE_SECRET_AGENT);
|
||||
g_assert (priv->proxy);
|
||||
|
|
|
@ -1029,7 +1029,7 @@ _new_auth_subject (DBusGMethodInvocation *context, GError **error)
|
|||
{
|
||||
NMAuthSubject *subject;
|
||||
|
||||
subject = nm_auth_subject_new_from_context (context);
|
||||
subject = nm_auth_subject_new_unix_process_from_context (context);
|
||||
if (!subject) {
|
||||
g_set_error_literal (error,
|
||||
NM_SETTINGS_ERROR,
|
||||
|
@ -1057,9 +1057,9 @@ auth_start (NMSettingsConnection *self,
|
|||
g_return_if_fail (NM_IS_AUTH_SUBJECT (subject));
|
||||
|
||||
/* Ensure the caller can view this connection */
|
||||
if (!nm_auth_uid_in_acl (NM_CONNECTION (self),
|
||||
if (!nm_auth_is_subject_in_acl (NM_CONNECTION (self),
|
||||
priv->session_monitor,
|
||||
nm_auth_subject_get_uid (subject),
|
||||
subject,
|
||||
&error_desc)) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_PERMISSION_DENIED,
|
||||
|
@ -1414,9 +1414,9 @@ impl_settings_connection_update_helper (NMSettingsConnection *self,
|
|||
* that's sending the update request. You can't make a connection
|
||||
* invisible to yourself.
|
||||
*/
|
||||
if (!nm_auth_uid_in_acl (tmp ? tmp : NM_CONNECTION (self),
|
||||
if (!nm_auth_is_subject_in_acl (tmp ? tmp : NM_CONNECTION (self),
|
||||
priv->session_monitor,
|
||||
nm_auth_subject_get_uid (subject),
|
||||
subject,
|
||||
&error_desc)) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_PERMISSION_DENIED,
|
||||
|
|
|
@ -288,7 +288,7 @@ impl_settings_get_connection_by_uuid (NMSettings *self,
|
|||
goto error;
|
||||
}
|
||||
|
||||
subject = nm_auth_subject_new_from_context (context);
|
||||
subject = nm_auth_subject_new_unix_process_from_context (context);
|
||||
if (!subject) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_PERMISSION_DENIED,
|
||||
|
@ -296,9 +296,9 @@ impl_settings_get_connection_by_uuid (NMSettings *self,
|
|||
goto error;
|
||||
}
|
||||
|
||||
if (!nm_auth_uid_in_acl (NM_CONNECTION (connection),
|
||||
if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection),
|
||||
nm_session_monitor_get (),
|
||||
nm_auth_subject_get_uid (subject),
|
||||
subject,
|
||||
&error_desc)) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_PERMISSION_DENIED,
|
||||
|
@ -1142,7 +1142,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
|
|||
goto done;
|
||||
}
|
||||
|
||||
subject = nm_auth_subject_new_from_context (context);
|
||||
subject = nm_auth_subject_new_unix_process_from_context (context);
|
||||
if (!subject) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_PERMISSION_DENIED,
|
||||
|
@ -1153,9 +1153,9 @@ nm_settings_add_connection_dbus (NMSettings *self,
|
|||
/* Ensure the caller's username exists in the connection's permissions,
|
||||
* or that the permissions is empty (ie, visible by everyone).
|
||||
*/
|
||||
if (!nm_auth_uid_in_acl (connection,
|
||||
if (!nm_auth_is_subject_in_acl (connection,
|
||||
nm_session_monitor_get (),
|
||||
nm_auth_subject_get_uid (subject),
|
||||
subject,
|
||||
&error_desc)) {
|
||||
error = g_error_new_literal (NM_SETTINGS_ERROR,
|
||||
NM_SETTINGS_ERROR_PERMISSION_DENIED,
|
||||
|
|
Loading…
Reference in a new issue