Commit 0621de7d authored by Dan Williams's avatar Dan Williams

core: use same codepaths for root and non-root during authentication

Instead of doing something like

<get caller UID>
if (root) {
   perform_operation()
   other boilerplate stuff
   return;
}

nm_auth_chain_new(perform_operation)
...

just have root also go through the auth chain, which is now
short circuited for root.  This ensures we always use the same
code paths for root and non-root, and that fixes made in one path
are also executed for the other.
parent f7b720b0
......@@ -42,8 +42,11 @@ struct NMAuthChain {
DBusGMethodInvocation *context;
char *owner;
gulong user_uid;
GError *error;
guint idle_id;
NMAuthChainResultFunc done_func;
gpointer user_data;
};
......@@ -72,6 +75,20 @@ free_data (gpointer data)
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)
......@@ -92,6 +109,7 @@ _auth_chain_new (DBusGMethodInvocation *context,
DBusGProxy *proxy,
DBusMessage *message,
const char *dbus_sender,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
......@@ -108,6 +126,7 @@ _auth_chain_new (DBusGMethodInvocation *context,
self->done_func = done_func;
self->user_data = user_data;
self->context = context;
self->user_uid = user_uid;
if (proxy)
self->owner = g_strdup (dbus_g_proxy_get_bus_name (proxy));
......@@ -118,7 +137,7 @@ _auth_chain_new (DBusGMethodInvocation *context,
else if (dbus_sender)
self->owner = g_strdup (dbus_sender);
if (!self->owner) {
if (user_uid > 0 && !self->owner) {
/* Need an owner */
g_warn_if_fail (self->owner);
nm_auth_chain_unref (self);
......@@ -131,26 +150,29 @@ _auth_chain_new (DBusGMethodInvocation *context,
NMAuthChain *
nm_auth_chain_new (DBusGMethodInvocation *context,
DBusGProxy *proxy,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
return _auth_chain_new (context, proxy, NULL, NULL, done_func, user_data);
return _auth_chain_new (context, proxy, NULL, NULL, user_uid, done_func, user_data);
}
NMAuthChain *
nm_auth_chain_new_raw_message (DBusMessage *message,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
return _auth_chain_new (NULL, NULL, message, NULL, done_func, user_data);
return _auth_chain_new (NULL, NULL, message, NULL, user_uid, done_func, user_data);
}
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, NULL, NULL, dbus_sender, done_func, user_data);
return _auth_chain_new (NULL, NULL, NULL, dbus_sender, user_uid, done_func, user_data);
}
gpointer
......@@ -261,10 +283,8 @@ nm_auth_chain_check_done (NMAuthChain *self)
g_return_if_fail (self != NULL);
if (g_slist_length (self->calls) == 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);
g_assert (self->idle_id == 0);
self->idle_id = g_idle_add (auth_chain_finish, self);
}
}
......@@ -372,7 +392,6 @@ pk_call_cb (GObject *object, GAsyncResult *result, gpointer user_data)
auth_call_complete (call);
}
#endif
static void
auth_call_schedule_complete_with_error (AuthCall *call, const char *msg)
......@@ -382,16 +401,14 @@ auth_call_schedule_complete_with_error (AuthCall *call, const char *msg)
call->idle_id = g_idle_add ((GSourceFunc) auth_call_complete, call);
}
gboolean
nm_auth_chain_add_call (NMAuthChain *self,
const char *permission,
gboolean allow_interaction)
static gboolean
_add_call_polkit (NMAuthChain *self,
const char *permission,
gboolean allow_interaction)
{
AuthCall *call;
#if WITH_POLKIT
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 != NULL, FALSE);
......@@ -423,17 +440,29 @@ nm_auth_chain_add_call (NMAuthChain *self,
pk_call_cb,
call);
g_object_unref (subject);
#else
/* -- NO POLKIT -- */
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);
/* When PolicyKit is disabled, everything is authorized */
#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->idle_id = g_idle_add ((GSourceFunc) auth_call_complete, call);
#endif
return TRUE;
}
......@@ -448,6 +477,9 @@ nm_auth_chain_unref (NMAuthChain *self)
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);
......
......@@ -57,14 +57,17 @@ typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain,
NMAuthChain *nm_auth_chain_new (DBusGMethodInvocation *context,
DBusGProxy *proxy,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data);
NMAuthChain *nm_auth_chain_new_raw_message (DBusMessage *message,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data);
NMAuthChain *nm_auth_chain_new_dbus_sender (const char *dbus_sender,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data);
......
This diff is collapsed.
......@@ -212,6 +212,7 @@ agent_register_permissions_done (NMAuthChain *chain,
g_error_free (local);
} else {
agent = nm_auth_chain_steal_data (chain, "agent");
g_assert (agent);
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED);
if (result == NM_AUTH_CALL_RESULT_YES)
......@@ -297,13 +298,13 @@ impl_agent_manager_register (NMAgentManager *self,
nm_secret_agent_get_description (agent));
/* Kick off permissions requests for this agent */
chain = nm_auth_chain_new (context, NULL, agent_register_permissions_done, self);
chain = nm_auth_chain_new (context, NULL, sender_uid, agent_register_permissions_done, self);
g_assert (chain);
priv->chains = g_slist_append (priv->chains, chain);
nm_auth_chain_set_data (chain, "agent", agent, g_object_unref);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE);
priv->chains = g_slist_append (priv->chains, chain);
done:
if (error)
dbus_g_method_return_error (context, error);
......@@ -816,7 +817,6 @@ get_agent_modify_auth_cb (NMAuthChain *chain,
gpointer user_data)
{
Request *req = user_data;
NMAuthCallResult result;
const char *perm;
req->chain = NULL;
......@@ -835,15 +835,15 @@ get_agent_modify_auth_cb (NMAuthChain *chain,
*/
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)
if (nm_auth_chain_get_result (chain, perm) == NM_AUTH_CALL_RESULT_YES)
req->current_has_modify = TRUE;
nm_log_dbg (LOGD_AGENTS, "(%p/%s) agent MODIFY check result %d",
req, req->setting_name, result);
nm_log_dbg (LOGD_AGENTS, "(%p/%s) agent MODIFY check result %s",
req, req->setting_name, req->current_has_modify ? "YES" : "NO");
get_agent_request_secrets (req, req->current_has_modify);
}
nm_auth_chain_unref (chain);
}
......@@ -912,6 +912,7 @@ get_next_cb (Request *req)
req, req->setting_name, agent_dbus_owner);
req->chain = nm_auth_chain_new_dbus_sender (agent_dbus_owner,
nm_secret_agent_get_owner_uid (NM_SECRET_AGENT (req->current)),
get_agent_modify_auth_cb,
req);
g_assert (req->chain);
......@@ -1337,32 +1338,29 @@ agent_permissions_changed_done (NMAuthChain *chain,
NMAgentManager *self = NM_AGENT_MANAGER (user_data);
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
NMSecretAgent *agent;
NMAuthCallResult result;
gboolean share_protected = FALSE, share_open = FALSE;
priv->chains = g_slist_remove (priv->chains, chain);
agent = nm_auth_chain_get_data (chain, "agent");
g_assert (agent);
if (error) {
nm_log_dbg (LOGD_AGENTS, "(%s) failed to request updated agent permissions",
nm_secret_agent_get_description (agent));
nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE);
nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE);
} else {
nm_log_dbg (LOGD_AGENTS, "(%s) updated agent permissions",
nm_secret_agent_get_description (agent));
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED);
nm_secret_agent_add_permission (agent,
NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED,
(result == NM_AUTH_CALL_RESULT_YES));
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN);
nm_secret_agent_add_permission (agent,
NM_AUTH_PERMISSION_WIFI_SHARE_OPEN,
(result == NM_AUTH_CALL_RESULT_YES));
if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED) == NM_AUTH_CALL_RESULT_YES)
share_protected = TRUE;
if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN) == NM_AUTH_CALL_RESULT_YES)
share_open = TRUE;
}
nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, share_protected);
nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, share_open);
nm_auth_chain_unref (chain);
}
......@@ -1378,11 +1376,14 @@ authority_changed_cb (gpointer user_data)
g_hash_table_iter_init (&iter, priv->agents);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) {
NMAuthChain *chain;
const char *sender;
/* Kick off permissions requests for this agent */
sender = nm_secret_agent_get_dbus_owner (agent);
chain = nm_auth_chain_new_dbus_sender (sender, agent_permissions_changed_done, self);
chain = nm_auth_chain_new_dbus_sender (nm_secret_agent_get_dbus_owner (agent),
nm_secret_agent_get_owner_uid (agent),
agent_permissions_changed_done,
self);
g_assert (chain);
priv->chains = g_slist_append (priv->chains, chain);
/* Make sure if the agent quits while the permissions call is in progress
* that the object sticks around until our callback.
......@@ -1390,8 +1391,6 @@ authority_changed_cb (gpointer user_data)
nm_auth_chain_set_data (chain, "agent", g_object_ref (agent), g_object_unref);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE);
priv->chains = g_slist_append (priv->chains, chain);
}
}
......
......@@ -896,23 +896,20 @@ pk_auth_cb (NMAuthChain *chain,
priv->pending_auths = g_slist_remove (priv->pending_auths, chain);
perm = nm_auth_chain_get_data (chain, "perm");
g_assert (perm);
result = nm_auth_chain_get_result (chain, perm);
/* If our NMSettingsConnection is already gone, do nothing */
if (chain_error) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_GENERAL,
"Error checking authorization: %s",
chain_error->message ? chain_error->message : "(unknown)");
} else {
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) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_NOT_PRIVILEGED,
"Insufficient privileges.");
}
} else if (result != NM_AUTH_CALL_RESULT_YES) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Insufficient privileges.");
}
callback = nm_auth_chain_get_data (chain, "callback");
......@@ -990,15 +987,16 @@ auth_start (NMSettingsConnection *self,
}
if (check_permission) {
chain = nm_auth_chain_new (context, NULL, pk_auth_cb, self);
chain = nm_auth_chain_new (context, NULL, sender_uid, pk_auth_cb, self);
g_assert (chain);
priv->pending_auths = g_slist_append (priv->pending_auths, chain);
nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, 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);
nm_auth_chain_add_call (chain, check_permission, TRUE);
priv->pending_auths = g_slist_append (priv->pending_auths, chain);
} else {
/* Don't need polkit auth, automatic success */
callback (self, context, sender_uid, NULL, callback_data);
......
......@@ -997,39 +997,34 @@ pk_add_cb (NMAuthChain *chain,
priv->auths = g_slist_remove (priv->auths, chain);
perm = nm_auth_chain_get_data (chain, "perm");
g_assert (perm);
result = nm_auth_chain_get_result (chain, perm);
if (chain_error) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_GENERAL,
"Error checking authorization: %s",
chain_error->message ? chain_error->message : "(unknown)");
goto done;
}
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) {
} else if (result != NM_AUTH_CALL_RESULT_YES) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_NOT_PRIVILEGED,
"Insufficient privileges.");
goto done;
}
connection = nm_auth_chain_get_data (chain, "connection");
g_assert (connection);
added = add_new_connection (self, connection, &add_error);
if (!added) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_ADD_FAILED,
"Saving connection failed: (%d) %s",
add_error ? add_error->code : -1,
(add_error && add_error->message) ? add_error->message : "(unknown)");
g_error_free (add_error);
} else {
/* Authorized */
connection = nm_auth_chain_get_data (chain, "connection");
g_assert (connection);
added = add_new_connection (self, connection, &add_error);
if (!added) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_ADD_FAILED,
"Saving connection failed: (%d) %s",
add_error ? add_error->code : -1,
(add_error && add_error->message) ? add_error->message : "(unknown)");
g_clear_error (&add_error);
}
}
done:
callback = nm_auth_chain_get_data (chain, "callback");
callback_data = nm_auth_chain_get_data (chain, "callback-data");
caller_uid = nm_auth_chain_get_data_ulong (chain, "caller-uid");
......@@ -1180,7 +1175,7 @@ nm_settings_add_connection (NMSettings *self,
perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM;
/* Otherwise validate the user request */
chain = nm_auth_chain_new (context, NULL, pk_add_cb, self);
chain = nm_auth_chain_new (context, NULL, caller_uid, pk_add_cb, self);
g_assert (chain);
priv->auths = g_slist_append (priv->auths, chain);
nm_auth_chain_add_call (chain, perm, TRUE);
......@@ -1219,51 +1214,43 @@ pk_hostname_cb (NMAuthChain *chain,
NMSettings *self = NM_SETTINGS (user_data);
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
NMAuthCallResult result;
gboolean success = FALSE;
GError *error = NULL;
GSList *iter;
const char *hostname;
priv->auths = g_slist_remove (priv->auths, chain);
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME);
/* If our NMSettingsConnection is already gone, do nothing */
if (chain_error) {
error = g_error_new (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_GENERAL,
"Error checking authorization: %s",
chain_error->message ? chain_error->message : "(unknown)");
goto done;
}
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME);
/* Caller didn't successfully authenticate */
if (result != NM_AUTH_CALL_RESULT_YES) {
} else if (result != NM_AUTH_CALL_RESULT_YES) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_NOT_PRIVILEGED,
"Insufficient privileges.");
goto done;
}
} else {
/* Set the hostname in all plugins */
hostname = nm_auth_chain_get_data (chain, "hostname");
for (iter = priv->plugins; iter; iter = iter->next) {
NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
/* Set the hostname in all plugins */
hostname = nm_auth_chain_get_data (chain, "hostname");
for (iter = priv->plugins; iter; iter = iter->next) {
NMSystemConfigInterfaceCapabilities caps = NM_SYSTEM_CONFIG_INTERFACE_CAP_NONE;
/* error will be cleared if any plugin supports saving the hostname */
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED,
"Saving the hostname failed.");
g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL);
if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) {
g_object_set (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, hostname, NULL);
success = TRUE;
g_object_get (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_CAPABILITIES, &caps, NULL);
if (caps & NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME) {
g_object_set (G_OBJECT (iter->data), NM_SYSTEM_CONFIG_INTERFACE_HOSTNAME, hostname, NULL);
g_clear_error (&error);
}
}
}
if (!success) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_SAVE_HOSTNAME_FAILED,
"Saving the hostname failed.");
}
done:
if (error)
dbus_g_method_return_error (context, error);
else
......@@ -1281,23 +1268,29 @@ impl_settings_save_hostname (NMSettings *self,
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
NMAuthChain *chain;
GError *error = NULL;
gulong sender_uid = G_MAXULONG;
/* Do any of the plugins support setting the hostname? */
if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED,
"None of the registered plugins support setting the hostname.");
} else if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &sender_uid)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Unable to determine request UID.");
} else {
chain = nm_auth_chain_new (context, NULL, sender_uid, pk_hostname_cb, self);
g_assert (chain);
priv->auths = g_slist_append (priv->auths, chain);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE);
nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free);
}
if (error) {
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
/* Otherwise validate the user request */
chain = nm_auth_chain_new (context, NULL, pk_hostname_cb, self);
g_assert (chain);
priv->auths = g_slist_append (priv->auths, chain);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE);
nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free);
}
static gboolean
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment