diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c index d094c4ffc6..2e0772e9e9 100644 --- a/src/settings/nm-agent-manager.c +++ b/src/settings/nm-agent-manager.c @@ -35,6 +35,7 @@ #include "nm-polkit-helpers.h" #include "nm-manager-auth.h" #include "nm-setting-vpn.h" +#include "nm-setting-connection.h" G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, G_TYPE_OBJECT) @@ -762,9 +763,9 @@ get_agent_modify_auth_cb (NMAuthChain *chain, { Request *req = user_data; NMAuthCallResult result; + const char *perm; req->chain = NULL; - nm_auth_chain_unref (chain); if (error) { nm_log_dbg (LOGD_AGENTS, "(%p/%s) agent MODIFY check error: (%d) %s", @@ -778,7 +779,9 @@ get_agent_modify_auth_cb (NMAuthChain *chain, * to it. If it didn't, we still ask it for secrets, but we don't send * any system secrets. */ - result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM); + perm = nm_auth_chain_get_data (chain, "perm"); + g_assert (perm); + result = nm_auth_chain_get_result (chain, perm); if (result == NM_AUTH_CALL_RESULT_YES) req->current_has_modify = TRUE; @@ -787,12 +790,14 @@ get_agent_modify_auth_cb (NMAuthChain *chain, get_agent_request_secrets (req, req->current_has_modify); } + nm_auth_chain_unref (chain); } static void get_next_cb (Request *req) { - const char *agent_dbus_owner; + NMSettingConnection *s_con; + const char *agent_dbus_owner, *perm; if (!next_generic (req, "getting")) return; @@ -813,7 +818,20 @@ get_next_cb (Request *req) get_agent_modify_auth_cb, req); g_assert (req->chain); - nm_auth_chain_add_call (req->chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, TRUE); + + /* If the caller is the only user in the connection's permissions, then + * we use the 'modify.own' permission instead of 'modify.system'. If the + * request affects more than just the caller, require 'modify.system'. + */ + s_con = (NMSettingConnection *) nm_connection_get_setting (req->connection, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + if (nm_setting_connection_get_num_permissions (s_con) == 1) + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; + else + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; + nm_auth_chain_set_data (req->chain, "perm", (gpointer) perm, NULL); + + nm_auth_chain_add_call (req->chain, perm, TRUE); } else { nm_log_dbg (LOGD_AGENTS, "(%p/%s) requesting user-owned secrets from agent %s", req, req->setting_name, agent_dbus_owner); diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index b8afed23ab..c26daeda8d 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -696,12 +696,6 @@ typedef void (*AuthCallback) (NMSettingsConnection *connection, GError *error, gpointer data); -typedef struct { - AuthCallback callback; - gpointer callback_data; - gulong sender_uid; -} PkAuthInfo; - static void pk_auth_cb (NMAuthChain *chain, GError *chain_error, @@ -712,7 +706,10 @@ pk_auth_cb (NMAuthChain *chain, NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); GError *error = NULL; NMAuthCallResult result; - PkAuthInfo *info; + const char *perm; + AuthCallback callback; + gpointer callback_data; + gulong sender_uid; priv->pending_auths = g_slist_remove (priv->pending_auths, chain); @@ -723,7 +720,9 @@ pk_auth_cb (NMAuthChain *chain, "Error checking authorization: %s", chain_error->message ? chain_error->message : "(unknown)"); } else { - result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM); + perm = nm_auth_chain_get_data (chain, "perm"); + g_assert (perm); + result = nm_auth_chain_get_result (chain, perm); /* Caller didn't successfully authenticate */ if (result != NM_AUTH_CALL_RESULT_YES) { @@ -733,8 +732,10 @@ pk_auth_cb (NMAuthChain *chain, } } - info = nm_auth_chain_get_data (chain, "pk-auth-info"); - info->callback (self, context, info->sender_uid, error, info->callback_data); + callback = nm_auth_chain_get_data (chain, "callback"); + callback_data = nm_auth_chain_get_data (chain, "callback-data"); + sender_uid = nm_auth_chain_get_data_ulong (chain, "sender-uid"); + callback (self, context, sender_uid, error, callback_data); g_clear_error (&error); nm_auth_chain_unref (chain); @@ -750,7 +751,6 @@ auth_start (NMSettingsConnection *self, NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMAuthChain *chain; gulong sender_uid = G_MAXULONG; - PkAuthInfo *info; GError *error = NULL; char *error_desc = NULL; @@ -778,16 +778,28 @@ auth_start (NMSettingsConnection *self, } if (check_modify) { + NMSettingConnection *s_con; + const char *perm; + + /* If the caller is the only user in the connection's permissions, then + * we use the 'modify.own' permission instead of 'modify.system'. If the + * request affects more than just the caller, require 'modify.system'. + */ + s_con = (NMSettingConnection *) nm_connection_get_setting (NM_CONNECTION (self), NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + if (nm_setting_connection_get_num_permissions (s_con) == 1) + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; + else + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; + chain = nm_auth_chain_new (priv->authority, context, NULL, pk_auth_cb, self); g_assert (chain); + nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL); + nm_auth_chain_set_data (chain, "callback", callback, NULL); + nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL); + nm_auth_chain_set_data_ulong (chain, "sender-uid", sender_uid); - info = g_malloc0 (sizeof (*info)); - info->callback = callback; - info->callback_data = callback_data; - info->sender_uid = sender_uid; - nm_auth_chain_set_data (chain, "pk-auth-info", info, g_free); - - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, TRUE); + nm_auth_chain_add_call (chain, perm, TRUE); priv->pending_auths = g_slist_append (priv->pending_auths, chain); } else { /* Don't need polkit auth, automatic success */ diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index 3e38a2f048..7f705d9f06 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -800,10 +800,9 @@ pk_add_cb (NMAuthChain *chain, GError *error = NULL, *add_error = NULL; NMConnection *connection; NMSettingsConnection *added = NULL; - gulong caller_uid = G_MAXULONG; - char *error_desc = NULL; NMSettingsAddCallback callback; gpointer callback_data; + const char *perm; priv->auths = g_slist_remove (priv->auths, chain); @@ -815,7 +814,9 @@ pk_add_cb (NMAuthChain *chain, goto done; } - result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM); + perm = nm_auth_chain_get_data (chain, "perm"); + g_assert (perm); + result = nm_auth_chain_get_result (chain, perm); /* Caller didn't successfully authenticate */ if (result != NM_AUTH_CALL_RESULT_YES) { @@ -825,35 +826,8 @@ pk_add_cb (NMAuthChain *chain, goto done; } - /* If the caller isn't root, make sure the connection can be viewed by - * the user that's adding it. - */ - if (!nm_auth_get_caller_uid (context, priv->dbus_mgr, &caller_uid, &error_desc)) { - error = g_error_new (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_NOT_PRIVILEGED, - "Unable to determine UID of request: %s.", - error_desc ? error_desc : "(unknown)"); - g_free (error_desc); - goto done; - } - connection = nm_auth_chain_get_data (chain, "connection"); - - /* Ensure the caller's username exists in the connection's permissions, - * or that the permissions is empty (ie, visible by everyone). - */ - if (0 != caller_uid) { - if (!nm_auth_uid_in_acl (connection, priv->session_monitor, caller_uid, &error_desc)) { - error = g_error_new_literal (NM_SETTINGS_ERROR, - NM_SETTINGS_ERROR_NOT_PRIVILEGED, - error_desc); - g_free (error_desc); - goto done; - } - - /* Caller is allowed to add this connection */ - } - + g_assert (connection); added = add_new_connection (self, connection, &add_error); if (!added) { error = g_error_new (NM_SETTINGS_ERROR, @@ -895,8 +869,12 @@ nm_settings_add_connection (NMSettings *self, gpointer user_data) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + NMSettingConnection *s_con; NMAuthChain *chain; GError *error = NULL, *tmp_error = NULL; + gulong caller_uid = G_MAXULONG; + char *error_desc = NULL; + const char *perm; /* Connection must be valid, of course */ if (!nm_connection_verify (connection, &tmp_error)) { @@ -905,7 +883,6 @@ nm_settings_add_connection (NMSettings *self, "The connection was invalid: %s", tmp_error ? tmp_error->message : "(unknown)"); g_error_free (tmp_error); - callback (self, NULL, error, context, user_data); g_error_free (error); return; @@ -921,11 +898,52 @@ nm_settings_add_connection (NMSettings *self, return; } + /* Get the caller's UID */ + if (!nm_auth_get_caller_uid (context, priv->dbus_mgr, &caller_uid, &error_desc)) { + error = g_error_new (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_NOT_PRIVILEGED, + "Unable to determine UID of request: %s.", + error_desc ? error_desc : "(unknown)"); + g_free (error_desc); + callback (self, NULL, error, context, user_data); + g_error_free (error); + return; + } + + /* Ensure the caller's username exists in the connection's permissions, + * or that the permissions is empty (ie, visible by everyone). + */ + if (0 != caller_uid) { + if (!nm_auth_uid_in_acl (connection, priv->session_monitor, caller_uid, &error_desc)) { + error = g_error_new_literal (NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_NOT_PRIVILEGED, + error_desc); + g_free (error_desc); + callback (self, NULL, error, context, user_data); + g_error_free (error); + return; + } + + /* Caller is allowed to add this connection */ + } + + /* If the caller is the only user in the connection's permissions, then + * we use the 'modify.own' permission instead of 'modify.system'. If the + * request affects more than just the caller, require 'modify.system'. + */ + s_con = (NMSettingConnection *) nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION); + g_assert (s_con); + if (nm_setting_connection_get_num_permissions (s_con) == 1) + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN; + else + perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM; + /* Otherwise validate the user request */ chain = nm_auth_chain_new (priv->authority, context, NULL, pk_add_cb, self); g_assert (chain); priv->auths = g_slist_append (priv->auths, chain); - nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, TRUE); + nm_auth_chain_add_call (chain, perm, TRUE); + nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL); nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref); nm_auth_chain_set_data (chain, "callback", callback, NULL); nm_auth_chain_set_data (chain, "callback-data", user_data, NULL);