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:
Thomas Haller 2014-08-14 13:34:57 +02:00
parent 63a8c6a184
commit eabe7d856c
19 changed files with 1334 additions and 487 deletions

View File

@ -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)"
else
echo " policykit: yes (restrictive modify.system)"
fi
if test "${enable_modify_system}" = "yes"; then
echo " policykit: yes (permissive modify.system) (default=${enable_polkit})"
else
echo " policykit: no"
echo " policykit: yes (restrictive modify.system) (default=${enable_polkit})"
fi
echo " selinux: $have_selinux"
echo

View File

@ -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}

View File

@ -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

View File

@ -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) \

View File

@ -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);

View File

@ -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
View 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
View 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 */

View File

@ -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))
typedef struct {
gulong pid;
gulong uid;
char *dbus_sender;
enum {
PROP_0,
PROP_SUBJECT_TYPE,
PROP_UNIX_PROCESS_DBUS_SENDER,
PROP_UNIX_PROCESS_PID,
PROP_UNIX_PROCESS_UID,
#if WITH_POLKIT
PolkitSubject *pk_subject;
#endif
PROP_LAST,
};
typedef struct {
NMAuthSubjectType subject_type;
struct {
gulong pid;
gulong uid;
guint64 start_time;
char *dbus_sender;
} 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;
}
NMAuthSubject *
nm_auth_subject_new_from_context (DBusGMethodInvocation *context)
{
return _new_common (context, NULL, NULL, FALSE);
return self;
}
NMAuthSubject *
nm_auth_subject_new_from_message (DBusConnection *connection,
DBusMessage *message)
nm_auth_subject_new_unix_process_from_context (DBusGMethodInvocation *context)
{
return _new_common (NULL, connection, message, FALSE);
return _new_unix_process (context, NULL, NULL);
}
NMAuthSubject *
nm_auth_subject_new_unix_process_from_message (DBusConnection *connection,
DBusMessage *message)
{
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));
}

View File

@ -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__ */

View File

@ -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);
g_clear_error (&error);
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);
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;
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);
} 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,
NMSessionMonitor *smon,
gulong uid,
char **out_error_desc)
nm_auth_is_subject_in_acl (NMConnection *connection,
NMSessionMonitor *smon,
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;
}
}
}

View File

@ -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,
const char *permission,
gboolean allow_interaction);
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,
NMSessionMonitor *smon,
gulong uid,
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);
gboolean nm_auth_is_subject_in_acl (NMConnection *connection,
NMSessionMonitor *smon,
NMAuthSubject *subect,
char **out_error_desc);
#endif /* __NETWORKMANAGER_MANAGER_AUTH_H__ */

View File

@ -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, ',');

View File

@ -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);

View File

@ -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,10 +1462,10 @@ device_auth_request_cb (NMDevice *device,
}
/* Ensure the subject has permissions for this connection */
if (connection && !nm_auth_uid_in_acl (connection,
nm_session_monitor_get (),
nm_auth_subject_get_uid (subject),
&error_desc)) {
if (connection && !nm_auth_is_subject_in_acl (connection,
nm_session_monitor_get (),
subject,
&error_desc)) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
@ -2662,10 +2663,10 @@ _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_session_monitor_get (),
nm_auth_subject_get_uid (subject),
&error_desc)) {
!nm_auth_is_subject_in_acl (existing_connection,
nm_session_monitor_get (),
subject,
&error_desc)) {
g_set_error (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
@ -2954,10 +2955,10 @@ 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,
nm_session_monitor_get (),
nm_auth_subject_get_uid (subject),
&error_desc)) {
if (!nm_auth_is_subject_in_acl (connection,
nm_session_monitor_get (),
subject,
&error_desc)) {
g_set_error_literal (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
@ -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,10 +3009,10 @@ validate_activation_request (NMManager *self,
}
/* Ensure the subject has permissions for this connection */
if (!nm_auth_uid_in_acl (connection,
nm_session_monitor_get (),
nm_auth_subject_get_uid (subject),
&error_desc)) {
if (!nm_auth_is_subject_in_acl (connection,
nm_session_monitor_get (),
subject,
&error_desc)) {
g_set_error_literal (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
@ -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,10 +3538,10 @@ impl_manager_deactivate_connection (NMManager *self,
}
/* Ensure the subject has permissions for this connection */
if (!nm_auth_uid_in_acl (connection,
nm_session_monitor_get (),
nm_auth_subject_get_uid (subject),
&error_desc)) {
if (!nm_auth_is_subject_in_acl (connection,
nm_session_monitor_get (),
subject,
&error_desc)) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
error_desc);
@ -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)

View File

@ -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);

View File

@ -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);

View File

@ -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,10 +1057,10 @@ 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),
priv->session_monitor,
nm_auth_subject_get_uid (subject),
&error_desc)) {
if (!nm_auth_is_subject_in_acl (NM_CONNECTION (self),
priv->session_monitor,
subject,
&error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
@ -1414,10 +1414,10 @@ 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),
priv->session_monitor,
nm_auth_subject_get_uid (subject),
&error_desc)) {
if (!nm_auth_is_subject_in_acl (tmp ? tmp : NM_CONNECTION (self),
priv->session_monitor,
subject,
&error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);

View File

@ -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,10 +296,10 @@ impl_settings_get_connection_by_uuid (NMSettings *self,
goto error;
}
if (!nm_auth_uid_in_acl (NM_CONNECTION (connection),
nm_session_monitor_get (),
nm_auth_subject_get_uid (subject),
&error_desc)) {
if (!nm_auth_is_subject_in_acl (NM_CONNECTION (connection),
nm_session_monitor_get (),
subject,
&error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
@ -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,10 +1153,10 @@ 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,
nm_session_monitor_get (),
nm_auth_subject_get_uid (subject),
&error_desc)) {
if (!nm_auth_is_subject_in_acl (connection,
nm_session_monitor_get (),
subject,
&error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);