From 624e7deb47faaf34d356cf4249ad09094442fc60 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 17 Aug 2014 14:06:41 +0200 Subject: config: refactor parsing of boolean config values Allow for the special values "1" and "0". Also, ignore the letter case when comparing the configuration value. Signed-off-by: Thomas Haller --- src/nm-config.c | 52 +++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 9 deletions(-) diff --git a/src/nm-config.c b/src/nm-config.c index 8fc78602bc..3978b56626 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -70,6 +70,46 @@ G_DEFINE_TYPE (NMConfig, nm_config, G_TYPE_OBJECT) /************************************************************************/ +static gboolean +_parse_bool_str (const char *str, gboolean *out_value) +{ + gboolean value; + gsize len; + char *s = NULL; + + g_return_val_if_fail (str, FALSE); + + while (g_ascii_isspace (*str)) + str++; + + if (!*str) + return FALSE; + + len = strlen (str); + + if (g_ascii_isspace (str[len-1])) { + str = s = g_strdup (str); + g_strchomp (s); + } + + if (!g_ascii_strcasecmp (str, "true") || !g_ascii_strcasecmp (str, "yes") || !g_ascii_strcasecmp (str, "on") || !g_ascii_strcasecmp (str, "1")) + value = TRUE; + else if (!g_ascii_strcasecmp (str, "false") || !g_ascii_strcasecmp (str, "no") || !g_ascii_strcasecmp (str, "off") || !g_ascii_strcasecmp (str, "0")) + value = FALSE; + else { + g_free (s); + return FALSE; + } + + if (out_value) + *out_value = value; + + g_free (s); + return TRUE; +} + +/************************************************************************/ + const char * nm_config_get_path (NMConfig *config) { @@ -533,18 +573,12 @@ nm_config_new (GError **error) priv->plugins = g_key_file_get_string_list (priv->keyfile, "main", "plugins", NULL, NULL); value = g_key_file_get_value (priv->keyfile, "main", "monitor-connection-files", NULL); + priv->monitor_connection_files = FALSE; if (value) { - if (!strcmp (value, "true") || !strcmp (value, "yes") || !strcmp (value, "on")) - priv->monitor_connection_files = TRUE; - else if (!strcmp (value, "false") || !strcmp (value, "no") || !strcmp (value, "off")) - priv->monitor_connection_files = FALSE; - else { + if (!_parse_bool_str (value, &priv->monitor_connection_files)) nm_log_warn (LOGD_CORE, "Unrecognized value for main.monitor-connection-files: %s. Assuming 'false'", value); - priv->monitor_connection_files = FALSE; - } g_free (value); - } else - priv->monitor_connection_files = FALSE; + } 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); -- cgit v1.2.1 From 05494423de63892114653a05272b31b6dccbda53 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sat, 16 Aug 2014 01:33:46 +0200 Subject: auth: rename file nm-manager-auth.* to nm-auth-utils.* Signed-off-by: Thomas Haller --- src/Makefile.am | 4 +- src/NetworkManagerUtils.c | 2 +- src/devices/nm-device.c | 2 +- src/devices/wifi/nm-device-wifi.c | 2 +- src/nm-active-connection.c | 2 +- src/nm-auth-utils.c | 656 ++++++++++++++++++++++++++++++++++ src/nm-auth-utils.h | 106 ++++++ src/nm-manager-auth.c | 656 ---------------------------------- src/nm-manager-auth.h | 106 ------ src/nm-manager.c | 2 +- src/nm-policy.c | 2 +- src/settings/nm-agent-manager.c | 4 +- src/settings/nm-settings-connection.c | 2 +- src/settings/nm-settings.c | 2 +- 14 files changed, 774 insertions(+), 774 deletions(-) create mode 100644 src/nm-auth-utils.c create mode 100644 src/nm-auth-utils.h delete mode 100644 src/nm-manager-auth.c delete mode 100644 src/nm-manager-auth.h diff --git a/src/Makefile.am b/src/Makefile.am index 62a4aa55ef..c72c85fefc 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -230,10 +230,10 @@ nm_sources = \ nm-ip6-config.h \ nm-logging.c \ nm-logging.h \ - nm-manager-auth.c \ - nm-manager-auth.h \ nm-auth-subject.c \ nm-auth-subject.h \ + nm-auth-utils.c \ + nm-auth-utils.h \ nm-manager.c \ nm-manager.h \ nm-policy.c \ diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c index 63648e3322..0096313a44 100644 --- a/src/NetworkManagerUtils.c +++ b/src/NetworkManagerUtils.c @@ -44,7 +44,7 @@ #include "nm-setting-ip6-config.h" #include "nm-setting-wireless.h" #include "nm-setting-wireless-security.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "nm-posix-signals.h" #include "nm-dbus-glib-types.h" diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 4a5eb186c4..75b07d2f03 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -66,7 +66,7 @@ #include "nm-settings-connection.h" #include "nm-connection-provider.h" #include "nm-posix-signals.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "nm-dbus-glib-types.h" #include "nm-dispatcher.h" #include "nm-config.h" diff --git a/src/devices/wifi/nm-device-wifi.c b/src/devices/wifi/nm-device-wifi.c index 41a75da1a1..8508097886 100644 --- a/src/devices/wifi/nm-device-wifi.c +++ b/src/devices/wifi/nm-device-wifi.c @@ -53,7 +53,7 @@ #include "nm-ip4-config.h" #include "nm-setting-ip6-config.h" #include "nm-platform.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "nm-settings-connection.h" #include "nm-enum-types.h" #include "nm-dbus-glib-types.h" diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 130b5229b0..888bbd1797 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -27,7 +27,7 @@ #include "nm-dbus-manager.h" #include "nm-device.h" #include "nm-settings-connection.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "NetworkManagerUtils.h" diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c new file mode 100644 index 0000000000..b2d7cb3cbd --- /dev/null +++ b/src/nm-auth-utils.c @@ -0,0 +1,656 @@ +/* -*- 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) 2010 Red Hat, Inc. + */ + +#include +#include +#include + +#if WITH_POLKIT +#include +#endif + +#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-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; + + guint idle_id; + + NMAuthChainResultFunc done_func; + gpointer user_data; +}; + +typedef struct { + NMAuthChain *chain; + GCancellable *cancellable; + char *permission; + guint call_idle_id; +} AuthCall; + +typedef struct { + gpointer data; + GDestroyNotify destroy; +} ChainData; + +static void +free_data (gpointer data) +{ + ChainData *tmp = data; + + if (tmp->destroy) + tmp->destroy (tmp->data); + memset (tmp, 0, sizeof (ChainData)); + g_free (tmp); +} + +static gboolean +auth_chain_finish (gpointer user_data) +{ + NMAuthChain *self = user_data; + + self->idle_id = 0; + + /* Ensure we say alive across the callback */ + self->refcount++; + self->done_func (self, self->error, self->context, self->user_data); + nm_auth_chain_unref (self); + 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, + NMAuthChainResultFunc done_func, + gpointer user_data) +{ + NMAuthSubject *subject; + NMAuthChain *chain; + + g_return_val_if_fail (context != NULL, NULL); + + subject = nm_auth_subject_new_from_context (context); + if (!subject) + return NULL; + + chain = nm_auth_chain_new_subject (subject, + context, + done_func, + user_data); + g_object_unref (subject); + return chain; +} + +/* Requires an NMAuthSubject */ +NMAuthChain * +nm_auth_chain_new_subject (NMAuthSubject *subject, + DBusGMethodInvocation *context, + NMAuthChainResultFunc done_func, + gpointer user_data) +{ + NMAuthChain *chain; + + g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); + chain = _auth_chain_new (subject, NULL, G_MAXULONG, context, done_func, user_data); + + /* Chains creation from a valid NMAuthSubject cannot fail since the + * subject already has all the necessary auth info. + */ + g_assert (chain); + return chain; +} + +gpointer +nm_auth_chain_get_data (NMAuthChain *self, const char *tag) +{ + ChainData *tmp; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (tag != NULL, NULL); + + tmp = g_hash_table_lookup (self->data, tag); + return tmp ? tmp->data : NULL; +} + +/** + * nm_auth_chain_steal_data: + * @self: A #NMAuthChain. + * @tag: A "tag" uniquely identifying the data to steal. + * + * Removes the datum assocated with @tag from the chain's data associations, + * without invoking the association's destroy handler. The caller assumes + * ownership over the returned value. + * + * Returns: the datum originally associated with @tag + */ +gpointer +nm_auth_chain_steal_data (NMAuthChain *self, const char *tag) +{ + ChainData *tmp; + gpointer value = NULL; + + g_return_val_if_fail (self != NULL, NULL); + g_return_val_if_fail (tag != NULL, NULL); + + tmp = g_hash_table_lookup (self->data, tag); + if (tmp) { + g_hash_table_steal (self->data, tag); + value = tmp->data; + /* Make sure the destroy handler isn't called when freeing */ + tmp->destroy = NULL; + free_data (tmp); + } + return value; +} + +void +nm_auth_chain_set_data (NMAuthChain *self, + const char *tag, + gpointer data, + GDestroyNotify data_destroy) +{ + ChainData *tmp; + + g_return_if_fail (self != NULL); + g_return_if_fail (tag != NULL); + + if (data == NULL) + g_hash_table_remove (self->data, tag); + else { + tmp = g_malloc0 (sizeof (ChainData)); + tmp->data = data; + tmp->destroy = data_destroy; + + g_hash_table_insert (self->data, g_strdup (tag), tmp); + } +} + +gulong +nm_auth_chain_get_data_ulong (NMAuthChain *self, const char *tag) +{ + gulong *ptr; + + g_return_val_if_fail (self != NULL, 0); + g_return_val_if_fail (tag != NULL, 0); + + ptr = nm_auth_chain_get_data (self, tag); + return *ptr; +} + + +void +nm_auth_chain_set_data_ulong (NMAuthChain *self, + const char *tag, + gulong data) +{ + gulong *ptr; + + g_return_if_fail (self != NULL); + g_return_if_fail (tag != NULL); + + ptr = g_malloc (sizeof (*ptr)); + *ptr = data; + nm_auth_chain_set_data (self, tag, ptr, g_free); +} + +NMAuthCallResult +nm_auth_chain_get_result (NMAuthChain *self, const char *permission) +{ + g_return_val_if_fail (self != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); + g_return_val_if_fail (permission != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); + + return GPOINTER_TO_UINT (nm_auth_chain_get_data (self, permission)); +} + +static void +nm_auth_chain_check_done (NMAuthChain *self) +{ + g_return_if_fail (self != NULL); + + if (g_slist_length (self->calls) == 0) { + g_assert (self->idle_id == 0); + self->idle_id = g_idle_add (auth_chain_finish, self); + } +} + +static void +nm_auth_chain_remove_call (NMAuthChain *self, AuthCall *call) +{ + g_return_if_fail (self != NULL); + g_return_if_fail (call != NULL); + + self->calls = g_slist_remove (self->calls, call); +} + +static AuthCall * +auth_call_new (NMAuthChain *chain, const char *permission) +{ + AuthCall *call; + + call = g_malloc0 (sizeof (AuthCall)); + call->chain = chain; + call->permission = g_strdup (permission); + chain->calls = g_slist_append (chain->calls, call); + return call; +} + +static void +auth_call_free (AuthCall *call) +{ + g_free (call->permission); + g_clear_object (&call->cancellable); + g_free (call); +} + +/* This can get used from scheduled idles, hence the boolean return */ +static gboolean +auth_call_complete (AuthCall *call) +{ + nm_auth_chain_remove_call (call->chain, call); + nm_auth_chain_check_done (call->chain); + auth_call_free (call); + return FALSE; +} + +static void +auth_call_cancel (gpointer user_data) +{ + AuthCall *call = user_data; + + if (call->cancellable) { + /* we don't free call immediately. Instead we cancel the async operation + * and set cancellable to NULL. pk_call_cb() will check for this and + * do the final cleanup. */ + g_cancellable_cancel (call->cancellable); + g_clear_object (&call->cancellable); + } else { + g_source_remove (call->call_idle_id); + auth_call_free (call); + } +} + +#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; + + pk_result = polkit_authority_check_authorization_finish ((PolkitAuthority *) object, result, &error); + + /* If the call is already canceled do nothing */ + if (!call->cancellable) { + 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); + } else { + guint call_result = NM_AUTH_CALL_RESULT_UNKNOWN; + + if (polkit_authorization_result_get_is_authorized (pk_result)) { + /* Caller has the permission */ + call_result = NM_AUTH_CALL_RESULT_YES; + } else if (polkit_authorization_result_get_is_challenge (pk_result)) { + /* 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 +nm_auth_chain_add_call (NMAuthChain *self, + const char *permission, + gboolean allow_interaction) +{ + AuthCall *call; + + g_return_val_if_fail (self != NULL, FALSE); + +#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; +} + +void +nm_auth_chain_unref (NMAuthChain *self) +{ + g_return_if_fail (self != NULL); + + self->refcount--; + if (self->refcount > 0) + return; + + 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); + + g_clear_error (&self->error); + g_hash_table_destroy (self->data); + + memset (self, 0, sizeof (NMAuthChain)); + g_free (self); +} + +/************ utils **************/ + +gboolean +nm_auth_uid_in_acl (NMConnection *connection, + NMSessionMonitor *smon, + gulong uid, + char **out_error_desc) +{ + NMSettingConnection *s_con; + const char *user = NULL; + GError *local = NULL; + + g_return_val_if_fail (connection != NULL, FALSE); + g_return_val_if_fail (smon != NULL, FALSE); + + /* Root gets a free pass */ + if (0 == uid) + return TRUE; + + /* Reject the request if the request comes from no session at all */ + if (!nm_session_monitor_uid_has_session (smon, uid, &user, &local)) { + if (out_error_desc) { + *out_error_desc = g_strdup_printf ("No session found for uid %lu (%s)", + uid, + local && local->message ? local->message : "unknown"); + } + g_clear_error (&local); + return FALSE; + } + + if (!user) { + if (out_error_desc) + *out_error_desc = g_strdup_printf ("Could not determine username for uid %lu", uid); + return FALSE; + } + + s_con = nm_connection_get_setting_connection (connection); + if (!s_con) { + /* This can only happen when called from AddAndActivate, so we know + * the user will be authorized when the connection is completed. + */ + return TRUE; + } + + /* Match the username returned by the session check to a user in the ACL */ + if (!nm_setting_connection_permissions_user_allowed (s_con, user)) { + if (out_error_desc) + *out_error_desc = g_strdup_printf ("uid %lu has no permission to perform this operation", uid); + return FALSE; + } + + 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; + } + } +} + diff --git a/src/nm-auth-utils.h b/src/nm-auth-utils.h new file mode 100644 index 0000000000..25f3cd591e --- /dev/null +++ b/src/nm-auth-utils.h @@ -0,0 +1,106 @@ +/* -*- 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) 2010 Red Hat, Inc. + */ + +#ifndef __NETWORKMANAGER_MANAGER_AUTH_H__ +#define __NETWORKMANAGER_MANAGER_AUTH_H__ + +#include +#include + +#include +#include "nm-types.h" + +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network" +#define NM_AUTH_PERMISSION_SLEEP_WAKE "org.freedesktop.NetworkManager.sleep-wake" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI "org.freedesktop.NetworkManager.enable-disable-wifi" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN "org.freedesktop.NetworkManager.enable-disable-wwan" +#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX "org.freedesktop.NetworkManager.enable-disable-wimax" +#define NM_AUTH_PERMISSION_NETWORK_CONTROL "org.freedesktop.NetworkManager.network-control" +#define NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED "org.freedesktop.NetworkManager.wifi.share.protected" +#define NM_AUTH_PERMISSION_WIFI_SHARE_OPEN "org.freedesktop.NetworkManager.wifi.share.open" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM "org.freedesktop.NetworkManager.settings.modify.system" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN "org.freedesktop.NetworkManager.settings.modify.own" +#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME "org.freedesktop.NetworkManager.settings.modify.hostname" + + +typedef struct NMAuthChain NMAuthChain; + +typedef enum { + NM_AUTH_CALL_RESULT_UNKNOWN, + NM_AUTH_CALL_RESULT_YES, + NM_AUTH_CALL_RESULT_AUTH, + NM_AUTH_CALL_RESULT_NO, +} NMAuthCallResult; + +typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain, + GError *error, + 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); + +NMAuthChain *nm_auth_chain_new_subject (NMAuthSubject *subject, + DBusGMethodInvocation *context, + NMAuthChainResultFunc done_func, + gpointer user_data); + +gpointer nm_auth_chain_get_data (NMAuthChain *chain, const char *tag); + +gpointer nm_auth_chain_steal_data (NMAuthChain *chain, const char *tag); + +void nm_auth_chain_set_data (NMAuthChain *chain, + const char *tag, + gpointer data, + GDestroyNotify data_destroy); + +void nm_auth_chain_set_data_ulong (NMAuthChain *chain, + const char *tag, + gulong data); + +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_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); + +#endif /* __NETWORKMANAGER_MANAGER_AUTH_H__ */ + diff --git a/src/nm-manager-auth.c b/src/nm-manager-auth.c deleted file mode 100644 index 80a0b87fba..0000000000 --- a/src/nm-manager-auth.c +++ /dev/null @@ -1,656 +0,0 @@ -/* -*- 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) 2010 Red Hat, Inc. - */ - -#include -#include -#include - -#if WITH_POLKIT -#include -#endif - -#include "nm-setting-connection.h" -#include "nm-manager-auth.h" -#include "nm-logging.h" -#include "nm-dbus-manager.h" -#include "nm-auth-subject.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; - - guint idle_id; - - NMAuthChainResultFunc done_func; - gpointer user_data; -}; - -typedef struct { - NMAuthChain *chain; - GCancellable *cancellable; - char *permission; - guint call_idle_id; -} AuthCall; - -typedef struct { - gpointer data; - GDestroyNotify destroy; -} ChainData; - -static void -free_data (gpointer data) -{ - ChainData *tmp = data; - - if (tmp->destroy) - tmp->destroy (tmp->data); - memset (tmp, 0, sizeof (ChainData)); - g_free (tmp); -} - -static gboolean -auth_chain_finish (gpointer user_data) -{ - NMAuthChain *self = user_data; - - self->idle_id = 0; - - /* Ensure we say alive across the callback */ - self->refcount++; - self->done_func (self, self->error, self->context, self->user_data); - nm_auth_chain_unref (self); - 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, - NMAuthChainResultFunc done_func, - gpointer user_data) -{ - NMAuthSubject *subject; - NMAuthChain *chain; - - g_return_val_if_fail (context != NULL, NULL); - - subject = nm_auth_subject_new_from_context (context); - if (!subject) - return NULL; - - chain = nm_auth_chain_new_subject (subject, - context, - done_func, - user_data); - g_object_unref (subject); - return chain; -} - -/* Requires an NMAuthSubject */ -NMAuthChain * -nm_auth_chain_new_subject (NMAuthSubject *subject, - DBusGMethodInvocation *context, - NMAuthChainResultFunc done_func, - gpointer user_data) -{ - NMAuthChain *chain; - - g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL); - chain = _auth_chain_new (subject, NULL, G_MAXULONG, context, done_func, user_data); - - /* Chains creation from a valid NMAuthSubject cannot fail since the - * subject already has all the necessary auth info. - */ - g_assert (chain); - return chain; -} - -gpointer -nm_auth_chain_get_data (NMAuthChain *self, const char *tag) -{ - ChainData *tmp; - - g_return_val_if_fail (self != NULL, NULL); - g_return_val_if_fail (tag != NULL, NULL); - - tmp = g_hash_table_lookup (self->data, tag); - return tmp ? tmp->data : NULL; -} - -/** - * nm_auth_chain_steal_data: - * @self: A #NMAuthChain. - * @tag: A "tag" uniquely identifying the data to steal. - * - * Removes the datum assocated with @tag from the chain's data associations, - * without invoking the association's destroy handler. The caller assumes - * ownership over the returned value. - * - * Returns: the datum originally associated with @tag - */ -gpointer -nm_auth_chain_steal_data (NMAuthChain *self, const char *tag) -{ - ChainData *tmp; - gpointer value = NULL; - - g_return_val_if_fail (self != NULL, NULL); - g_return_val_if_fail (tag != NULL, NULL); - - tmp = g_hash_table_lookup (self->data, tag); - if (tmp) { - g_hash_table_steal (self->data, tag); - value = tmp->data; - /* Make sure the destroy handler isn't called when freeing */ - tmp->destroy = NULL; - free_data (tmp); - } - return value; -} - -void -nm_auth_chain_set_data (NMAuthChain *self, - const char *tag, - gpointer data, - GDestroyNotify data_destroy) -{ - ChainData *tmp; - - g_return_if_fail (self != NULL); - g_return_if_fail (tag != NULL); - - if (data == NULL) - g_hash_table_remove (self->data, tag); - else { - tmp = g_malloc0 (sizeof (ChainData)); - tmp->data = data; - tmp->destroy = data_destroy; - - g_hash_table_insert (self->data, g_strdup (tag), tmp); - } -} - -gulong -nm_auth_chain_get_data_ulong (NMAuthChain *self, const char *tag) -{ - gulong *ptr; - - g_return_val_if_fail (self != NULL, 0); - g_return_val_if_fail (tag != NULL, 0); - - ptr = nm_auth_chain_get_data (self, tag); - return *ptr; -} - - -void -nm_auth_chain_set_data_ulong (NMAuthChain *self, - const char *tag, - gulong data) -{ - gulong *ptr; - - g_return_if_fail (self != NULL); - g_return_if_fail (tag != NULL); - - ptr = g_malloc (sizeof (*ptr)); - *ptr = data; - nm_auth_chain_set_data (self, tag, ptr, g_free); -} - -NMAuthCallResult -nm_auth_chain_get_result (NMAuthChain *self, const char *permission) -{ - g_return_val_if_fail (self != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); - g_return_val_if_fail (permission != NULL, NM_AUTH_CALL_RESULT_UNKNOWN); - - return GPOINTER_TO_UINT (nm_auth_chain_get_data (self, permission)); -} - -static void -nm_auth_chain_check_done (NMAuthChain *self) -{ - g_return_if_fail (self != NULL); - - if (g_slist_length (self->calls) == 0) { - g_assert (self->idle_id == 0); - self->idle_id = g_idle_add (auth_chain_finish, self); - } -} - -static void -nm_auth_chain_remove_call (NMAuthChain *self, AuthCall *call) -{ - g_return_if_fail (self != NULL); - g_return_if_fail (call != NULL); - - self->calls = g_slist_remove (self->calls, call); -} - -static AuthCall * -auth_call_new (NMAuthChain *chain, const char *permission) -{ - AuthCall *call; - - call = g_malloc0 (sizeof (AuthCall)); - call->chain = chain; - call->permission = g_strdup (permission); - chain->calls = g_slist_append (chain->calls, call); - return call; -} - -static void -auth_call_free (AuthCall *call) -{ - g_free (call->permission); - g_clear_object (&call->cancellable); - g_free (call); -} - -/* This can get used from scheduled idles, hence the boolean return */ -static gboolean -auth_call_complete (AuthCall *call) -{ - nm_auth_chain_remove_call (call->chain, call); - nm_auth_chain_check_done (call->chain); - auth_call_free (call); - return FALSE; -} - -static void -auth_call_cancel (gpointer user_data) -{ - AuthCall *call = user_data; - - if (call->cancellable) { - /* we don't free call immediately. Instead we cancel the async operation - * and set cancellable to NULL. pk_call_cb() will check for this and - * do the final cleanup. */ - g_cancellable_cancel (call->cancellable); - g_clear_object (&call->cancellable); - } else { - g_source_remove (call->call_idle_id); - auth_call_free (call); - } -} - -#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; - - pk_result = polkit_authority_check_authorization_finish ((PolkitAuthority *) object, result, &error); - - /* If the call is already canceled do nothing */ - if (!call->cancellable) { - 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); - } else { - guint call_result = NM_AUTH_CALL_RESULT_UNKNOWN; - - if (polkit_authorization_result_get_is_authorized (pk_result)) { - /* Caller has the permission */ - call_result = NM_AUTH_CALL_RESULT_YES; - } else if (polkit_authorization_result_get_is_challenge (pk_result)) { - /* 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 -nm_auth_chain_add_call (NMAuthChain *self, - const char *permission, - gboolean allow_interaction) -{ - AuthCall *call; - - g_return_val_if_fail (self != NULL, FALSE); - -#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; -} - -void -nm_auth_chain_unref (NMAuthChain *self) -{ - g_return_if_fail (self != NULL); - - self->refcount--; - if (self->refcount > 0) - return; - - 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); - - g_clear_error (&self->error); - g_hash_table_destroy (self->data); - - memset (self, 0, sizeof (NMAuthChain)); - g_free (self); -} - -/************ utils **************/ - -gboolean -nm_auth_uid_in_acl (NMConnection *connection, - NMSessionMonitor *smon, - gulong uid, - char **out_error_desc) -{ - NMSettingConnection *s_con; - const char *user = NULL; - GError *local = NULL; - - g_return_val_if_fail (connection != NULL, FALSE); - g_return_val_if_fail (smon != NULL, FALSE); - - /* Root gets a free pass */ - if (0 == uid) - return TRUE; - - /* Reject the request if the request comes from no session at all */ - if (!nm_session_monitor_uid_has_session (smon, uid, &user, &local)) { - if (out_error_desc) { - *out_error_desc = g_strdup_printf ("No session found for uid %lu (%s)", - uid, - local && local->message ? local->message : "unknown"); - } - g_clear_error (&local); - return FALSE; - } - - if (!user) { - if (out_error_desc) - *out_error_desc = g_strdup_printf ("Could not determine username for uid %lu", uid); - return FALSE; - } - - s_con = nm_connection_get_setting_connection (connection); - if (!s_con) { - /* This can only happen when called from AddAndActivate, so we know - * the user will be authorized when the connection is completed. - */ - return TRUE; - } - - /* Match the username returned by the session check to a user in the ACL */ - if (!nm_setting_connection_permissions_user_allowed (s_con, user)) { - if (out_error_desc) - *out_error_desc = g_strdup_printf ("uid %lu has no permission to perform this operation", uid); - return FALSE; - } - - 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; - } - } -} - diff --git a/src/nm-manager-auth.h b/src/nm-manager-auth.h deleted file mode 100644 index 25f3cd591e..0000000000 --- a/src/nm-manager-auth.h +++ /dev/null @@ -1,106 +0,0 @@ -/* -*- 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) 2010 Red Hat, Inc. - */ - -#ifndef __NETWORKMANAGER_MANAGER_AUTH_H__ -#define __NETWORKMANAGER_MANAGER_AUTH_H__ - -#include -#include - -#include -#include "nm-types.h" - -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network" -#define NM_AUTH_PERMISSION_SLEEP_WAKE "org.freedesktop.NetworkManager.sleep-wake" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI "org.freedesktop.NetworkManager.enable-disable-wifi" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN "org.freedesktop.NetworkManager.enable-disable-wwan" -#define NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX "org.freedesktop.NetworkManager.enable-disable-wimax" -#define NM_AUTH_PERMISSION_NETWORK_CONTROL "org.freedesktop.NetworkManager.network-control" -#define NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED "org.freedesktop.NetworkManager.wifi.share.protected" -#define NM_AUTH_PERMISSION_WIFI_SHARE_OPEN "org.freedesktop.NetworkManager.wifi.share.open" -#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM "org.freedesktop.NetworkManager.settings.modify.system" -#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN "org.freedesktop.NetworkManager.settings.modify.own" -#define NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME "org.freedesktop.NetworkManager.settings.modify.hostname" - - -typedef struct NMAuthChain NMAuthChain; - -typedef enum { - NM_AUTH_CALL_RESULT_UNKNOWN, - NM_AUTH_CALL_RESULT_YES, - NM_AUTH_CALL_RESULT_AUTH, - NM_AUTH_CALL_RESULT_NO, -} NMAuthCallResult; - -typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain, - GError *error, - 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); - -NMAuthChain *nm_auth_chain_new_subject (NMAuthSubject *subject, - DBusGMethodInvocation *context, - NMAuthChainResultFunc done_func, - gpointer user_data); - -gpointer nm_auth_chain_get_data (NMAuthChain *chain, const char *tag); - -gpointer nm_auth_chain_steal_data (NMAuthChain *chain, const char *tag); - -void nm_auth_chain_set_data (NMAuthChain *chain, - const char *tag, - gpointer data, - GDestroyNotify data_destroy); - -void nm_auth_chain_set_data_ulong (NMAuthChain *chain, - const char *tag, - gulong data); - -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_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); - -#endif /* __NETWORKMANAGER_MANAGER_AUTH_H__ */ - diff --git a/src/nm-manager.c b/src/nm-manager.c index eb20ada399..8f5d41f813 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -49,7 +49,7 @@ #include "nm-dhcp-manager.h" #include "nm-settings.h" #include "nm-settings-connection.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "NetworkManagerUtils.h" #include "nm-utils.h" #include "nm-device-factory.h" diff --git a/src/nm-policy.c b/src/nm-policy.c index a0cf71e5a9..f6ef476bf9 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -38,7 +38,7 @@ #include "nm-platform.h" #include "nm-dns-manager.h" #include "nm-vpn-manager.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "nm-firewall-manager.h" #include "nm-dispatcher.h" #include "nm-utils.h" diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 333cbb261e..26692c339f 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -30,9 +30,9 @@ #include "nm-logging.h" #include "nm-agent-manager.h" #include "nm-secret-agent.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "nm-dbus-glib-types.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "nm-setting-vpn.h" #include "nm-setting-connection.h" #include "nm-enum-types.h" diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 6b0d38c738..9cf90a5bc9 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -36,7 +36,7 @@ #include "nm-settings-error.h" #include "nm-dbus-glib-types.h" #include "nm-logging.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "nm-agent-manager.h" #include "NetworkManagerUtils.h" diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index a4339ed492..7876a69bf6 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -62,7 +62,7 @@ #include "nm-system-config-interface.h" #include "nm-logging.h" #include "nm-dbus-manager.h" -#include "nm-manager-auth.h" +#include "nm-auth-utils.h" #include "nm-auth-subject.h" #include "nm-session-monitor.h" #include "plugins/keyfile/plugin.h" -- cgit v1.2.1 From 63a8c6a184a58176b656d9e22f99a280682e0e5f Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 17 Aug 2014 16:18:45 +0200 Subject: build: generate man/NetworkManager.conf.xml by autoconf Signed-off-by: Thomas Haller --- .gitignore | 1 + configure.ac | 1 + man/NetworkManager.conf.xml | 511 ----------------------------------------- man/NetworkManager.conf.xml.in | 511 +++++++++++++++++++++++++++++++++++++++++ 4 files changed, 513 insertions(+), 511 deletions(-) delete mode 100644 man/NetworkManager.conf.xml create mode 100644 man/NetworkManager.conf.xml.in diff --git a/.gitignore b/.gitignore index b58f499316..86209c29bc 100644 --- a/.gitignore +++ b/.gitignore @@ -205,6 +205,7 @@ valgrind-*.log /m4/xsize.m4 /man/*.[185] +/man/NetworkManager.conf.xml /man/nm-settings.xml /man/nm-settings-ifcfg-rh.xml /man/nm-settings-keyfile.xml diff --git a/configure.ac b/configure.ac index e24ce732f9..1a1cc28412 100644 --- a/configure.ac +++ b/configure.ac @@ -918,6 +918,7 @@ initscript/linexa/networkmanager introspection/Makefile introspection/all.xml man/Makefile +man/NetworkManager.conf.xml man/nm-system-settings.conf.5 man/nm-online.1 man/nmcli.1 diff --git a/man/NetworkManager.conf.xml b/man/NetworkManager.conf.xml deleted file mode 100644 index c017822e3f..0000000000 --- a/man/NetworkManager.conf.xml +++ /dev/null @@ -1,511 +0,0 @@ - - - - - - - - NetworkManager.conf - NetworkManager developers - - - - NetworkManager.conf - 5 - NetworkManager - Configuration - 0.9.10 - - - - NetworkManager.conf - NetworkManager configuration file - - - - /etc/NetworkManager/NetworkManager.conf, - /etc/NetworkManager/conf.d/name.conf - - - - - Description - This is a configuration file for NetworkManager. It is used - to set up various aspects of NetworkManager's behavior. The - location of the file may be changed through use of the - argument for NetworkManager. - - If a default NetworkManager.conf is - provided by your distribution's packages, you should not modify - it, since your changes may get overwritten by package - updates. Instead, you can add additional .conf - files to the conf.d directory. These will be read in order, - with later files overriding earlier ones. - - - - - - File Format - - The configuration file format is so-called key file (sort of - ini-style format). It consists of sections (groups) of - key-value pairs. Lines beginning with a '#' and blank lines are - considered comments. Sections are started by a header line - containing the section enclosed in '[' and ']', and ended - implicitly by the start of the next section or the end of the - file. Each key-value pair must be contained in a section. - - - For keys that take a list of devices as their value, you can - specify devices by their MAC addresses or interface names, or - "*" to specify all devices. - - - Minimal system settings configuration file looks like this: - - [main] - plugins=keyfile - - - - As an extension to the normal keyfile format, you can also - append a value to a previously-set list-valued key by doing: - - plugins+=another-plugin - - - - - - <literal>main</literal> section - - - plugins - - - Lists system settings plugin names separated by ','. These - plugins are used to read and write system-wide - connections. When multiple plugins are specified, the - connections are read from all listed plugins. When writing - connections, the plugins will be asked to save the - connection in the order listed here; if the first plugin - cannot write out that connection type (or can't write out - any connections) the next plugin is tried, etc. If none of - the plugins can save the connection, an error is returned - to the user. - - - If NetworkManager defines a distro-specific - network-configuration plugin for your system, then that - will normally be listed here. (See below for the available - plugins.) Note that the keyfile plugin - is always appended to the end of this list (if it doesn't - already appear earlier in the list), so if there is no - distro-specific plugin for your system then you can leave - this key unset and NetworkManager will fall back to using - keyfile. - - - - - monitor-connection-files - Whether the configured settings plugin(s) - should set up file monitors and immediately pick up changes - made to connection files while NetworkManager is running. This - is disabled by default; NetworkManager will only read - the connection files at startup, and when explicitly requested - via the ReloadConnections D-Bus call. If this key is set to - 'true', then NetworkManager will reload - connection files any time they changed. - - - dhcp - This key sets up what DHCP client - NetworkManager will use. Presently - dhclient and dhcpcd - are supported. The client configured here should be - available on your system too. If this key is missing, - available DHCP clients are looked for in this order: - dhclient, dhcpcd. - - - no-auto-default - Comma-separated list of devices for which - NetworkManager shouldn't create default wired connection - (Auto eth0). By default, NetworkManager creates a temporary - wired connection for any Ethernet device that is managed and - doesn't have a connection configured. List a device in this - option to inhibit creating the default connection for the - device. May have the special value * to - apply to all devices. - When the default wired connection is deleted or saved - to a new persistent connection by a plugin, the device is - added to a list in the file - /var/run/NetworkManager/no-auto-default.state - to prevent creating the default connection for that device - again. - - - no-auto-default=00:22:68:5c:5d:c4,00:1e:65:ff:aa:ee - no-auto-default=eth0,eth1 - no-auto-default=* - - - - - - - ignore-carrier - - - Comma-separated list of devices for which NetworkManager - will (partially) ignore the carrier state. Normally, for - device types that support carrier-detect, such as Ethernet - and InfiniBand, NetworkManager will only allow a - connection to be activated on the device if carrier is - present (ie, a cable is plugged in), and it will - deactivate the device if carrier drops for more than a few - seconds. - - - Listing a device here will allow activating connections on - that device even when it does not have carrier, provided - that the connection uses only statically-configured IP - addresses. Additionally, it will allow any active - connection (whether static or dynamic) to remain active on - the device when carrier is lost. - - - May have the special value * to apply - to all devices. - - - Note that the "carrier" property of NMDevices and device D-Bus - interfaces will still reflect the actual device state; it's just - that NetworkManager will not make use of that information. - - - - - - dns - Set the DNS (resolv.conf) processing mode. - default: The default if the key is - not specified. NetworkManager will update - resolv.conf to reflect the nameservers - provided by currently active connections. - dnsmasq: NetworkManager will run - dnsmasq as a local caching nameserver, using a "split DNS" - configuration if you are connected to a VPN, and then update - resolv.conf to point to the local - nameserver. - unbound: NetworkManager will talk - to unbound and dnssec-triggerd, providing a "split DNS" - configuration with DNSSEC support. The /etc/resolv.conf - will be managed by dnssec-trigger daemon. - none: NetworkManager will not - modify resolv.conf. - - - - - debug - Comma separated list of options to aid - debugging. This value will be combined with the environment - variable NM_DEBUG. Currently the following - values are supported: - - RLIMIT_CORE: set ulimit -c unlimited - to write out core dumps. - - - - - - - - - <literal>keyfile</literal> section - This section contains keyfile-plugin-specific options, and - is normally only used when you are not using any other - distro-specific plugin. - - - - - hostname - Set a persistent hostname. - - - unmanaged-devices - Set devices that should be ignored by - NetworkManager when using the keyfile - plugin. Devices are specified in the following - format: - mac:<hwaddr> or - interface-name:<ifname>. Here - hwaddr is the MAC address of the device - to be ignored, in hex-digits-and-colons notation. - ifname is the interface name of the - ignored device. - Multiple entries are separated with semicolons. No - spaces are allowed in the value. - - Example: - -unmanaged-devices=interface-name:em4 -unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth2 - - - - - - - - - - <literal>ifupdown</literal> section - This section contains ifupdown-specific options and thus only - has effect when using the ifupdown plugin. - - - - - managed - If set to true, then - interfaces listed in - /etc/network/interfaces are managed by - NetworkManager. If set to false, then - any interface listed in - /etc/network/interfaces will be ignored - by NetworkManager. Remember that NetworkManager controls the - default route, so because the interface is ignored, - NetworkManager may assign the default route to some other - interface. - - The default value is false. - - - - - - - - - <literal>logging</literal> section - This section controls NetworkManager's logging. Any - settings here are overridden by the - and command-line options. - - - - - level - The default logging verbosity level. - One of ERR, - WARN, INFO, - DEBUG. The ERR level logs only critical - errors. WARN logs warnings that may reflect operation. - INFO logs various informational messages that are useful for - tracking state and operations. DEBUG enables verbose - logging for debugging purposes. Subsequent levels also log - all messages from earlier levels; thus setting the log level - to INFO also logs error and warning messages. - - - domains - The following log domains are available: - PLATFORM, RFKILL, ETHER, WIFI, BT, MB, DHCP4, DHCP6, PPP, - WIFI_SCAN, IP4, IP6, AUTOIP4, DNS, VPN, SHARING, SUPPLICANT, - AGENTS, SETTINGS, SUSPEND, CORE, DEVICE, OLPC, WIMAX, - INFINIBAND, FIREWALL, ADSL, BOND, VLAN, BRIDGE, DBUS_PROPS, - TEAM, CONCHECK, DCB, DISPATCH. - In addition, these special domains can be used: NONE, - ALL, DEFAULT, DHCP, IP. - You can specify per-domain log level overrides by - adding a colon and a log level to any domain. E.g., - "WIFI:DEBUG". - - - Domain descriptions: - - PLATFORM : OS (platform) operations - RFKILL : RFKill subsystem operations - ETHER : Ethernet device operations - WIFI : Wi-Fi device operations - BT : Bluetooth operations - MB : Mobile broadband operations - DHCP4 : DHCP for IPv4 - DHCP6 : DHCP for IPv6 - PPP : Point-to-point protocol operations - WIFI_SCAN : Wi-Fi scanning operations - IP4 : IPv4-related operations - IP6 : IPv6-related operations - AUTOIP4 : AutoIP (avahi) operations - DNS : Domain Name System related operations - VPN : Virtual Private Network connections and operations - SHARING : Connection sharing - SUPPLICANT : WPA supplicant related operations - AGENTS : Secret agents operations and communication - SETTINGS : Settings/config service operations - SUSPEND : Suspend/resume - CORE : Core daemon and policy operations - DEVICE : Activation and general interface operations - OLPC : OLPC Mesh device operations - WIMAX : WiMAX device operations - INFINIBAND : InfiniBand device operations - FIREWALL : FirewallD related operations - ADSL : ADSL device operations - BOND : Bonding operations - VLAN : VLAN operations - BRIDGE : Bridging operations - DBUS_PROPS : D-Bus property changes - TEAM : Teaming operations - CONCHECK : Connectivity check - DCB : Data Center Bridging (DCB) operations - DISPATCH : Dispatcher scripts - - NONE : when given by itself logging is disabled - ALL : all log domains - DEFAULT : default log domains - DHCP : shortcut for "DHCP4,DHCP6" - IP : shortcut for "IP4,IP6" - - HW : deprecated alias for "PLATFORM" - - - - - - - - - <literal>connectivity</literal> section - This section controls NetworkManager's optional connectivity - checking functionality. This allows NetworkManager to detect - whether or not the system can actually access the internet or - whether it is behind a captive portal. - - - - - uri - The URI of a web page to periodically - request when connectivity is being checked. This page - should return the header "X-NetworkManager-Status" with a - value of "online". Alternatively, it's body content should - be set to "NetworkManager is online". The body content - check can be controlled by the response - option. If this option is blank or missing, connectivity - checking is disabled. - - - - interval - Specified in seconds; controls how often - connectivity is checked when a network connection exists. If - set to 0 connectivity checking is disabled. If missing, the - default is 300 seconds. - - - response - If set controls what body content - NetworkManager checks for when requesting the URI for - connectivity checking. If missing, defaults to - "NetworkManager is online" - - - - - - - Plugins - - - - keyfile - - - The keyfile plugin is the generic - plugin that supports all the connection types and - capabilities that NetworkManager has. It writes files out - in an .ini-style format in - /etc/NetworkManager/system-connections. - - - The stored connection file may contain passwords and - private keys, so it will be made readable only to root, - and the plugin will ignore files that are readable or - writeable by any user or group other than root. - - - This plugin is always active, and will automatically be - used to store any connections that aren't supported by any - other active plugin. - - - - - ifcfg-rh - - - This plugin is used on the Fedora and Red Hat Enterprise - Linux distributions to read and write configuration from - the standard - /etc/sysconfig/network-scripts/ifcfg-* - files. It currently supports reading Ethernet, Wi-Fi, - InfiniBand, VLAN, Bond, Bridge, and Team connections. - - - - - - ifcfg-suse - - - This plugin is only provided for simple backward - compatibility with SUSE and OpenSUSE configuration. Most - setups should be using the keyfile - plugin instead. The ifcfg-suse plugin - supports reading Ethernet and Wi-Fi connections, but does - not support saving any connection types. - - - - - - ifupdown - - - This plugin is used on the Debian and Ubuntu - distributions, and reads Ethernet and Wi-Fi connections - from /etc/network/interfaces. - - - This plugin is read-only; any connections (of any type) - added from within NetworkManager when you are using this - plugin will be saved using the keyfile - plugin instead. - - - - - - - - See Also - - NetworkManager8, - nmcli1, - nmcli-examples5, - nm-online1, - nm-settings5, - nm-applet1, - nm-connection-editor1 - - - diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in new file mode 100644 index 0000000000..c017822e3f --- /dev/null +++ b/man/NetworkManager.conf.xml.in @@ -0,0 +1,511 @@ + + + + + + + + NetworkManager.conf + NetworkManager developers + + + + NetworkManager.conf + 5 + NetworkManager + Configuration + 0.9.10 + + + + NetworkManager.conf + NetworkManager configuration file + + + + /etc/NetworkManager/NetworkManager.conf, + /etc/NetworkManager/conf.d/name.conf + + + + + Description + This is a configuration file for NetworkManager. It is used + to set up various aspects of NetworkManager's behavior. The + location of the file may be changed through use of the + argument for NetworkManager. + + If a default NetworkManager.conf is + provided by your distribution's packages, you should not modify + it, since your changes may get overwritten by package + updates. Instead, you can add additional .conf + files to the conf.d directory. These will be read in order, + with later files overriding earlier ones. + + + + + + File Format + + The configuration file format is so-called key file (sort of + ini-style format). It consists of sections (groups) of + key-value pairs. Lines beginning with a '#' and blank lines are + considered comments. Sections are started by a header line + containing the section enclosed in '[' and ']', and ended + implicitly by the start of the next section or the end of the + file. Each key-value pair must be contained in a section. + + + For keys that take a list of devices as their value, you can + specify devices by their MAC addresses or interface names, or + "*" to specify all devices. + + + Minimal system settings configuration file looks like this: + + [main] + plugins=keyfile + + + + As an extension to the normal keyfile format, you can also + append a value to a previously-set list-valued key by doing: + + plugins+=another-plugin + + + + + + <literal>main</literal> section + + + plugins + + + Lists system settings plugin names separated by ','. These + plugins are used to read and write system-wide + connections. When multiple plugins are specified, the + connections are read from all listed plugins. When writing + connections, the plugins will be asked to save the + connection in the order listed here; if the first plugin + cannot write out that connection type (or can't write out + any connections) the next plugin is tried, etc. If none of + the plugins can save the connection, an error is returned + to the user. + + + If NetworkManager defines a distro-specific + network-configuration plugin for your system, then that + will normally be listed here. (See below for the available + plugins.) Note that the keyfile plugin + is always appended to the end of this list (if it doesn't + already appear earlier in the list), so if there is no + distro-specific plugin for your system then you can leave + this key unset and NetworkManager will fall back to using + keyfile. + + + + + monitor-connection-files + Whether the configured settings plugin(s) + should set up file monitors and immediately pick up changes + made to connection files while NetworkManager is running. This + is disabled by default; NetworkManager will only read + the connection files at startup, and when explicitly requested + via the ReloadConnections D-Bus call. If this key is set to + 'true', then NetworkManager will reload + connection files any time they changed. + + + dhcp + This key sets up what DHCP client + NetworkManager will use. Presently + dhclient and dhcpcd + are supported. The client configured here should be + available on your system too. If this key is missing, + available DHCP clients are looked for in this order: + dhclient, dhcpcd. + + + no-auto-default + Comma-separated list of devices for which + NetworkManager shouldn't create default wired connection + (Auto eth0). By default, NetworkManager creates a temporary + wired connection for any Ethernet device that is managed and + doesn't have a connection configured. List a device in this + option to inhibit creating the default connection for the + device. May have the special value * to + apply to all devices. + When the default wired connection is deleted or saved + to a new persistent connection by a plugin, the device is + added to a list in the file + /var/run/NetworkManager/no-auto-default.state + to prevent creating the default connection for that device + again. + + + no-auto-default=00:22:68:5c:5d:c4,00:1e:65:ff:aa:ee + no-auto-default=eth0,eth1 + no-auto-default=* + + + + + + + ignore-carrier + + + Comma-separated list of devices for which NetworkManager + will (partially) ignore the carrier state. Normally, for + device types that support carrier-detect, such as Ethernet + and InfiniBand, NetworkManager will only allow a + connection to be activated on the device if carrier is + present (ie, a cable is plugged in), and it will + deactivate the device if carrier drops for more than a few + seconds. + + + Listing a device here will allow activating connections on + that device even when it does not have carrier, provided + that the connection uses only statically-configured IP + addresses. Additionally, it will allow any active + connection (whether static or dynamic) to remain active on + the device when carrier is lost. + + + May have the special value * to apply + to all devices. + + + Note that the "carrier" property of NMDevices and device D-Bus + interfaces will still reflect the actual device state; it's just + that NetworkManager will not make use of that information. + + + + + + dns + Set the DNS (resolv.conf) processing mode. + default: The default if the key is + not specified. NetworkManager will update + resolv.conf to reflect the nameservers + provided by currently active connections. + dnsmasq: NetworkManager will run + dnsmasq as a local caching nameserver, using a "split DNS" + configuration if you are connected to a VPN, and then update + resolv.conf to point to the local + nameserver. + unbound: NetworkManager will talk + to unbound and dnssec-triggerd, providing a "split DNS" + configuration with DNSSEC support. The /etc/resolv.conf + will be managed by dnssec-trigger daemon. + none: NetworkManager will not + modify resolv.conf. + + + + + debug + Comma separated list of options to aid + debugging. This value will be combined with the environment + variable NM_DEBUG. Currently the following + values are supported: + + RLIMIT_CORE: set ulimit -c unlimited + to write out core dumps. + + + + + + + + + <literal>keyfile</literal> section + This section contains keyfile-plugin-specific options, and + is normally only used when you are not using any other + distro-specific plugin. + + + + + hostname + Set a persistent hostname. + + + unmanaged-devices + Set devices that should be ignored by + NetworkManager when using the keyfile + plugin. Devices are specified in the following + format: + mac:<hwaddr> or + interface-name:<ifname>. Here + hwaddr is the MAC address of the device + to be ignored, in hex-digits-and-colons notation. + ifname is the interface name of the + ignored device. + Multiple entries are separated with semicolons. No + spaces are allowed in the value. + + Example: + +unmanaged-devices=interface-name:em4 +unmanaged-devices=mac:00:22:68:1c:59:b1;mac:00:1E:65:30:D1:C4;interface-name:eth2 + + + + + + + + + + <literal>ifupdown</literal> section + This section contains ifupdown-specific options and thus only + has effect when using the ifupdown plugin. + + + + + managed + If set to true, then + interfaces listed in + /etc/network/interfaces are managed by + NetworkManager. If set to false, then + any interface listed in + /etc/network/interfaces will be ignored + by NetworkManager. Remember that NetworkManager controls the + default route, so because the interface is ignored, + NetworkManager may assign the default route to some other + interface. + + The default value is false. + + + + + + + + + <literal>logging</literal> section + This section controls NetworkManager's logging. Any + settings here are overridden by the + and command-line options. + + + + + level + The default logging verbosity level. + One of ERR, + WARN, INFO, + DEBUG. The ERR level logs only critical + errors. WARN logs warnings that may reflect operation. + INFO logs various informational messages that are useful for + tracking state and operations. DEBUG enables verbose + logging for debugging purposes. Subsequent levels also log + all messages from earlier levels; thus setting the log level + to INFO also logs error and warning messages. + + + domains + The following log domains are available: + PLATFORM, RFKILL, ETHER, WIFI, BT, MB, DHCP4, DHCP6, PPP, + WIFI_SCAN, IP4, IP6, AUTOIP4, DNS, VPN, SHARING, SUPPLICANT, + AGENTS, SETTINGS, SUSPEND, CORE, DEVICE, OLPC, WIMAX, + INFINIBAND, FIREWALL, ADSL, BOND, VLAN, BRIDGE, DBUS_PROPS, + TEAM, CONCHECK, DCB, DISPATCH. + In addition, these special domains can be used: NONE, + ALL, DEFAULT, DHCP, IP. + You can specify per-domain log level overrides by + adding a colon and a log level to any domain. E.g., + "WIFI:DEBUG". + + + Domain descriptions: + + PLATFORM : OS (platform) operations + RFKILL : RFKill subsystem operations + ETHER : Ethernet device operations + WIFI : Wi-Fi device operations + BT : Bluetooth operations + MB : Mobile broadband operations + DHCP4 : DHCP for IPv4 + DHCP6 : DHCP for IPv6 + PPP : Point-to-point protocol operations + WIFI_SCAN : Wi-Fi scanning operations + IP4 : IPv4-related operations + IP6 : IPv6-related operations + AUTOIP4 : AutoIP (avahi) operations + DNS : Domain Name System related operations + VPN : Virtual Private Network connections and operations + SHARING : Connection sharing + SUPPLICANT : WPA supplicant related operations + AGENTS : Secret agents operations and communication + SETTINGS : Settings/config service operations + SUSPEND : Suspend/resume + CORE : Core daemon and policy operations + DEVICE : Activation and general interface operations + OLPC : OLPC Mesh device operations + WIMAX : WiMAX device operations + INFINIBAND : InfiniBand device operations + FIREWALL : FirewallD related operations + ADSL : ADSL device operations + BOND : Bonding operations + VLAN : VLAN operations + BRIDGE : Bridging operations + DBUS_PROPS : D-Bus property changes + TEAM : Teaming operations + CONCHECK : Connectivity check + DCB : Data Center Bridging (DCB) operations + DISPATCH : Dispatcher scripts + + NONE : when given by itself logging is disabled + ALL : all log domains + DEFAULT : default log domains + DHCP : shortcut for "DHCP4,DHCP6" + IP : shortcut for "IP4,IP6" + + HW : deprecated alias for "PLATFORM" + + + + + + + + + <literal>connectivity</literal> section + This section controls NetworkManager's optional connectivity + checking functionality. This allows NetworkManager to detect + whether or not the system can actually access the internet or + whether it is behind a captive portal. + + + + + uri + The URI of a web page to periodically + request when connectivity is being checked. This page + should return the header "X-NetworkManager-Status" with a + value of "online". Alternatively, it's body content should + be set to "NetworkManager is online". The body content + check can be controlled by the response + option. If this option is blank or missing, connectivity + checking is disabled. + + + + interval + Specified in seconds; controls how often + connectivity is checked when a network connection exists. If + set to 0 connectivity checking is disabled. If missing, the + default is 300 seconds. + + + response + If set controls what body content + NetworkManager checks for when requesting the URI for + connectivity checking. If missing, defaults to + "NetworkManager is online" + + + + + + + Plugins + + + + keyfile + + + The keyfile plugin is the generic + plugin that supports all the connection types and + capabilities that NetworkManager has. It writes files out + in an .ini-style format in + /etc/NetworkManager/system-connections. + + + The stored connection file may contain passwords and + private keys, so it will be made readable only to root, + and the plugin will ignore files that are readable or + writeable by any user or group other than root. + + + This plugin is always active, and will automatically be + used to store any connections that aren't supported by any + other active plugin. + + + + + ifcfg-rh + + + This plugin is used on the Fedora and Red Hat Enterprise + Linux distributions to read and write configuration from + the standard + /etc/sysconfig/network-scripts/ifcfg-* + files. It currently supports reading Ethernet, Wi-Fi, + InfiniBand, VLAN, Bond, Bridge, and Team connections. + + + + + + ifcfg-suse + + + This plugin is only provided for simple backward + compatibility with SUSE and OpenSUSE configuration. Most + setups should be using the keyfile + plugin instead. The ifcfg-suse plugin + supports reading Ethernet and Wi-Fi connections, but does + not support saving any connection types. + + + + + + ifupdown + + + This plugin is used on the Debian and Ubuntu + distributions, and reads Ethernet and Wi-Fi connections + from /etc/network/interfaces. + + + This plugin is read-only; any connections (of any type) + added from within NetworkManager when you are using this + plugin will be saved using the keyfile + plugin instead. + + + + + + + + See Also + + NetworkManager8, + nmcli1, + nmcli-examples5, + nm-online1, + nm-settings5, + nm-applet1, + nm-connection-editor1 + + + -- cgit v1.2.1 From eabe7d856c243673bbaba3295ce74d72e188596d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 14 Aug 2014 13:34:57 +0200 Subject: auth: rework polkit autorization to use DBUS interface directly This makes NetworkManager independent of 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 --- configure.ac | 34 +- contrib/fedora/rpm/NetworkManager.spec | 1 - man/NetworkManager.conf.xml.in | 8 + src/Makefile.am | 4 +- src/main.c | 3 + src/nm-active-connection.c | 2 +- src/nm-auth-manager.c | 643 +++++++++++++++++++++++++++++++++ src/nm-auth-manager.h | 82 +++++ src/nm-auth-subject.c | 468 +++++++++++++++++++----- src/nm-auth-subject.h | 45 ++- src/nm-auth-utils.c | 318 ++++------------ src/nm-auth-utils.h | 23 +- src/nm-config.c | 21 ++ src/nm-config.h | 1 + src/nm-manager.c | 61 ++-- src/settings/nm-agent-manager.c | 36 +- src/settings/nm-secret-agent.c | 17 +- src/settings/nm-settings-connection.c | 18 +- src/settings/nm-settings.c | 20 +- 19 files changed, 1326 insertions(+), 479 deletions(-) create mode 100644 src/nm-auth-manager.c create mode 100644 src/nm-auth-manager.h diff --git a/configure.ac b/configure.ac index 1a1cc28412..93fc135265 100644 --- a/configure.ac +++ b/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)" - 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 diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec index def31b3602..8d3bc63bfb 100644 --- a/contrib/fedora/rpm/NetworkManager.spec +++ b/contrib/fedora/rpm/NetworkManager.spec @@ -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} diff --git a/man/NetworkManager.conf.xml.in b/man/NetworkManager.conf.xml.in index c017822e3f..06aa403a8b 100644 --- a/man/NetworkManager.conf.xml.in +++ b/man/NetworkManager.conf.xml.in @@ -122,6 +122,14 @@ Copyright (C) 2010 - 2013 Red Hat, Inc. 'true', then NetworkManager will reload connection files any time they changed. + + auth-polkit + Whether the system uses PolicyKit for authorization. + If false, all requests will be allowed. If + true, non-root requests are authorized using PolicyKit. + The default value is @NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT@. + + dhcp This key sets up what DHCP client diff --git a/src/Makefile.am b/src/Makefile.am index c72c85fefc..95df89be74 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -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) \ diff --git a/src/main.c b/src/main.c index d41472d4ff..17769587a9 100644 --- a/src/main.c +++ b/src/main.c @@ -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); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 888bbd1797..3e532e5225 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -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 * diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c new file mode 100644 index 0000000000..092248fa5f --- /dev/null +++ b/src/nm-auth-manager.c @@ -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); + +} + diff --git a/src/nm-auth-manager.h b/src/nm-auth-manager.h new file mode 100644 index 0000000000..3f5ebc6589 --- /dev/null +++ b/src/nm-auth-manager.h @@ -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 + +#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 */ + diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c index e770af49ec..f982616677 100644 --- a/src/nm-auth-subject.c +++ b/src/nm-auth-subject.c @@ -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 -#include -#include -#include -#include +#include "nm-auth-subject.h" -#if WITH_POLKIT -#include -#endif +#include +#include +#include -#include "nm-auth-subject.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, + + PROP_LAST, +}; -#if WITH_POLKIT - PolkitSubject *pk_subject; -#endif +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) -{ - NMAuthSubject *subject; - NMAuthSubjectPrivate *priv; - NMDBusManager *dbus_mgr; - gboolean success = FALSE; - g_return_val_if_fail (context || (connection && message) || internal, NULL); - if (internal) - g_return_val_if_fail (context == NULL && connection == NULL && message == NULL, NULL); - subject = NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT, NULL)); - priv = NM_AUTH_SUBJECT_GET_PRIVATE (subject); +/**************************************************************/ + +/* copied from polkit source (src/polkit/polkitunixprocess.c) + * and adjusted. + */ +static guint64 +get_start_time_for_pid (pid_t pid) +{ + guint64 start_time; + gchar *filename; + gchar *contents; + size_t length; + gchar **tokens; + guint num_tokens; + gchar *p; + gchar *endp; + + start_time = 0; + contents = NULL; + + filename = g_strdup_printf ("/proc/%d/stat", pid); + + if (!g_file_get_contents (filename, &contents, &length, NULL)) + goto out; + + /* 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; +} + +/**************************************************************/ - dbus_mgr = nm_dbus_manager_get (); +#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); \ - if (internal) { - priv->uid = 0; - priv->pid = 0; - return subject; +#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_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; + 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); + } + 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, - DBusMessage *message) +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); -gulong -nm_auth_subject_get_pid (NMAuthSubject *subject) -{ - return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->pid; + 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; + } } -const char * -nm_auth_subject_get_dbus_sender (NMAuthSubject *subject) +static void +set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender; + 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; + } } -gboolean -nm_auth_subject_get_internal (NMAuthSubject *subject) +static void +_clear_private (NMAuthSubjectPrivate *priv) { - /* internal requests will have no dbus sender */ - return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender ? FALSE : TRUE; + 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); } -#if WITH_POLKIT -PolkitSubject * -nm_auth_subject_get_polkit_subject (NMAuthSubject *subject) +static void +nm_auth_subject_init (NMAuthSubject *self) { - return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->pk_subject; + _clear_private (NM_AUTH_SUBJECT_GET_PRIVATE (self)); } -#endif - -/******************************************************************/ static void -nm_auth_subject_init (NMAuthSubject *self) +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)); + } diff --git a/src/nm-auth-subject.h b/src/nm-auth-subject.h index 4834005e2e..4e1d83162f 100644 --- a/src/nm-auth-subject.h +++ b/src/nm-auth-subject.h @@ -27,10 +27,6 @@ #include #include -#if WITH_POLKIT -#include -#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_internal (void); -NMAuthSubject *nm_auth_subject_new_from_message (DBusConnection *connection, DBusMessage *message); +NMAuthSubject *nm_auth_subject_new_unix_process_from_context (DBusGMethodInvocation *context); -NMAuthSubject *nm_auth_subject_new_internal (void); +NMAuthSubject *nm_auth_subject_new_unix_process_from_message (DBusConnection *connection, DBusMessage *message); + + +NMAuthSubjectType nm_auth_subject_get_subject_type (NMAuthSubject *subject); + + +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_uid (NMAuthSubject *subject); -gulong nm_auth_subject_get_pid (NMAuthSubject *subject); +gulong nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject); -const char *nm_auth_subject_get_dbus_sender (NMAuthSubject *subject); -gboolean nm_auth_subject_get_internal (NMAuthSubject *subject); +const char *nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len); -#if WITH_POLKIT -PolkitSubject *nm_auth_subject_get_polkit_subject (NMAuthSubject *subject); -#endif +GVariant * nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self); #endif /* __NETWORKMANAGER_AUTH_SUBJECT_H__ */ diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c index b2d7cb3cbd..0a652507e9 100644 --- a/src/nm-auth-utils.c +++ b/src/nm-auth-utils.c @@ -22,28 +22,21 @@ #include #include -#if WITH_POLKIT -#include -#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); - -#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 + 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)); - /* 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; - } - } -} diff --git a/src/nm-auth-utils.h b/src/nm-auth-utils.h index 25f3cd591e..2ab026d012 100644 --- a/src/nm-auth-utils.h +++ b/src/nm-auth-utils.h @@ -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__ */ diff --git a/src/nm-config.c b/src/nm-config.c index 3978b56626..2580541a62 100644 --- a/src/nm-config.c +++ b/src/nm-config.c @@ -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, ','); diff --git a/src/nm-config.h b/src/nm-config.h index 8f4fa1f7af..27da4cbbc6 100644 --- a/src/nm-config.h +++ b/src/nm-config.h @@ -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); diff --git a/src/nm-manager.c b/src/nm-manager.c index 8f5d41f813..db46bf5be8 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -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) diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index 26692c339f..0de63ffb16 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -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); diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c index a1c6954ee2..3099f4518b 100644 --- a/src/settings/nm-secret-agent.c +++ b/src/settings/nm-secret-agent.c @@ -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); diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 9cf90a5bc9..1e0106d07b 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -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); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 7876a69bf6..65bc241e48 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -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); -- cgit v1.2.1 From 53e244bef637c3e4004961651d4ed23eda7393b5 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 19 Aug 2014 18:56:23 +0200 Subject: auth: support disabling POLKIT authentication entirely at compile time Let the user completly disable polkit authentication by building NM with configure option '--enable-polkit=disabled'. In that case, configuring 'main.auth-polkit=yes' will fail all authentication requests (except root-requests, which are always granted). This reduces the size of the NetworkManager binary by some 26KB (16KB stripped). Signed-off-by: Thomas Haller --- configure.ac | 24 +++++++++++++++++++----- src/nm-auth-manager.c | 17 +++++++++++++++++ src/nm-auth-manager.h | 3 +++ src/nm-auth-subject.c | 4 ++++ src/nm-auth-subject.h | 4 ++++ src/nm-auth-utils.c | 11 +++++++++++ 6 files changed, 58 insertions(+), 5 deletions(-) diff --git a/configure.ac b/configure.ac index 93fc135265..13bd82d203 100644 --- a/configure.ac +++ b/configure.ac @@ -457,9 +457,14 @@ else fi AM_CONDITIONAL(WITH_TEAMDCTL, test "${enable_teamdctl}" = "yes") -AC_ARG_ENABLE(polkit, AS_HELP_STRING([--enable-polkit], [set default value for auth-polkit configuration option]), +# we usually compile with polkit support. --enable-polkit=yes|no only sets the +# default configuration for main.auth-polkit. User can always enable/disable polkit +# autorization via config. Only when specifying --enable-polkit=disabled, we do +# not compile support. In this case, the user cannot enable polkit authorization via +# configuration. +AC_ARG_ENABLE(polkit, AS_HELP_STRING([--enable-polkit=yes|no|disabled], [set default value for auth-polkit configuration option. This value can be overwritten by NM configuration. 'disabled' compiles NM without any support]), [enable_polkit=${enableval}], [enable_polkit=yes]) -if (test "${enable_polkit}" != "no"); then +if (test "${enable_polkit}" != "no" -a "${enable_polkit}" != "disabled"); 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' @@ -467,6 +472,11 @@ else 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 +if (test "${enable_polkit}" != "disabled"); then + AC_DEFINE(WITH_POLKIT, 1, [whether to compile polkit support]) +else + AC_DEFINE(WITH_POLKIT, 0, [whether to compile polkit support]) +fi AC_SUBST(NM_CONFIG_DEFAULT_AUTH_POLKIT_TEXT) AC_ARG_ENABLE(modify-system, @@ -961,10 +971,14 @@ echo echo "Platform:" echo " session tracking: $with_session_tracking" echo " suspend/resume: $with_suspend_resume" -if test "${enable_modify_system}" = "yes"; then - echo " policykit: yes (permissive modify.system) (default=${enable_polkit})" +if test "${enable_polkit}" = "yes"; then + if test "${enable_modify_system}" = "yes"; then + echo " policykit: yes (permissive modify.system) (default=${enable_polkit})" + else + echo " policykit: yes (restrictive modify.system) (default=${enable_polkit})" + fi else - echo " policykit: yes (restrictive modify.system) (default=${enable_polkit})" + echo " policykit: no" fi echo " selinux: $have_selinux" echo diff --git a/src/nm-auth-manager.c b/src/nm-auth-manager.c index 092248fa5f..07996709d5 100644 --- a/src/nm-auth-manager.c +++ b/src/nm-auth-manager.c @@ -66,10 +66,12 @@ static guint signals[LAST_SIGNAL] = {0}; typedef struct { gboolean polkit_enabled; +#if WITH_POLKIT guint call_id_counter; GCancellable *new_proxy_cancellable; GSList *queued_calls; GDBusProxy *proxy; +#endif } NMAuthManagerPrivate; static NMAuthManager *_instance = NULL; @@ -100,6 +102,8 @@ nm_auth_manager_get_polkit_enabled (NMAuthManager *self) /*****************************************************************************/ +#if WITH_POLKIT + typedef enum { POLKIT_CHECK_AUTHORIZATION_FLAGS_NONE = 0, POLKIT_CHECK_AUTHORIZATION_FLAGS_ALLOW_USER_INTERACTION = (1<<0), @@ -477,6 +481,8 @@ _dbus_new_proxy_cb (GObject *source_object, _emit_changed_signal (self); } +#endif + /*****************************************************************************/ NMAuthManager * @@ -548,6 +554,7 @@ constructed (GObject *object) G_OBJECT_CLASS (nm_auth_manager_parent_class)->constructed (object); +#if WITH_POLKIT _LOGD ("create auth-manager: polkit %s", priv->polkit_enabled ? "enabled" : "disabled"); if (priv->polkit_enabled) { @@ -567,6 +574,12 @@ constructed (GObject *object) _dbus_new_proxy_cb, p_self); } +#else + if (priv->polkit_enabled) + _LOGW ("create auth-manager: polkit disabled at compile time. All authentication requests will fail"); + else + _LOGD ("create auth-manager: polkit disabled at compile time"); +#endif } @@ -574,10 +587,13 @@ static void dispose (GObject *object) { NMAuthManager* self = NM_AUTH_MANAGER (object); +#if WITH_POLKIT NMAuthManagerPrivate *priv = NM_AUTH_MANAGER_GET_PRIVATE (self); +#endif _LOGD ("dispose"); +#if WITH_POLKIT /* 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); @@ -591,6 +607,7 @@ dispose (GObject *object) g_signal_handlers_disconnect_by_func (priv->proxy, _dbus_on_g_signal_cb, self); g_clear_object (&priv->proxy); } +#endif G_OBJECT_CLASS (nm_auth_manager_parent_class)->dispose (object); } diff --git a/src/nm-auth-manager.h b/src/nm-auth-manager.h index 3f5ebc6589..06cd00867d 100644 --- a/src/nm-auth-manager.h +++ b/src/nm-auth-manager.h @@ -62,6 +62,8 @@ NMAuthManager *nm_auth_manager_get (void); gboolean nm_auth_manager_get_polkit_enabled (NMAuthManager *self); +#if WITH_POLKIT + void nm_auth_manager_polkit_authority_check_authorization (NMAuthManager *self, NMAuthSubject *subject, const char *action_id, @@ -75,6 +77,7 @@ gboolean nm_auth_manager_polkit_authority_check_authorization_finish (NMAuthMana gboolean *out_is_challenge, GError **error); +#endif G_END_DECLS diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c index f982616677..fa3b5dca47 100644 --- a/src/nm-auth-subject.c +++ b/src/nm-auth-subject.c @@ -150,6 +150,8 @@ nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len) return buf; } +#if WITH_POLKIT + /* returns a floating variant */ GVariant * nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self) @@ -171,6 +173,8 @@ nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self) return ret; } +#endif + NMAuthSubjectType nm_auth_subject_get_subject_type (NMAuthSubject *subject) { diff --git a/src/nm-auth-subject.h b/src/nm-auth-subject.h index 4e1d83162f..cc004fa90c 100644 --- a/src/nm-auth-subject.h +++ b/src/nm-auth-subject.h @@ -82,6 +82,10 @@ gulong nm_auth_subject_get_unix_process_uid (NMAuthSubject *subject); const char *nm_auth_subject_to_string (NMAuthSubject *self, char *buf, gsize buf_len); +#if WITH_POLKIT + GVariant * nm_auth_subject_unix_process_to_polkit_gvariant (NMAuthSubject *self); +#endif + #endif /* __NETWORKMANAGER_AUTH_SUBJECT_H__ */ diff --git a/src/nm-auth-utils.c b/src/nm-auth-utils.c index 0a652507e9..77b0fd1088 100644 --- a/src/nm-auth-utils.c +++ b/src/nm-auth-utils.c @@ -298,6 +298,7 @@ auth_call_cancel (gpointer user_data) } } +#if WITH_POLKIT static void pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data) { @@ -345,6 +346,7 @@ pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data) auth_call_complete (call); } +#endif void nm_auth_chain_add_call (NMAuthChain *self, @@ -369,6 +371,7 @@ nm_auth_chain_add_call (NMAuthChain *self, call->call_idle_id = g_idle_add ((GSourceFunc) auth_call_complete, call); } else { /* Non-root always gets authenticated when using polkit */ +#if WITH_POLKIT call->cancellable = g_cancellable_new (); nm_auth_manager_polkit_authority_check_authorization (auth_manager, self->subject, @@ -377,6 +380,14 @@ nm_auth_chain_add_call (NMAuthChain *self, call->cancellable, pk_call_cb, call); +#else + if (!call->chain->error) { + call->chain->error = g_error_new_literal (DBUS_GERROR, + DBUS_GERROR_FAILED, + "Polkit support is disabled at compile time"); + } + call->call_idle_id = g_idle_add ((GSourceFunc) auth_call_complete, call); +#endif } } -- cgit v1.2.1