2010-12-10 12:38:19 -06:00
|
|
|
/* -*- 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.
|
|
|
|
|
*
|
agents: fix removing requests from hash table while iterating it
GLib-CRITICAL **: g_hash_table_iter_next: assertion 'ri->version == ri->hash_table->version' failed
It is not allowed to modify hash table while it is iterated. Unfortunately,
request_remove_agent() may remove the request from the 'requests' hash table,
making it not usable in the loop hash table looping.
We need to store the request into a temporary list and call request_next_agent()
on them later (after the hash loop).
Test case:
1. start NM and nm-applet
2. activate a Wi-Fi WPA connection
3. nm-applet displays a dialog asking for a password
4. kill nm-applet
5. NetworkManager removes the nm-applet's secret agent
and runs into removing the request from hash table in the
iterating loop (via get_complete_cb)
#0 get_complete_cb (parent=0x7f3f250f2970, secrets=0x0, agent_dbus_owner=0x0, agent_username=0x0, error=0x7f3f250f7830, user_data=0x7f3f25020e10)
at settings/nm-agent-manager.c:1111
#1 0x00007f3f23b46ea5 in req_complete_error (error=0x7f3f250f7830, req=0x7f3f250f2970) at settings/nm-agent-manager.c:509
#2 request_next_agent (req=0x7f3f250f2970) at settings/nm-agent-manager.c:615
#3 0x00007f3f23b48596 in request_remove_agent (agent=0x7f3f250f4a20, req=0x7f3f250f2970) at settings/nm-agent-manager.c:631
#4 remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:130
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
#0 0x00007f3f1fb9c4e9 in g_logv (log_domain=0x7f3f1fbfef4e "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff156b77c0) at gmessages.c:989
#1 0x00007f3f1fb9c63f in g_log (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL,
format=format@entry=0x7f3f1fc0889a "%s: assertion '%s' failed") at gmessages.c:1025
#2 0x00007f3f1fb9c679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib",
pretty_function=pretty_function@entry=0x7f3f1fc03c30 <__PRETTY_FUNCTION__.4571> "g_hash_table_iter_next",
expression=expression@entry=0x7f3f1fc038f0 "ri->version == ri->hash_table->version") at gmessages.c:1034
#3 0x00007f3f1fb849c0 in g_hash_table_iter_next (iter=<optimized out>, key=<optimized out>, value=<optimized out>) at ghash.c:733
#4 0x00007f3f23b484e5 in remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:129
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
2013-11-21 10:31:28 +01:00
|
|
|
* Copyright (C) 2010 - 2013 Red Hat, Inc.
|
2010-12-10 12:38:19 -06:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
#include <string.h>
|
2011-03-31 18:39:09 -05:00
|
|
|
#include <pwd.h>
|
2010-12-10 12:38:19 -06:00
|
|
|
|
|
|
|
|
#include <glib.h>
|
|
|
|
|
#include <dbus/dbus-glib.h>
|
|
|
|
|
#include <dbus/dbus-glib-lowlevel.h>
|
|
|
|
|
|
|
|
|
|
#include "NetworkManager.h"
|
2010-12-10 13:32:45 -06:00
|
|
|
#include "nm-logging.h"
|
2010-12-10 12:38:19 -06:00
|
|
|
#include "nm-agent-manager.h"
|
|
|
|
|
#include "nm-secret-agent.h"
|
|
|
|
|
#include "nm-manager-auth.h"
|
2010-12-14 15:34:34 -06:00
|
|
|
#include "nm-dbus-glib-types.h"
|
2011-02-02 16:19:15 -06:00
|
|
|
#include "nm-manager-auth.h"
|
2011-02-10 11:36:00 -06:00
|
|
|
#include "nm-setting-vpn.h"
|
2011-02-11 17:06:57 -06:00
|
|
|
#include "nm-setting-connection.h"
|
2012-02-08 12:56:52 -05:00
|
|
|
#include "nm-enum-types.h"
|
2010-12-10 12:38:19 -06:00
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
|
|
#define NM_AGENT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
|
|
|
|
|
NM_TYPE_AGENT_MANAGER, \
|
|
|
|
|
NMAgentManagerPrivate))
|
|
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
|
gboolean disposed;
|
|
|
|
|
|
|
|
|
|
NMDBusManager *dbus_mgr;
|
|
|
|
|
NMSessionMonitor *session_monitor;
|
|
|
|
|
|
2011-07-01 14:34:08 -05:00
|
|
|
/* Auth chains for checking agent permissions */
|
|
|
|
|
GSList *chains;
|
|
|
|
|
|
2010-12-10 12:38:19 -06:00
|
|
|
/* Hashed by owner name, not identifier, since two agents in different
|
|
|
|
|
* sessions can use the same identifier.
|
|
|
|
|
*/
|
|
|
|
|
GHashTable *agents;
|
2010-12-13 13:11:51 -06:00
|
|
|
|
|
|
|
|
GHashTable *requests;
|
2010-12-10 12:38:19 -06:00
|
|
|
} NMAgentManagerPrivate;
|
|
|
|
|
|
2011-06-28 15:48:12 +02:00
|
|
|
enum {
|
|
|
|
|
AGENT_REGISTERED,
|
|
|
|
|
|
|
|
|
|
LAST_SIGNAL
|
|
|
|
|
};
|
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
|
|
|
|
|
2010-12-14 15:34:34 -06:00
|
|
|
typedef struct _Request Request;
|
|
|
|
|
|
|
|
|
|
static void request_add_agent (Request *req,
|
|
|
|
|
NMSecretAgent *agent,
|
|
|
|
|
NMSessionMonitor *session_monitor);
|
|
|
|
|
|
agents: fix removing requests from hash table while iterating it
GLib-CRITICAL **: g_hash_table_iter_next: assertion 'ri->version == ri->hash_table->version' failed
It is not allowed to modify hash table while it is iterated. Unfortunately,
request_remove_agent() may remove the request from the 'requests' hash table,
making it not usable in the loop hash table looping.
We need to store the request into a temporary list and call request_next_agent()
on them later (after the hash loop).
Test case:
1. start NM and nm-applet
2. activate a Wi-Fi WPA connection
3. nm-applet displays a dialog asking for a password
4. kill nm-applet
5. NetworkManager removes the nm-applet's secret agent
and runs into removing the request from hash table in the
iterating loop (via get_complete_cb)
#0 get_complete_cb (parent=0x7f3f250f2970, secrets=0x0, agent_dbus_owner=0x0, agent_username=0x0, error=0x7f3f250f7830, user_data=0x7f3f25020e10)
at settings/nm-agent-manager.c:1111
#1 0x00007f3f23b46ea5 in req_complete_error (error=0x7f3f250f7830, req=0x7f3f250f2970) at settings/nm-agent-manager.c:509
#2 request_next_agent (req=0x7f3f250f2970) at settings/nm-agent-manager.c:615
#3 0x00007f3f23b48596 in request_remove_agent (agent=0x7f3f250f4a20, req=0x7f3f250f2970) at settings/nm-agent-manager.c:631
#4 remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:130
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
#0 0x00007f3f1fb9c4e9 in g_logv (log_domain=0x7f3f1fbfef4e "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff156b77c0) at gmessages.c:989
#1 0x00007f3f1fb9c63f in g_log (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL,
format=format@entry=0x7f3f1fc0889a "%s: assertion '%s' failed") at gmessages.c:1025
#2 0x00007f3f1fb9c679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib",
pretty_function=pretty_function@entry=0x7f3f1fc03c30 <__PRETTY_FUNCTION__.4571> "g_hash_table_iter_next",
expression=expression@entry=0x7f3f1fc038f0 "ri->version == ri->hash_table->version") at gmessages.c:1034
#3 0x00007f3f1fb849c0 in g_hash_table_iter_next (iter=<optimized out>, key=<optimized out>, value=<optimized out>) at ghash.c:733
#4 0x00007f3f23b484e5 in remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:129
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
2013-11-21 10:31:28 +01:00
|
|
|
static void request_remove_agent (Request *req, NMSecretAgent *agent, GSList **pending_reqs);
|
|
|
|
|
|
|
|
|
|
static void request_next_agent (Request *req);
|
2010-12-10 12:38:19 -06:00
|
|
|
|
|
|
|
|
static void impl_agent_manager_register (NMAgentManager *self,
|
|
|
|
|
const char *identifier,
|
|
|
|
|
DBusGMethodInvocation *context);
|
|
|
|
|
|
2013-07-18 22:39:39 -05:00
|
|
|
static void impl_agent_manager_register_with_capabilities (NMAgentManager *self,
|
|
|
|
|
const char *identifier,
|
|
|
|
|
NMSecretAgentCapabilities capabilities,
|
|
|
|
|
DBusGMethodInvocation *context);
|
|
|
|
|
|
2010-12-10 12:38:19 -06:00
|
|
|
static void impl_agent_manager_unregister (NMAgentManager *self,
|
|
|
|
|
DBusGMethodInvocation *context);
|
|
|
|
|
|
|
|
|
|
#include "nm-agent-manager-glue.h"
|
|
|
|
|
|
|
|
|
|
/********************************************************************/
|
|
|
|
|
|
|
|
|
|
#define NM_AGENT_MANAGER_ERROR (nm_agent_manager_error_quark ())
|
|
|
|
|
|
|
|
|
|
static GQuark
|
|
|
|
|
nm_agent_manager_error_quark (void)
|
|
|
|
|
{
|
|
|
|
|
static GQuark ret = 0;
|
|
|
|
|
|
|
|
|
|
if (G_UNLIKELY (ret == 0))
|
|
|
|
|
ret = g_quark_from_static_string ("nm-agent-manager-error");
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************/
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
remove_agent (NMAgentManager *self, const char *owner)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
NMSecretAgent *agent;
|
2010-12-14 15:34:34 -06:00
|
|
|
GHashTableIter iter;
|
|
|
|
|
gpointer data;
|
agents: fix removing requests from hash table while iterating it
GLib-CRITICAL **: g_hash_table_iter_next: assertion 'ri->version == ri->hash_table->version' failed
It is not allowed to modify hash table while it is iterated. Unfortunately,
request_remove_agent() may remove the request from the 'requests' hash table,
making it not usable in the loop hash table looping.
We need to store the request into a temporary list and call request_next_agent()
on them later (after the hash loop).
Test case:
1. start NM and nm-applet
2. activate a Wi-Fi WPA connection
3. nm-applet displays a dialog asking for a password
4. kill nm-applet
5. NetworkManager removes the nm-applet's secret agent
and runs into removing the request from hash table in the
iterating loop (via get_complete_cb)
#0 get_complete_cb (parent=0x7f3f250f2970, secrets=0x0, agent_dbus_owner=0x0, agent_username=0x0, error=0x7f3f250f7830, user_data=0x7f3f25020e10)
at settings/nm-agent-manager.c:1111
#1 0x00007f3f23b46ea5 in req_complete_error (error=0x7f3f250f7830, req=0x7f3f250f2970) at settings/nm-agent-manager.c:509
#2 request_next_agent (req=0x7f3f250f2970) at settings/nm-agent-manager.c:615
#3 0x00007f3f23b48596 in request_remove_agent (agent=0x7f3f250f4a20, req=0x7f3f250f2970) at settings/nm-agent-manager.c:631
#4 remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:130
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
#0 0x00007f3f1fb9c4e9 in g_logv (log_domain=0x7f3f1fbfef4e "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff156b77c0) at gmessages.c:989
#1 0x00007f3f1fb9c63f in g_log (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL,
format=format@entry=0x7f3f1fc0889a "%s: assertion '%s' failed") at gmessages.c:1025
#2 0x00007f3f1fb9c679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib",
pretty_function=pretty_function@entry=0x7f3f1fc03c30 <__PRETTY_FUNCTION__.4571> "g_hash_table_iter_next",
expression=expression@entry=0x7f3f1fc038f0 "ri->version == ri->hash_table->version") at gmessages.c:1034
#3 0x00007f3f1fb849c0 in g_hash_table_iter_next (iter=<optimized out>, key=<optimized out>, value=<optimized out>) at ghash.c:733
#4 0x00007f3f23b484e5 in remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:129
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
2013-11-21 10:31:28 +01:00
|
|
|
GSList *pending_reqs = NULL;
|
2010-12-10 12:38:19 -06:00
|
|
|
|
|
|
|
|
g_return_val_if_fail (owner != NULL, FALSE);
|
|
|
|
|
|
2010-12-14 15:34:34 -06:00
|
|
|
/* Make sure this agent has already registered */
|
2010-12-10 12:38:19 -06:00
|
|
|
agent = g_hash_table_lookup (priv->agents, owner);
|
|
|
|
|
if (!agent)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2013-06-26 14:11:33 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent unregistered or disappeared",
|
2010-12-14 15:34:34 -06:00
|
|
|
nm_secret_agent_get_description (agent));
|
2010-12-10 12:38:19 -06:00
|
|
|
|
agents: fix removing requests from hash table while iterating it
GLib-CRITICAL **: g_hash_table_iter_next: assertion 'ri->version == ri->hash_table->version' failed
It is not allowed to modify hash table while it is iterated. Unfortunately,
request_remove_agent() may remove the request from the 'requests' hash table,
making it not usable in the loop hash table looping.
We need to store the request into a temporary list and call request_next_agent()
on them later (after the hash loop).
Test case:
1. start NM and nm-applet
2. activate a Wi-Fi WPA connection
3. nm-applet displays a dialog asking for a password
4. kill nm-applet
5. NetworkManager removes the nm-applet's secret agent
and runs into removing the request from hash table in the
iterating loop (via get_complete_cb)
#0 get_complete_cb (parent=0x7f3f250f2970, secrets=0x0, agent_dbus_owner=0x0, agent_username=0x0, error=0x7f3f250f7830, user_data=0x7f3f25020e10)
at settings/nm-agent-manager.c:1111
#1 0x00007f3f23b46ea5 in req_complete_error (error=0x7f3f250f7830, req=0x7f3f250f2970) at settings/nm-agent-manager.c:509
#2 request_next_agent (req=0x7f3f250f2970) at settings/nm-agent-manager.c:615
#3 0x00007f3f23b48596 in request_remove_agent (agent=0x7f3f250f4a20, req=0x7f3f250f2970) at settings/nm-agent-manager.c:631
#4 remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:130
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
#0 0x00007f3f1fb9c4e9 in g_logv (log_domain=0x7f3f1fbfef4e "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff156b77c0) at gmessages.c:989
#1 0x00007f3f1fb9c63f in g_log (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL,
format=format@entry=0x7f3f1fc0889a "%s: assertion '%s' failed") at gmessages.c:1025
#2 0x00007f3f1fb9c679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib",
pretty_function=pretty_function@entry=0x7f3f1fc03c30 <__PRETTY_FUNCTION__.4571> "g_hash_table_iter_next",
expression=expression@entry=0x7f3f1fc038f0 "ri->version == ri->hash_table->version") at gmessages.c:1034
#3 0x00007f3f1fb849c0 in g_hash_table_iter_next (iter=<optimized out>, key=<optimized out>, value=<optimized out>) at ghash.c:733
#4 0x00007f3f23b484e5 in remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:129
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
2013-11-21 10:31:28 +01:00
|
|
|
/* Remove this agent from any in-progress secrets requests */
|
2010-12-14 15:34:34 -06:00
|
|
|
g_hash_table_iter_init (&iter, priv->requests);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, &data))
|
agents: fix removing requests from hash table while iterating it
GLib-CRITICAL **: g_hash_table_iter_next: assertion 'ri->version == ri->hash_table->version' failed
It is not allowed to modify hash table while it is iterated. Unfortunately,
request_remove_agent() may remove the request from the 'requests' hash table,
making it not usable in the loop hash table looping.
We need to store the request into a temporary list and call request_next_agent()
on them later (after the hash loop).
Test case:
1. start NM and nm-applet
2. activate a Wi-Fi WPA connection
3. nm-applet displays a dialog asking for a password
4. kill nm-applet
5. NetworkManager removes the nm-applet's secret agent
and runs into removing the request from hash table in the
iterating loop (via get_complete_cb)
#0 get_complete_cb (parent=0x7f3f250f2970, secrets=0x0, agent_dbus_owner=0x0, agent_username=0x0, error=0x7f3f250f7830, user_data=0x7f3f25020e10)
at settings/nm-agent-manager.c:1111
#1 0x00007f3f23b46ea5 in req_complete_error (error=0x7f3f250f7830, req=0x7f3f250f2970) at settings/nm-agent-manager.c:509
#2 request_next_agent (req=0x7f3f250f2970) at settings/nm-agent-manager.c:615
#3 0x00007f3f23b48596 in request_remove_agent (agent=0x7f3f250f4a20, req=0x7f3f250f2970) at settings/nm-agent-manager.c:631
#4 remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:130
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
#0 0x00007f3f1fb9c4e9 in g_logv (log_domain=0x7f3f1fbfef4e "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff156b77c0) at gmessages.c:989
#1 0x00007f3f1fb9c63f in g_log (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL,
format=format@entry=0x7f3f1fc0889a "%s: assertion '%s' failed") at gmessages.c:1025
#2 0x00007f3f1fb9c679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib",
pretty_function=pretty_function@entry=0x7f3f1fc03c30 <__PRETTY_FUNCTION__.4571> "g_hash_table_iter_next",
expression=expression@entry=0x7f3f1fc038f0 "ri->version == ri->hash_table->version") at gmessages.c:1034
#3 0x00007f3f1fb849c0 in g_hash_table_iter_next (iter=<optimized out>, key=<optimized out>, value=<optimized out>) at ghash.c:733
#4 0x00007f3f23b484e5 in remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:129
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
2013-11-21 10:31:28 +01:00
|
|
|
request_remove_agent ((Request *) data, agent, &pending_reqs);
|
|
|
|
|
|
|
|
|
|
/* We cannot call request_next_agent() from from within hash iterating loop,
|
|
|
|
|
* because it may remove the request from the hash table, which invalidates
|
|
|
|
|
* the iterator. So, only remove the agent from requests. And store the requests
|
|
|
|
|
* that should be sent to other agent to a temporary list to proceed afterwards.
|
|
|
|
|
*/
|
|
|
|
|
g_slist_free_full (pending_reqs, (GDestroyNotify) request_next_agent);
|
2010-12-10 13:32:45 -06:00
|
|
|
|
2010-12-14 15:34:34 -06:00
|
|
|
/* And dispose of the agent */
|
2010-12-10 12:38:19 -06:00
|
|
|
g_hash_table_remove (priv->agents, owner);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************/
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
validate_identifier (const char *identifier, GError **error)
|
|
|
|
|
{
|
|
|
|
|
const char *p = identifier;
|
|
|
|
|
size_t id_len;
|
|
|
|
|
|
|
|
|
|
if (!identifier) {
|
|
|
|
|
g_set_error_literal (error,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER,
|
|
|
|
|
"No identifier was given");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Length between 3 and 255 characters inclusive */
|
|
|
|
|
id_len = strlen (identifier);
|
|
|
|
|
if (id_len < 3 || id_len > 255) {
|
|
|
|
|
g_set_error_literal (error,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER,
|
|
|
|
|
"Identifier length not between 3 and 255 characters (inclusive)");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((identifier[0] == '.') || (identifier[id_len - 1] == '.')) {
|
|
|
|
|
g_set_error_literal (error,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER,
|
|
|
|
|
"Identifier must not start or end with '.'");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* FIXME: do complete validation here */
|
|
|
|
|
while (p && *p) {
|
2012-09-25 10:44:23 -04:00
|
|
|
if (!g_ascii_isalnum (*p) && (*p != '_') && (*p != '-') && (*p != '.')) {
|
2010-12-10 12:38:19 -06:00
|
|
|
g_set_error (error,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER,
|
|
|
|
|
"Identifier contains invalid character '%c'", *p);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((*p == '.') && (*(p + 1) == '.')) {
|
|
|
|
|
g_set_error_literal (error,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_INVALID_IDENTIFIER,
|
|
|
|
|
"Identifier contains two '.' characters in sequence");
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2010-12-14 11:14:24 -06:00
|
|
|
p++;
|
2010-12-10 12:38:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-01 14:34:08 -05:00
|
|
|
static void
|
|
|
|
|
agent_register_permissions_done (NMAuthChain *chain,
|
|
|
|
|
GError *error,
|
|
|
|
|
DBusGMethodInvocation *context,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManager *self = NM_AGENT_MANAGER (user_data);
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
const char *sender;
|
|
|
|
|
GError *local = NULL;
|
|
|
|
|
NMAuthCallResult result;
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
Request *req;
|
|
|
|
|
|
2013-07-29 10:40:11 -05:00
|
|
|
g_assert (context);
|
|
|
|
|
|
2011-07-01 14:34:08 -05:00
|
|
|
priv->chains = g_slist_remove (priv->chains, chain);
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
local = g_error_new (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED,
|
|
|
|
|
"Failed to request agent permissions: (%d) %s",
|
|
|
|
|
error->code, error->message);
|
|
|
|
|
dbus_g_method_return_error (context, local);
|
|
|
|
|
g_error_free (local);
|
|
|
|
|
} else {
|
|
|
|
|
agent = nm_auth_chain_steal_data (chain, "agent");
|
2012-10-08 12:52:15 -05:00
|
|
|
g_assert (agent);
|
2011-07-01 14:34:08 -05:00
|
|
|
|
|
|
|
|
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED);
|
|
|
|
|
if (result == NM_AUTH_CALL_RESULT_YES)
|
|
|
|
|
nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, TRUE);
|
|
|
|
|
|
|
|
|
|
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN);
|
|
|
|
|
if (result == NM_AUTH_CALL_RESULT_YES)
|
|
|
|
|
nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, TRUE);
|
|
|
|
|
|
|
|
|
|
sender = nm_secret_agent_get_dbus_owner (agent);
|
|
|
|
|
g_hash_table_insert (priv->agents, g_strdup (sender), agent);
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent registered",
|
|
|
|
|
nm_secret_agent_get_description (agent));
|
|
|
|
|
dbus_g_method_return (context);
|
|
|
|
|
|
|
|
|
|
/* Signal an agent was registered */
|
|
|
|
|
g_signal_emit (self, signals[AGENT_REGISTERED], 0, agent);
|
|
|
|
|
|
|
|
|
|
/* Add this agent to any in-progress secrets requests */
|
|
|
|
|
g_hash_table_iter_init (&iter, priv->requests);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &req))
|
|
|
|
|
request_add_agent (req, agent, priv->session_monitor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_auth_chain_unref (chain);
|
|
|
|
|
}
|
|
|
|
|
|
2012-12-16 11:34:07 -06:00
|
|
|
static NMSecretAgent *
|
|
|
|
|
find_agent_by_identifier_and_uid (NMAgentManager *self,
|
|
|
|
|
const char *identifier,
|
|
|
|
|
gulong sender_uid)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, priv->agents);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) {
|
|
|
|
|
if ( g_strcmp0 (nm_secret_agent_get_identifier (agent), identifier) == 0
|
|
|
|
|
&& nm_secret_agent_get_owner_uid (agent) == sender_uid)
|
|
|
|
|
return agent;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-10 12:38:19 -06:00
|
|
|
static void
|
2013-07-18 22:39:39 -05:00
|
|
|
impl_agent_manager_register_with_capabilities (NMAgentManager *self,
|
|
|
|
|
const char *identifier,
|
|
|
|
|
NMSecretAgentCapabilities capabilities,
|
|
|
|
|
DBusGMethodInvocation *context)
|
2010-12-10 12:38:19 -06:00
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
2013-07-29 10:40:11 -05:00
|
|
|
NMAuthSubject *subject;
|
2010-12-10 12:38:19 -06:00
|
|
|
gulong sender_uid = G_MAXULONG;
|
|
|
|
|
GError *error = NULL, *local = NULL;
|
|
|
|
|
NMSecretAgent *agent;
|
2011-07-01 14:34:08 -05:00
|
|
|
NMAuthChain *chain;
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2013-07-29 10:40:11 -05:00
|
|
|
subject = nm_auth_subject_new_from_context (context);
|
|
|
|
|
if (!subject) {
|
2010-12-10 12:38:19 -06:00
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
|
2012-12-15 10:48:11 -06:00
|
|
|
"Unable to determine request sender and UID.");
|
2010-12-10 12:38:19 -06:00
|
|
|
goto done;
|
|
|
|
|
}
|
2013-07-29 10:40:11 -05:00
|
|
|
sender_uid = nm_auth_subject_get_uid (subject);
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2012-12-16 11:46:06 -06:00
|
|
|
if ( 0 != sender_uid
|
|
|
|
|
&& !nm_session_monitor_uid_has_session (priv->session_monitor,
|
|
|
|
|
sender_uid,
|
|
|
|
|
NULL,
|
|
|
|
|
&local)) {
|
2010-12-10 12:38:19 -06:00
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_SESSION_NOT_FOUND,
|
|
|
|
|
local && local->message ? local->message : "Session not found");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Validate the identifier */
|
|
|
|
|
if (!validate_identifier (identifier, &error))
|
|
|
|
|
goto done;
|
|
|
|
|
|
2012-12-16 11:34:07 -06:00
|
|
|
/* Only one agent for each identifier is allowed per user */
|
|
|
|
|
if (find_agent_by_identifier_and_uid (self, identifier, sender_uid)) {
|
|
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED,
|
|
|
|
|
"An agent with this ID is already registered for this user.");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-10 12:38:19 -06:00
|
|
|
/* Success, add the new agent */
|
2013-07-29 10:40:11 -05:00
|
|
|
agent = nm_secret_agent_new (context, subject, identifier, capabilities);
|
2010-12-10 12:38:19 -06:00
|
|
|
if (!agent) {
|
|
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR,
|
|
|
|
|
"Failed to initialize the agent");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-01 14:34:08 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) requesting permissions",
|
2010-12-14 15:34:34 -06:00
|
|
|
nm_secret_agent_get_description (agent));
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2011-07-01 14:34:08 -05:00
|
|
|
/* Kick off permissions requests for this agent */
|
2013-07-29 10:40:11 -05:00
|
|
|
chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self);
|
2012-12-16 12:30:41 -06:00
|
|
|
if (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);
|
|
|
|
|
} else {
|
|
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
|
2013-07-29 10:40:11 -05:00
|
|
|
"Unable to start agent authentication.");
|
2012-12-16 12:30:41 -06:00
|
|
|
}
|
2011-06-28 15:48:12 +02:00
|
|
|
|
2010-12-10 12:38:19 -06:00
|
|
|
done:
|
|
|
|
|
if (error)
|
|
|
|
|
dbus_g_method_return_error (context, error);
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
g_clear_error (&local);
|
2013-07-29 10:40:11 -05:00
|
|
|
g_clear_object (&subject);
|
2010-12-10 12:38:19 -06:00
|
|
|
}
|
|
|
|
|
|
2013-07-18 22:39:39 -05:00
|
|
|
static void
|
|
|
|
|
impl_agent_manager_register (NMAgentManager *self,
|
|
|
|
|
const char *identifier,
|
|
|
|
|
DBusGMethodInvocation *context)
|
|
|
|
|
{
|
|
|
|
|
impl_agent_manager_register_with_capabilities (self, identifier, 0, context);
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-10 12:38:19 -06:00
|
|
|
static void
|
|
|
|
|
impl_agent_manager_unregister (NMAgentManager *self,
|
|
|
|
|
DBusGMethodInvocation *context)
|
|
|
|
|
{
|
2012-12-15 10:48:11 -06:00
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
2010-12-10 12:38:19 -06:00
|
|
|
GError *error = NULL;
|
|
|
|
|
char *sender = NULL;
|
|
|
|
|
|
2012-12-15 10:48:11 -06:00
|
|
|
if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr,
|
|
|
|
|
context,
|
|
|
|
|
&sender,
|
2013-07-25 12:01:49 -05:00
|
|
|
NULL,
|
2012-12-15 10:48:11 -06:00
|
|
|
NULL)) {
|
2010-12-10 12:38:19 -06:00
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
|
2012-12-15 10:48:11 -06:00
|
|
|
"Unable to determine request sender.");
|
2010-12-10 12:38:19 -06:00
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Found the agent, unregister and remove it */
|
|
|
|
|
if (!remove_agent (self, sender)) {
|
|
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_NOT_REGISTERED,
|
|
|
|
|
"Caller is not registered as an Agent");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
dbus_g_method_return (context);
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
if (error)
|
|
|
|
|
dbus_g_method_return_error (context, error);
|
|
|
|
|
g_clear_error (&error);
|
|
|
|
|
g_free (sender);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************/
|
|
|
|
|
|
2010-12-13 13:11:51 -06:00
|
|
|
typedef void (*RequestCompleteFunc) (Request *req,
|
|
|
|
|
GHashTable *secrets,
|
2011-02-02 12:17:58 -06:00
|
|
|
const char *agent_dbus_owner,
|
2011-03-31 18:39:09 -05:00
|
|
|
const char *agent_username,
|
2010-12-13 13:11:51 -06:00
|
|
|
GError *error,
|
|
|
|
|
gpointer user_data);
|
2013-05-21 11:45:09 -05:00
|
|
|
typedef gboolean (*RequestAddAgentFunc) (Request *req,
|
|
|
|
|
NMSecretAgent *agent,
|
|
|
|
|
NMSessionMonitor *session_monitor);
|
2011-01-31 23:10:33 -06:00
|
|
|
typedef void (*RequestNextFunc) (Request *req);
|
|
|
|
|
typedef void (*RequestCancelFunc) (Request *req);
|
2010-12-13 13:11:51 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
/* Basic secrets request structure */
|
2010-12-13 13:11:51 -06:00
|
|
|
struct _Request {
|
|
|
|
|
guint32 reqid;
|
2013-05-21 11:45:09 -05:00
|
|
|
char *detail;
|
|
|
|
|
char *verb;
|
2010-12-13 13:11:51 -06:00
|
|
|
|
2011-01-26 18:36:08 -06:00
|
|
|
gboolean filter_by_uid;
|
|
|
|
|
gulong uid_filter;
|
2010-12-13 13:11:51 -06:00
|
|
|
|
2010-12-14 15:34:34 -06:00
|
|
|
/* Current agent being asked for secrets */
|
|
|
|
|
NMSecretAgent *current;
|
2011-01-18 13:19:29 -06:00
|
|
|
gconstpointer current_call_id;
|
2010-12-14 15:34:34 -06:00
|
|
|
|
2011-02-02 12:17:58 -06:00
|
|
|
/* Stores the sorted list of NMSecretAgents which will be asked for secrets */
|
2010-12-14 15:34:34 -06:00
|
|
|
GSList *pending;
|
|
|
|
|
|
|
|
|
|
/* Stores the list of NMSecretAgent hashes that we've already
|
|
|
|
|
* asked for secrets, so that we don't ask the same agent twice
|
|
|
|
|
* if it quits and re-registers during this secrets request.
|
|
|
|
|
*/
|
|
|
|
|
GSList *asked;
|
|
|
|
|
|
2010-12-13 13:11:51 -06:00
|
|
|
guint32 idle_id;
|
|
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
RequestAddAgentFunc add_agent_callback;
|
2011-01-31 23:10:33 -06:00
|
|
|
RequestCancelFunc cancel_callback;
|
|
|
|
|
RequestNextFunc next_callback;
|
2010-12-13 13:11:51 -06:00
|
|
|
RequestCompleteFunc complete_callback;
|
2010-12-14 15:34:34 -06:00
|
|
|
gpointer complete_callback_data;
|
2013-08-30 18:21:44 +02:00
|
|
|
gboolean completed;
|
2013-05-21 11:45:09 -05:00
|
|
|
|
|
|
|
|
GDestroyNotify free_func;
|
2010-12-13 13:11:51 -06:00
|
|
|
};
|
|
|
|
|
|
2011-01-31 23:10:33 -06:00
|
|
|
static guint32 next_req_id = 1;
|
|
|
|
|
|
2010-12-13 13:11:51 -06:00
|
|
|
static Request *
|
2013-05-21 11:45:09 -05:00
|
|
|
request_new (gsize struct_size,
|
|
|
|
|
const char *detail,
|
|
|
|
|
const char *verb,
|
|
|
|
|
gboolean filter_by_uid,
|
|
|
|
|
gulong uid_filter,
|
|
|
|
|
RequestCompleteFunc complete_callback,
|
|
|
|
|
gpointer complete_callback_data,
|
|
|
|
|
RequestAddAgentFunc add_agent_callback,
|
|
|
|
|
RequestNextFunc next_callback,
|
|
|
|
|
RequestCancelFunc cancel_callback,
|
|
|
|
|
GDestroyNotify free_func)
|
2010-12-13 13:11:51 -06:00
|
|
|
{
|
|
|
|
|
Request *req;
|
|
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
req = g_malloc0 (struct_size);
|
2011-01-31 23:10:33 -06:00
|
|
|
req->reqid = next_req_id++;
|
2013-05-21 11:45:09 -05:00
|
|
|
req->detail = g_strdup (detail);
|
|
|
|
|
req->verb = g_strdup (verb);
|
2011-01-26 18:36:08 -06:00
|
|
|
req->filter_by_uid = filter_by_uid;
|
|
|
|
|
req->uid_filter = uid_filter;
|
2010-12-14 15:34:34 -06:00
|
|
|
req->complete_callback = complete_callback;
|
|
|
|
|
req->complete_callback_data = complete_callback_data;
|
2013-05-21 11:45:09 -05:00
|
|
|
req->add_agent_callback = add_agent_callback,
|
2011-01-31 23:10:33 -06:00
|
|
|
req->next_callback = next_callback;
|
|
|
|
|
req->cancel_callback = cancel_callback;
|
2013-05-21 11:45:09 -05:00
|
|
|
req->free_func = free_func;
|
2011-01-31 23:10:33 -06:00
|
|
|
return req;
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-13 13:11:51 -06:00
|
|
|
static void
|
|
|
|
|
request_free (Request *req)
|
|
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
if (req->free_func)
|
|
|
|
|
req->free_func ((gpointer) req);
|
|
|
|
|
|
2010-12-13 13:11:51 -06:00
|
|
|
if (req->idle_id)
|
|
|
|
|
g_source_remove (req->idle_id);
|
|
|
|
|
|
2013-08-30 18:21:44 +02:00
|
|
|
if (!req->completed && req->cancel_callback)
|
2013-06-26 14:11:33 -05:00
|
|
|
req->cancel_callback (req);
|
2010-12-14 15:34:34 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
g_free (req->detail);
|
|
|
|
|
g_free (req->verb);
|
agents: fix crash in nm_secret_agent_cancel_secrets() (rh #922855)
When request for getting secrets is being freed in request_free(),
cancel_callback is get_cancel_cb(). It uses parent->current as a secret agent
object. However, this object can be already freed and thus there is a problem
getting priv in nm_secret_agent_cancel_secrets:
g_return_if_fail (self != NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
(gdb) p self
$66 = (NMSecretAgent *) 0x7fae9afd42e0
(gdb) p *self
$67 = {parent = {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0}}
#0 nm_secret_agent_cancel_secrets (self=0x7fae9afd42e0, call=0x1) at settings/nm-secret-agent.c:325
#1 0x00007fae9a774882 in request_free (req=0x7fae9afc48f0) at settings/nm-agent-manager.c:496
#2 0x00007fae967b251a in g_hash_table_remove_internal (hash_table=0x7fae9aefdf00, key=0x2, notify=1) at ghash.c:1276
#3 0x00007fae9a72b340 in dispose (object=0x7fae9af77200) at nm-activation-request.c:446
#4 0x00007fae96cbeee8 in g_object_unref (_object=0x7fae9af77200) at gobject.c:3160
#5 0x00007fae9a73d87c in _active_connection_cleanup (user_data=<optimized out>) at nm-manager.c:359
#6 0x00007fae967c32a6 in g_main_dispatch (context=0x7fae9aedb180) at gmain.c:3066
#7 g_main_context_dispatch (context=context@entry=0x7fae9aedb180) at gmain.c:3642
#8 0x00007fae967c3628 in g_main_context_iterate (context=0x7fae9aedb180, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3713
#9 0x00007fae967c3a3a in g_main_loop_run (loop=0x7fae9aedb860) at gmain.c:3907
So we need to ref() 'agent' when adding it to pending list, so that the object
is not freed if the secret agent unregisters and is removed.
Test case:
1. run NM and nm-applet
2. activate a Wi-Fi network
3. nm-applet will ask for a password; ignore the popup window and kill nm-applet
4. start nm-applet again
5. click the same Wi-Fi network in nm-applet
6. NM will experience problems in nm_secret_agent_cancel_secrets() or crashes
(the procedure may not be 100%, but reproduces most of the time)
https://bugzilla.redhat.com/show_bug.cgi?id=922855
2013-11-21 13:40:04 +01:00
|
|
|
g_slist_free_full (req->pending, g_object_unref);
|
2010-12-14 15:34:34 -06:00
|
|
|
g_slist_free (req->asked);
|
2010-12-13 13:11:51 -06:00
|
|
|
memset (req, 0, sizeof (Request));
|
|
|
|
|
g_free (req);
|
|
|
|
|
}
|
|
|
|
|
|
2011-03-31 18:39:09 -05:00
|
|
|
static void
|
|
|
|
|
req_complete_success (Request *req,
|
|
|
|
|
GHashTable *secrets,
|
|
|
|
|
const char *agent_dbus_owner,
|
2013-05-21 11:45:09 -05:00
|
|
|
const char *agent_uname)
|
2011-03-31 18:39:09 -05:00
|
|
|
{
|
2013-08-30 18:21:44 +02:00
|
|
|
req->completed = TRUE;
|
2011-03-31 18:39:09 -05:00
|
|
|
req->complete_callback (req,
|
|
|
|
|
secrets,
|
|
|
|
|
agent_dbus_owner,
|
|
|
|
|
agent_uname,
|
|
|
|
|
NULL,
|
|
|
|
|
req->complete_callback_data);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
req_complete_error (Request *req, GError *error)
|
|
|
|
|
{
|
2013-08-30 18:21:44 +02:00
|
|
|
req->completed = TRUE;
|
2013-05-21 11:45:09 -05:00
|
|
|
req->complete_callback (req, NULL, NULL, NULL, error, req->complete_callback_data);
|
2011-03-31 18:39:09 -05:00
|
|
|
}
|
|
|
|
|
|
2011-01-31 23:10:33 -06:00
|
|
|
static gint
|
|
|
|
|
agent_compare_func (NMSecretAgent *a, NMSecretAgent *b, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMSessionMonitor *session_monitor = NM_SESSION_MONITOR (user_data);
|
|
|
|
|
gboolean a_active, b_active;
|
|
|
|
|
|
|
|
|
|
if (a && !b)
|
|
|
|
|
return -1;
|
|
|
|
|
else if (a == b)
|
|
|
|
|
return 0;
|
|
|
|
|
else if (!a && b)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
/* Prefer agents in active sessions */
|
|
|
|
|
a_active = nm_session_monitor_uid_active (session_monitor,
|
|
|
|
|
nm_secret_agent_get_owner_uid (a),
|
|
|
|
|
NULL);
|
|
|
|
|
b_active = nm_session_monitor_uid_active (session_monitor,
|
|
|
|
|
nm_secret_agent_get_owner_uid (b),
|
|
|
|
|
NULL);
|
|
|
|
|
if (a_active && !b_active)
|
|
|
|
|
return -1;
|
|
|
|
|
else if (a_active == b_active)
|
|
|
|
|
return 0;
|
|
|
|
|
else if (!a_active && b_active)
|
|
|
|
|
return 1;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
2010-12-14 15:34:34 -06:00
|
|
|
|
|
|
|
|
static void
|
2011-01-31 23:10:33 -06:00
|
|
|
request_add_agent (Request *req,
|
|
|
|
|
NMSecretAgent *agent,
|
|
|
|
|
NMSessionMonitor *session_monitor)
|
|
|
|
|
{
|
|
|
|
|
uid_t agent_uid;
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (req != NULL);
|
|
|
|
|
g_return_if_fail (agent != NULL);
|
|
|
|
|
|
|
|
|
|
if (g_slist_find (req->asked, GUINT_TO_POINTER (nm_secret_agent_get_hash (agent))))
|
|
|
|
|
return;
|
|
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
if (req->add_agent_callback && !req->add_agent_callback (req, agent, session_monitor))
|
2012-12-16 11:38:04 -06:00
|
|
|
return;
|
2011-01-31 23:10:33 -06:00
|
|
|
|
|
|
|
|
/* If the request should filter agents by UID, do that now */
|
2013-05-21 11:45:09 -05:00
|
|
|
agent_uid = nm_secret_agent_get_owner_uid (agent);
|
2011-01-31 23:10:33 -06:00
|
|
|
if (req->filter_by_uid && (agent_uid != req->uid_filter)) {
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s "
|
2011-03-19 12:44:14 -05:00
|
|
|
"(uid %d not required %ld)",
|
2012-12-14 17:46:34 -06:00
|
|
|
nm_secret_agent_get_description (agent),
|
2013-05-21 11:45:09 -05:00
|
|
|
req, req->detail, agent_uid, req->uid_filter);
|
2011-01-31 23:10:33 -06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent allowed for secrets request %p/%s",
|
2012-12-14 17:46:34 -06:00
|
|
|
nm_secret_agent_get_description (agent),
|
2013-05-21 11:45:09 -05:00
|
|
|
req, req->detail);
|
2011-01-31 23:10:33 -06:00
|
|
|
|
|
|
|
|
/* Add this agent to the list, preferring active sessions */
|
|
|
|
|
req->pending = g_slist_insert_sorted_with_data (req->pending,
|
agents: fix crash in nm_secret_agent_cancel_secrets() (rh #922855)
When request for getting secrets is being freed in request_free(),
cancel_callback is get_cancel_cb(). It uses parent->current as a secret agent
object. However, this object can be already freed and thus there is a problem
getting priv in nm_secret_agent_cancel_secrets:
g_return_if_fail (self != NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
(gdb) p self
$66 = (NMSecretAgent *) 0x7fae9afd42e0
(gdb) p *self
$67 = {parent = {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0}}
#0 nm_secret_agent_cancel_secrets (self=0x7fae9afd42e0, call=0x1) at settings/nm-secret-agent.c:325
#1 0x00007fae9a774882 in request_free (req=0x7fae9afc48f0) at settings/nm-agent-manager.c:496
#2 0x00007fae967b251a in g_hash_table_remove_internal (hash_table=0x7fae9aefdf00, key=0x2, notify=1) at ghash.c:1276
#3 0x00007fae9a72b340 in dispose (object=0x7fae9af77200) at nm-activation-request.c:446
#4 0x00007fae96cbeee8 in g_object_unref (_object=0x7fae9af77200) at gobject.c:3160
#5 0x00007fae9a73d87c in _active_connection_cleanup (user_data=<optimized out>) at nm-manager.c:359
#6 0x00007fae967c32a6 in g_main_dispatch (context=0x7fae9aedb180) at gmain.c:3066
#7 g_main_context_dispatch (context=context@entry=0x7fae9aedb180) at gmain.c:3642
#8 0x00007fae967c3628 in g_main_context_iterate (context=0x7fae9aedb180, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3713
#9 0x00007fae967c3a3a in g_main_loop_run (loop=0x7fae9aedb860) at gmain.c:3907
So we need to ref() 'agent' when adding it to pending list, so that the object
is not freed if the secret agent unregisters and is removed.
Test case:
1. run NM and nm-applet
2. activate a Wi-Fi network
3. nm-applet will ask for a password; ignore the popup window and kill nm-applet
4. start nm-applet again
5. click the same Wi-Fi network in nm-applet
6. NM will experience problems in nm_secret_agent_cancel_secrets() or crashes
(the procedure may not be 100%, but reproduces most of the time)
https://bugzilla.redhat.com/show_bug.cgi?id=922855
2013-11-21 13:40:04 +01:00
|
|
|
g_object_ref (agent),
|
2011-01-31 23:10:33 -06:00
|
|
|
(GCompareDataFunc) agent_compare_func,
|
|
|
|
|
session_monitor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
request_add_agents (NMAgentManager *self, Request *req)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
gpointer data;
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, priv->agents);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, &data))
|
|
|
|
|
request_add_agent (req, NM_SECRET_AGENT (data), priv->session_monitor);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-05-21 11:45:09 -05:00
|
|
|
request_next_agent (Request *req)
|
2011-01-31 23:10:33 -06:00
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
GError *error = NULL;
|
2011-01-31 23:10:33 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
if (req->pending) {
|
|
|
|
|
/* Send the request to the next agent */
|
2011-01-31 23:10:33 -06:00
|
|
|
req->current_call_id = NULL;
|
agents: fix crash in nm_secret_agent_cancel_secrets() (rh #922855)
When request for getting secrets is being freed in request_free(),
cancel_callback is get_cancel_cb(). It uses parent->current as a secret agent
object. However, this object can be already freed and thus there is a problem
getting priv in nm_secret_agent_cancel_secrets:
g_return_if_fail (self != NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
(gdb) p self
$66 = (NMSecretAgent *) 0x7fae9afd42e0
(gdb) p *self
$67 = {parent = {g_type_instance = {g_class = 0x0}, ref_count = 0, qdata = 0x0}}
#0 nm_secret_agent_cancel_secrets (self=0x7fae9afd42e0, call=0x1) at settings/nm-secret-agent.c:325
#1 0x00007fae9a774882 in request_free (req=0x7fae9afc48f0) at settings/nm-agent-manager.c:496
#2 0x00007fae967b251a in g_hash_table_remove_internal (hash_table=0x7fae9aefdf00, key=0x2, notify=1) at ghash.c:1276
#3 0x00007fae9a72b340 in dispose (object=0x7fae9af77200) at nm-activation-request.c:446
#4 0x00007fae96cbeee8 in g_object_unref (_object=0x7fae9af77200) at gobject.c:3160
#5 0x00007fae9a73d87c in _active_connection_cleanup (user_data=<optimized out>) at nm-manager.c:359
#6 0x00007fae967c32a6 in g_main_dispatch (context=0x7fae9aedb180) at gmain.c:3066
#7 g_main_context_dispatch (context=context@entry=0x7fae9aedb180) at gmain.c:3642
#8 0x00007fae967c3628 in g_main_context_iterate (context=0x7fae9aedb180, block=block@entry=1, dispatch=dispatch@entry=1, self=<optimized out>) at gmain.c:3713
#9 0x00007fae967c3a3a in g_main_loop_run (loop=0x7fae9aedb860) at gmain.c:3907
So we need to ref() 'agent' when adding it to pending list, so that the object
is not freed if the secret agent unregisters and is removed.
Test case:
1. run NM and nm-applet
2. activate a Wi-Fi network
3. nm-applet will ask for a password; ignore the popup window and kill nm-applet
4. start nm-applet again
5. click the same Wi-Fi network in nm-applet
6. NM will experience problems in nm_secret_agent_cancel_secrets() or crashes
(the procedure may not be 100%, but reproduces most of the time)
https://bugzilla.redhat.com/show_bug.cgi?id=922855
2013-11-21 13:40:04 +01:00
|
|
|
if (req->current)
|
|
|
|
|
g_object_unref (req->current);
|
2013-05-21 11:45:09 -05:00
|
|
|
req->current = req->pending->data;
|
|
|
|
|
req->pending = g_slist_remove (req->pending, req->current);
|
2011-01-31 23:10:33 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent %s secrets for request %p/%s",
|
|
|
|
|
nm_secret_agent_get_description (req->current),
|
|
|
|
|
req->verb, req, req->detail);
|
2011-01-31 23:10:33 -06:00
|
|
|
|
|
|
|
|
req->next_callback (req);
|
2013-05-21 11:45:09 -05:00
|
|
|
} else {
|
2013-06-26 14:11:33 -05:00
|
|
|
req->current_call_id = NULL;
|
|
|
|
|
req->current = NULL;
|
|
|
|
|
|
2011-01-31 23:10:33 -06:00
|
|
|
/* No more secret agents are available to fulfill this secrets request */
|
|
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_NO_SECRETS,
|
|
|
|
|
"No agents were available for this request.");
|
2011-03-31 18:39:09 -05:00
|
|
|
req_complete_error (req, error);
|
2011-01-31 23:10:33 -06:00
|
|
|
g_error_free (error);
|
|
|
|
|
}
|
2013-05-21 11:45:09 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
agents: fix removing requests from hash table while iterating it
GLib-CRITICAL **: g_hash_table_iter_next: assertion 'ri->version == ri->hash_table->version' failed
It is not allowed to modify hash table while it is iterated. Unfortunately,
request_remove_agent() may remove the request from the 'requests' hash table,
making it not usable in the loop hash table looping.
We need to store the request into a temporary list and call request_next_agent()
on them later (after the hash loop).
Test case:
1. start NM and nm-applet
2. activate a Wi-Fi WPA connection
3. nm-applet displays a dialog asking for a password
4. kill nm-applet
5. NetworkManager removes the nm-applet's secret agent
and runs into removing the request from hash table in the
iterating loop (via get_complete_cb)
#0 get_complete_cb (parent=0x7f3f250f2970, secrets=0x0, agent_dbus_owner=0x0, agent_username=0x0, error=0x7f3f250f7830, user_data=0x7f3f25020e10)
at settings/nm-agent-manager.c:1111
#1 0x00007f3f23b46ea5 in req_complete_error (error=0x7f3f250f7830, req=0x7f3f250f2970) at settings/nm-agent-manager.c:509
#2 request_next_agent (req=0x7f3f250f2970) at settings/nm-agent-manager.c:615
#3 0x00007f3f23b48596 in request_remove_agent (agent=0x7f3f250f4a20, req=0x7f3f250f2970) at settings/nm-agent-manager.c:631
#4 remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:130
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
#0 0x00007f3f1fb9c4e9 in g_logv (log_domain=0x7f3f1fbfef4e "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff156b77c0) at gmessages.c:989
#1 0x00007f3f1fb9c63f in g_log (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL,
format=format@entry=0x7f3f1fc0889a "%s: assertion '%s' failed") at gmessages.c:1025
#2 0x00007f3f1fb9c679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib",
pretty_function=pretty_function@entry=0x7f3f1fc03c30 <__PRETTY_FUNCTION__.4571> "g_hash_table_iter_next",
expression=expression@entry=0x7f3f1fc038f0 "ri->version == ri->hash_table->version") at gmessages.c:1034
#3 0x00007f3f1fb849c0 in g_hash_table_iter_next (iter=<optimized out>, key=<optimized out>, value=<optimized out>) at ghash.c:733
#4 0x00007f3f23b484e5 in remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:129
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
2013-11-21 10:31:28 +01:00
|
|
|
request_remove_agent (Request *req, NMSecretAgent *agent, GSList **pending_reqs)
|
2013-05-21 11:45:09 -05:00
|
|
|
{
|
|
|
|
|
g_return_if_fail (req != NULL);
|
|
|
|
|
g_return_if_fail (agent != NULL);
|
|
|
|
|
|
|
|
|
|
req->pending = g_slist_remove (req->pending, agent);
|
2011-01-31 23:10:33 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
if (agent == req->current) {
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) current agent removed from secrets request %p/%s",
|
|
|
|
|
nm_secret_agent_get_description (agent), req, req->detail);
|
agents: fix removing requests from hash table while iterating it
GLib-CRITICAL **: g_hash_table_iter_next: assertion 'ri->version == ri->hash_table->version' failed
It is not allowed to modify hash table while it is iterated. Unfortunately,
request_remove_agent() may remove the request from the 'requests' hash table,
making it not usable in the loop hash table looping.
We need to store the request into a temporary list and call request_next_agent()
on them later (after the hash loop).
Test case:
1. start NM and nm-applet
2. activate a Wi-Fi WPA connection
3. nm-applet displays a dialog asking for a password
4. kill nm-applet
5. NetworkManager removes the nm-applet's secret agent
and runs into removing the request from hash table in the
iterating loop (via get_complete_cb)
#0 get_complete_cb (parent=0x7f3f250f2970, secrets=0x0, agent_dbus_owner=0x0, agent_username=0x0, error=0x7f3f250f7830, user_data=0x7f3f25020e10)
at settings/nm-agent-manager.c:1111
#1 0x00007f3f23b46ea5 in req_complete_error (error=0x7f3f250f7830, req=0x7f3f250f2970) at settings/nm-agent-manager.c:509
#2 request_next_agent (req=0x7f3f250f2970) at settings/nm-agent-manager.c:615
#3 0x00007f3f23b48596 in request_remove_agent (agent=0x7f3f250f4a20, req=0x7f3f250f2970) at settings/nm-agent-manager.c:631
#4 remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:130
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
#0 0x00007f3f1fb9c4e9 in g_logv (log_domain=0x7f3f1fbfef4e "GLib", log_level=G_LOG_LEVEL_CRITICAL, format=<optimized out>, args=args@entry=0x7fff156b77c0) at gmessages.c:989
#1 0x00007f3f1fb9c63f in g_log (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib", log_level=log_level@entry=G_LOG_LEVEL_CRITICAL,
format=format@entry=0x7f3f1fc0889a "%s: assertion '%s' failed") at gmessages.c:1025
#2 0x00007f3f1fb9c679 in g_return_if_fail_warning (log_domain=log_domain@entry=0x7f3f1fbfef4e "GLib",
pretty_function=pretty_function@entry=0x7f3f1fc03c30 <__PRETTY_FUNCTION__.4571> "g_hash_table_iter_next",
expression=expression@entry=0x7f3f1fc038f0 "ri->version == ri->hash_table->version") at gmessages.c:1034
#3 0x00007f3f1fb849c0 in g_hash_table_iter_next (iter=<optimized out>, key=<optimized out>, value=<optimized out>) at ghash.c:733
#4 0x00007f3f23b484e5 in remove_agent (self=<optimized out>, owner=0x7f3f250dbff0 ":1.275") at settings/nm-agent-manager.c:129
#5 0x00007f3f23b4868d in impl_agent_manager_unregister (self=0x7f3f25020e10, context=0x7f3f250f5480) at settings/nm-agent-manager.c:374
2013-11-21 10:31:28 +01:00
|
|
|
*pending_reqs = g_slist_prepend (*pending_reqs, req);
|
2013-05-21 11:45:09 -05:00
|
|
|
} else {
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent removed from secrets request %p/%s",
|
|
|
|
|
nm_secret_agent_get_description (agent), req, req->detail);
|
|
|
|
|
}
|
2011-01-31 23:10:33 -06:00
|
|
|
}
|
|
|
|
|
|
2011-01-31 23:33:46 -06:00
|
|
|
static gboolean
|
2013-05-21 11:45:09 -05:00
|
|
|
request_start (gpointer user_data)
|
2011-01-31 23:33:46 -06:00
|
|
|
{
|
|
|
|
|
Request *req = user_data;
|
|
|
|
|
|
|
|
|
|
req->idle_id = 0;
|
2013-05-21 11:45:09 -05:00
|
|
|
request_next_agent (req);
|
2011-01-31 23:33:46 -06:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-31 23:10:33 -06:00
|
|
|
/*************************************************************/
|
|
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
/* Request subclass for connection secrets */
|
|
|
|
|
typedef struct {
|
|
|
|
|
Request parent;
|
|
|
|
|
|
|
|
|
|
NMSettingsGetSecretsFlags flags;
|
|
|
|
|
NMConnection *connection;
|
|
|
|
|
char *setting_name;
|
2013-06-19 17:51:09 -05:00
|
|
|
char **hints;
|
2013-05-21 11:45:09 -05:00
|
|
|
|
|
|
|
|
GHashTable *existing_secrets;
|
|
|
|
|
|
|
|
|
|
NMAgentSecretsResultFunc callback;
|
|
|
|
|
gpointer callback_data;
|
|
|
|
|
gpointer other_data2;
|
|
|
|
|
gpointer other_data3;
|
|
|
|
|
|
|
|
|
|
NMAuthChain *chain;
|
|
|
|
|
|
|
|
|
|
/* Whether the agent currently being asked for secrets
|
|
|
|
|
* has the system.modify privilege.
|
|
|
|
|
*/
|
|
|
|
|
gboolean current_has_modify;
|
|
|
|
|
} ConnectionRequest;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
connection_request_free (gpointer data)
|
|
|
|
|
{
|
|
|
|
|
ConnectionRequest *req = data;
|
|
|
|
|
|
|
|
|
|
g_object_unref (req->connection);
|
|
|
|
|
g_free (req->setting_name);
|
2013-06-19 17:51:09 -05:00
|
|
|
g_strfreev (req->hints);
|
2013-05-21 11:45:09 -05:00
|
|
|
if (req->existing_secrets)
|
|
|
|
|
g_hash_table_unref (req->existing_secrets);
|
|
|
|
|
if (req->chain)
|
|
|
|
|
nm_auth_chain_unref (req->chain);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
connection_request_add_agent (Request *parent,
|
|
|
|
|
NMSecretAgent *agent,
|
|
|
|
|
NMSessionMonitor *session_monitor)
|
|
|
|
|
{
|
|
|
|
|
ConnectionRequest *req = (ConnectionRequest *) parent;
|
|
|
|
|
uid_t agent_uid = nm_secret_agent_get_owner_uid (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, session_monitor, agent_uid, 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);
|
|
|
|
|
/* Connection not visible to this agent's user */
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ConnectionRequest *
|
|
|
|
|
connection_request_new_get (NMConnection *connection,
|
|
|
|
|
gboolean filter_by_uid,
|
|
|
|
|
gulong uid_filter,
|
|
|
|
|
GHashTable *existing_secrets,
|
|
|
|
|
const char *setting_name,
|
|
|
|
|
const char *verb,
|
|
|
|
|
NMSettingsGetSecretsFlags flags,
|
2013-06-19 17:51:09 -05:00
|
|
|
const char **hints,
|
2013-05-21 11:45:09 -05:00
|
|
|
NMAgentSecretsResultFunc callback,
|
|
|
|
|
gpointer callback_data,
|
|
|
|
|
gpointer other_data2,
|
|
|
|
|
gpointer other_data3,
|
|
|
|
|
RequestCompleteFunc complete_callback,
|
|
|
|
|
gpointer complete_callback_data,
|
|
|
|
|
RequestNextFunc next_callback,
|
|
|
|
|
RequestCancelFunc cancel_callback)
|
|
|
|
|
{
|
|
|
|
|
ConnectionRequest *req;
|
|
|
|
|
|
|
|
|
|
req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest),
|
|
|
|
|
nm_connection_get_id (connection),
|
|
|
|
|
verb,
|
|
|
|
|
filter_by_uid,
|
|
|
|
|
uid_filter,
|
|
|
|
|
complete_callback,
|
|
|
|
|
complete_callback_data,
|
|
|
|
|
connection_request_add_agent,
|
|
|
|
|
next_callback,
|
|
|
|
|
cancel_callback,
|
|
|
|
|
connection_request_free);
|
|
|
|
|
g_assert (req);
|
|
|
|
|
|
|
|
|
|
req->connection = g_object_ref (connection);
|
|
|
|
|
if (existing_secrets)
|
|
|
|
|
req->existing_secrets = g_hash_table_ref (existing_secrets);
|
|
|
|
|
req->setting_name = g_strdup (setting_name);
|
2013-06-19 17:51:09 -05:00
|
|
|
req->hints = g_strdupv ((char **) hints);
|
2013-05-21 11:45:09 -05:00
|
|
|
req->flags = flags;
|
|
|
|
|
req->callback = callback;
|
|
|
|
|
req->callback_data = callback_data;
|
|
|
|
|
req->other_data2 = other_data2;
|
|
|
|
|
req->other_data3 = other_data3;
|
|
|
|
|
return req;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static ConnectionRequest *
|
|
|
|
|
connection_request_new_other (NMConnection *connection,
|
|
|
|
|
gboolean filter_by_uid,
|
|
|
|
|
gulong uid_filter,
|
|
|
|
|
const char *verb,
|
|
|
|
|
RequestCompleteFunc complete_callback,
|
|
|
|
|
gpointer complete_callback_data,
|
|
|
|
|
RequestNextFunc next_callback)
|
|
|
|
|
{
|
|
|
|
|
ConnectionRequest *req;
|
|
|
|
|
|
|
|
|
|
req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest),
|
|
|
|
|
nm_connection_get_id (connection),
|
|
|
|
|
verb,
|
|
|
|
|
filter_by_uid,
|
|
|
|
|
uid_filter,
|
|
|
|
|
complete_callback,
|
|
|
|
|
complete_callback_data,
|
|
|
|
|
NULL,
|
|
|
|
|
next_callback,
|
|
|
|
|
NULL,
|
|
|
|
|
connection_request_free);
|
|
|
|
|
g_assert (req);
|
|
|
|
|
req->connection = g_object_ref (connection);
|
|
|
|
|
return req;
|
|
|
|
|
}
|
|
|
|
|
|
2011-01-31 23:10:33 -06:00
|
|
|
static void
|
|
|
|
|
get_done_cb (NMSecretAgent *agent,
|
|
|
|
|
gconstpointer call_id,
|
|
|
|
|
GHashTable *secrets,
|
|
|
|
|
GError *error,
|
|
|
|
|
gpointer user_data)
|
2010-12-14 15:34:34 -06:00
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
Request *parent = user_data;
|
|
|
|
|
ConnectionRequest *req = user_data;
|
2011-01-27 10:41:02 -06:00
|
|
|
GHashTable *setting_secrets;
|
2011-02-02 12:17:58 -06:00
|
|
|
const char *agent_dbus_owner;
|
2011-03-31 18:39:09 -05:00
|
|
|
struct passwd *pw;
|
|
|
|
|
char *agent_uname = NULL;
|
2010-12-14 15:34:34 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
g_return_if_fail (call_id == parent->current_call_id);
|
2010-12-14 15:34:34 -06:00
|
|
|
|
2011-01-18 13:19:29 -06:00
|
|
|
if (error) {
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent failed secrets request %p/%s/%s: (%d) %s",
|
2011-02-02 16:19:15 -06:00
|
|
|
nm_secret_agent_get_description (agent),
|
2013-05-21 11:45:09 -05:00
|
|
|
req, parent->detail, req->setting_name,
|
2011-02-02 16:19:15 -06:00
|
|
|
error ? error->code : -1,
|
|
|
|
|
(error && error->message) ? error->message : "(unknown)");
|
2010-12-14 15:34:34 -06:00
|
|
|
/* Try the next agent */
|
2013-05-21 11:45:09 -05:00
|
|
|
request_next_agent (parent);
|
2010-12-14 15:34:34 -06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Ensure the setting we wanted secrets for got returned and has something in it */
|
|
|
|
|
setting_secrets = g_hash_table_lookup (secrets, req->setting_name);
|
|
|
|
|
if (!setting_secrets || !g_hash_table_size (setting_secrets)) {
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent returned no secrets for request %p/%s/%s",
|
2011-02-02 16:19:15 -06:00
|
|
|
nm_secret_agent_get_description (agent),
|
2013-05-21 11:45:09 -05:00
|
|
|
req, parent->detail, req->setting_name);
|
2010-12-14 15:34:34 -06:00
|
|
|
/* Try the next agent */
|
2013-05-21 11:45:09 -05:00
|
|
|
request_next_agent (parent);
|
2010-12-14 15:34:34 -06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent returned secrets for request %p/%s/%s",
|
2011-02-02 16:19:15 -06:00
|
|
|
nm_secret_agent_get_description (agent),
|
2013-05-21 11:45:09 -05:00
|
|
|
req, parent->detail, req->setting_name);
|
2010-12-14 15:34:34 -06:00
|
|
|
|
2011-03-31 18:39:09 -05:00
|
|
|
/* Get the agent's username */
|
|
|
|
|
pw = getpwuid (nm_secret_agent_get_owner_uid (agent));
|
|
|
|
|
if (pw && strlen (pw->pw_name)) {
|
|
|
|
|
/* Needs to be UTF-8 valid since it may be pushed through D-Bus */
|
|
|
|
|
if (g_utf8_validate (pw->pw_name, -1, NULL))
|
|
|
|
|
agent_uname = g_strdup (pw->pw_name);
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-02 12:17:58 -06:00
|
|
|
agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent);
|
2013-05-21 11:45:09 -05:00
|
|
|
req_complete_success (parent, secrets, agent_dbus_owner, agent_uname);
|
2011-03-31 18:39:09 -05:00
|
|
|
g_free (agent_uname);
|
2010-12-14 15:34:34 -06:00
|
|
|
}
|
|
|
|
|
|
2011-02-07 23:45:19 -06:00
|
|
|
static void
|
|
|
|
|
set_secrets_not_required (NMConnection *connection, GHashTable *hash)
|
|
|
|
|
{
|
|
|
|
|
GHashTableIter iter, setting_iter;
|
|
|
|
|
const char *setting_name = NULL;
|
|
|
|
|
GHashTable *setting_hash = NULL;
|
|
|
|
|
|
|
|
|
|
/* Iterate through the settings hashes */
|
|
|
|
|
g_hash_table_iter_init (&iter, hash);
|
|
|
|
|
while (g_hash_table_iter_next (&iter,
|
|
|
|
|
(gpointer *) &setting_name,
|
|
|
|
|
(gpointer *) &setting_hash)) {
|
|
|
|
|
const char *key_name = NULL;
|
|
|
|
|
NMSetting *setting;
|
2011-02-10 11:36:00 -06:00
|
|
|
GValue *val;
|
2011-02-07 23:45:19 -06:00
|
|
|
|
|
|
|
|
setting = nm_connection_get_setting_by_name (connection, setting_name);
|
|
|
|
|
if (setting) {
|
|
|
|
|
/* Now through each secret in the setting and mark it as not required */
|
|
|
|
|
g_hash_table_iter_init (&setting_iter, setting_hash);
|
2011-02-10 11:36:00 -06:00
|
|
|
while (g_hash_table_iter_next (&setting_iter, (gpointer *) &key_name, (gpointer *) &val)) {
|
|
|
|
|
/* For each secret, set the flag that it's not required; VPN
|
|
|
|
|
* secrets need slightly different treatment here since the
|
|
|
|
|
* "secrets" property is actually a hash table of secrets.
|
|
|
|
|
*/
|
|
|
|
|
if ( strcmp (setting_name, NM_SETTING_VPN_SETTING_NAME) == 0
|
|
|
|
|
&& strcmp (key_name, NM_SETTING_VPN_SECRETS) == 0
|
|
|
|
|
&& G_VALUE_HOLDS (val, DBUS_TYPE_G_MAP_OF_STRING)) {
|
|
|
|
|
GHashTableIter vpn_secret_iter;
|
|
|
|
|
const char *secret_name;
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&vpn_secret_iter, g_value_get_boxed (val));
|
|
|
|
|
while (g_hash_table_iter_next (&vpn_secret_iter, (gpointer *) &secret_name, NULL))
|
|
|
|
|
nm_setting_set_secret_flags (setting, secret_name, NM_SETTING_SECRET_FLAG_NOT_REQUIRED, NULL);
|
|
|
|
|
} else
|
|
|
|
|
nm_setting_set_secret_flags (setting, key_name, NM_SETTING_SECRET_FLAG_NOT_REQUIRED, NULL);
|
|
|
|
|
}
|
2011-02-07 23:45:19 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-13 13:11:51 -06:00
|
|
|
static void
|
2013-05-21 11:45:09 -05:00
|
|
|
get_agent_request_secrets (ConnectionRequest *req, gboolean include_system_secrets)
|
2010-12-13 13:11:51 -06:00
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
Request *parent = (Request *) req;
|
2011-02-02 16:19:15 -06:00
|
|
|
NMConnection *tmp;
|
|
|
|
|
|
|
|
|
|
tmp = nm_connection_duplicate (req->connection);
|
|
|
|
|
nm_connection_clear_secrets (tmp);
|
2011-03-16 20:53:13 -05:00
|
|
|
if (include_system_secrets) {
|
|
|
|
|
if (req->existing_secrets)
|
2013-10-31 14:13:33 +01:00
|
|
|
(void) nm_connection_update_secrets (tmp, req->setting_name, req->existing_secrets, NULL);
|
2011-03-16 20:53:13 -05:00
|
|
|
} else {
|
2011-02-07 23:45:19 -06:00
|
|
|
/* Update secret flags in the temporary connection to indicate that
|
|
|
|
|
* the system secrets we're not sending to the agent aren't required,
|
|
|
|
|
* so the agent can properly validate UI controls and such.
|
|
|
|
|
*/
|
2011-02-11 17:11:58 -06:00
|
|
|
if (req->existing_secrets)
|
|
|
|
|
set_secrets_not_required (tmp, req->existing_secrets);
|
2011-02-07 23:45:19 -06:00
|
|
|
}
|
2010-12-14 15:34:34 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
parent->current_call_id = nm_secret_agent_get_secrets (parent->current,
|
|
|
|
|
tmp,
|
|
|
|
|
req->setting_name,
|
2013-06-19 17:51:09 -05:00
|
|
|
(const char **) req->hints,
|
2013-05-21 11:45:09 -05:00
|
|
|
req->flags,
|
|
|
|
|
get_done_cb,
|
|
|
|
|
req);
|
|
|
|
|
if (parent->current_call_id == NULL) {
|
2010-12-14 15:34:34 -06:00
|
|
|
/* Shouldn't hit this, but handle it anyway */
|
2013-05-21 11:45:09 -05:00
|
|
|
g_warn_if_fail (parent->current_call_id != NULL);
|
|
|
|
|
request_next_agent (parent);
|
2010-12-14 15:34:34 -06:00
|
|
|
}
|
2011-02-02 16:19:15 -06:00
|
|
|
|
|
|
|
|
g_object_unref (tmp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_agent_modify_auth_cb (NMAuthChain *chain,
|
|
|
|
|
GError *error,
|
|
|
|
|
DBusGMethodInvocation *context,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
Request *parent = user_data;
|
|
|
|
|
ConnectionRequest *req = user_data;
|
2011-02-11 17:06:57 -06:00
|
|
|
const char *perm;
|
2011-02-02 16:19:15 -06:00
|
|
|
|
|
|
|
|
req->chain = NULL;
|
|
|
|
|
|
|
|
|
|
if (error) {
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent %p/%s/%s MODIFY check error: (%d) %s",
|
|
|
|
|
nm_secret_agent_get_description (parent->current),
|
|
|
|
|
req, parent->detail, req->setting_name,
|
2011-02-02 16:19:15 -06:00
|
|
|
error->code, error->message ? error->message : "(unknown)");
|
|
|
|
|
/* Try the next agent */
|
2013-05-21 11:45:09 -05:00
|
|
|
request_next_agent (parent);
|
2011-02-02 16:19:15 -06:00
|
|
|
} else {
|
|
|
|
|
/* If the agent obtained the 'modify' permission, we send all system secrets
|
|
|
|
|
* to it. If it didn't, we still ask it for secrets, but we don't send
|
|
|
|
|
* any system secrets.
|
|
|
|
|
*/
|
2011-02-11 17:06:57 -06:00
|
|
|
perm = nm_auth_chain_get_data (chain, "perm");
|
|
|
|
|
g_assert (perm);
|
2012-10-08 12:52:15 -05:00
|
|
|
if (nm_auth_chain_get_result (chain, perm) == NM_AUTH_CALL_RESULT_YES)
|
2011-02-02 16:19:15 -06:00
|
|
|
req->current_has_modify = TRUE;
|
|
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent %p/%s/%s MODIFY check result %s",
|
|
|
|
|
nm_secret_agent_get_description (parent->current),
|
|
|
|
|
req, parent->detail, req->setting_name,
|
|
|
|
|
req->current_has_modify ? "YES" : "NO");
|
2011-02-02 16:19:15 -06:00
|
|
|
|
|
|
|
|
get_agent_request_secrets (req, req->current_has_modify);
|
|
|
|
|
}
|
2012-10-08 12:52:15 -05:00
|
|
|
|
2011-02-11 17:06:57 -06:00
|
|
|
nm_auth_chain_unref (chain);
|
2011-02-02 16:19:15 -06:00
|
|
|
}
|
|
|
|
|
|
2011-02-11 17:49:27 -06:00
|
|
|
static void
|
|
|
|
|
check_system_secrets_cb (NMSetting *setting,
|
|
|
|
|
const char *key,
|
|
|
|
|
const GValue *value,
|
|
|
|
|
GParamFlags flags,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
|
gboolean *has_system = user_data;
|
|
|
|
|
|
|
|
|
|
if (!(flags & NM_SETTING_PARAM_SECRET))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Clear out system-owned or always-ask secrets */
|
|
|
|
|
if (NM_IS_SETTING_VPN (setting) && !strcmp (key, NM_SETTING_VPN_SECRETS)) {
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
const char *secret_name = NULL;
|
|
|
|
|
|
|
|
|
|
/* VPNs are special; need to handle each secret separately */
|
|
|
|
|
g_hash_table_iter_init (&iter, (GHashTable *) g_value_get_boxed (value));
|
|
|
|
|
while (g_hash_table_iter_next (&iter, (gpointer *) &secret_name, NULL)) {
|
2011-05-23 13:45:51 -05:00
|
|
|
secret_flags = NM_SETTING_SECRET_FLAG_NONE;
|
|
|
|
|
nm_setting_get_secret_flags (setting, secret_name, &secret_flags, NULL);
|
|
|
|
|
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE)
|
|
|
|
|
*has_system = TRUE;
|
2011-02-11 17:49:27 -06:00
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
nm_setting_get_secret_flags (setting, key, &secret_flags, NULL);
|
|
|
|
|
if (secret_flags == NM_SETTING_SECRET_FLAG_NONE)
|
|
|
|
|
*has_system = TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
has_system_secrets (NMConnection *connection)
|
|
|
|
|
{
|
|
|
|
|
gboolean has_system = FALSE;
|
|
|
|
|
|
|
|
|
|
nm_connection_for_each_setting_value (connection, check_system_secrets_cb, &has_system);
|
|
|
|
|
return has_system;
|
|
|
|
|
}
|
|
|
|
|
|
2011-02-02 16:19:15 -06:00
|
|
|
static void
|
2013-05-21 11:45:09 -05:00
|
|
|
get_next_cb (Request *parent)
|
2011-02-02 16:19:15 -06:00
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
ConnectionRequest *req = (ConnectionRequest *) parent;
|
2011-02-11 17:06:57 -06:00
|
|
|
NMSettingConnection *s_con;
|
|
|
|
|
const char *agent_dbus_owner, *perm;
|
2011-02-02 16:19:15 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
req->current_has_modify = FALSE;
|
2011-02-02 16:19:15 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
agent_dbus_owner = nm_secret_agent_get_dbus_owner (parent->current);
|
2011-02-02 16:19:15 -06:00
|
|
|
|
2011-02-11 17:49:27 -06:00
|
|
|
/* If the request flags allow user interaction, and there are existing
|
|
|
|
|
* system secrets (or blank secrets that are supposed to be system-owned),
|
2011-02-07 13:58:05 -06:00
|
|
|
* check whether the agent has the 'modify' permission before sending those
|
|
|
|
|
* secrets to the agent. We shouldn't leak system-owned secrets to
|
|
|
|
|
* unprivileged users.
|
|
|
|
|
*/
|
2011-03-29 22:53:22 -05:00
|
|
|
if ( (req->flags != NM_SETTINGS_GET_SECRETS_FLAG_NONE)
|
|
|
|
|
&& (req->existing_secrets || has_system_secrets (req->connection))) {
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) request has system secrets; checking agent %s for MODIFY",
|
|
|
|
|
req, parent->detail, req->setting_name, agent_dbus_owner);
|
2011-02-07 13:58:05 -06:00
|
|
|
|
2013-07-29 10:40:11 -05:00
|
|
|
req->chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (parent->current),
|
|
|
|
|
NULL,
|
|
|
|
|
get_agent_modify_auth_cb,
|
|
|
|
|
req);
|
2011-02-07 13:58:05 -06:00
|
|
|
g_assert (req->chain);
|
2011-02-11 17:06:57 -06:00
|
|
|
|
|
|
|
|
/* 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'.
|
|
|
|
|
*/
|
2011-12-05 12:27:47 +01:00
|
|
|
s_con = nm_connection_get_setting_connection (req->connection);
|
2011-02-11 17:06:57 -06:00
|
|
|
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);
|
2011-02-07 13:58:05 -06:00
|
|
|
} else {
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) requesting user-owned secrets from agent %s",
|
|
|
|
|
req, parent->detail, req->setting_name, agent_dbus_owner);
|
2011-02-02 16:19:15 -06:00
|
|
|
|
2011-02-07 13:58:05 -06:00
|
|
|
get_agent_request_secrets (req, FALSE);
|
2011-02-02 16:19:15 -06:00
|
|
|
}
|
2010-12-13 13:11:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2011-01-31 23:10:33 -06:00
|
|
|
get_start (gpointer user_data)
|
2010-12-13 13:11:51 -06:00
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
Request *parent = user_data;
|
|
|
|
|
ConnectionRequest *req = user_data;
|
2011-01-27 10:41:02 -06:00
|
|
|
GHashTable *setting_secrets = NULL;
|
2010-12-13 13:11:51 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
parent->idle_id = 0;
|
2010-12-13 13:11:51 -06:00
|
|
|
|
2011-01-27 10:41:02 -06:00
|
|
|
/* Check if there are any existing secrets */
|
|
|
|
|
if (req->existing_secrets)
|
|
|
|
|
setting_secrets = g_hash_table_lookup (req->existing_secrets, req->setting_name);
|
2010-12-22 15:12:12 -06:00
|
|
|
|
|
|
|
|
if (setting_secrets && g_hash_table_size (setting_secrets)) {
|
|
|
|
|
NMConnection *tmp;
|
2011-01-27 10:41:02 -06:00
|
|
|
GError *error = NULL;
|
2013-05-21 11:45:09 -05:00
|
|
|
gboolean new_secrets = (req->flags & NM_SETTINGS_GET_SECRETS_FLAG_REQUEST_NEW);
|
2010-12-22 15:12:12 -06:00
|
|
|
|
|
|
|
|
/* The connection already had secrets; check if any more are required.
|
|
|
|
|
* If no more are required, we're done. If secrets are still needed,
|
|
|
|
|
* ask a secret agent for more. This allows admins to provide generic
|
|
|
|
|
* secrets but allow additional user-specific ones as well.
|
|
|
|
|
*/
|
|
|
|
|
tmp = nm_connection_duplicate (req->connection);
|
|
|
|
|
g_assert (tmp);
|
|
|
|
|
|
2011-01-27 10:41:02 -06:00
|
|
|
if (!nm_connection_update_secrets (tmp, req->setting_name, req->existing_secrets, &error)) {
|
2013-05-21 11:45:09 -05:00
|
|
|
req_complete_error (parent, error);
|
2010-12-22 15:12:12 -06:00
|
|
|
g_clear_error (&error);
|
|
|
|
|
} else {
|
|
|
|
|
/* Do we have everything we need? */
|
2011-06-15 12:15:52 -05:00
|
|
|
if ( (req->flags & NM_SETTINGS_GET_SECRETS_FLAG_ONLY_SYSTEM)
|
2013-05-21 11:45:09 -05:00
|
|
|
|| ((nm_connection_need_secrets (tmp, NULL) == NULL) && (new_secrets == FALSE))) {
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) system settings secrets sufficient",
|
|
|
|
|
req, parent->detail, req->setting_name);
|
2011-01-19 16:58:26 -06:00
|
|
|
|
2010-12-22 15:12:12 -06:00
|
|
|
/* Got everything, we're done */
|
2013-05-21 11:45:09 -05:00
|
|
|
req_complete_success (parent, req->existing_secrets, NULL, NULL);
|
2010-12-22 15:12:12 -06:00
|
|
|
} else {
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) system settings secrets insufficient, asking agents",
|
|
|
|
|
req, parent->detail, req->setting_name);
|
2011-01-19 16:58:26 -06:00
|
|
|
|
2010-12-22 15:12:12 -06:00
|
|
|
/* We don't, so ask some agents for additional secrets */
|
2013-05-21 11:45:09 -05:00
|
|
|
request_next_agent (parent);
|
2010-12-22 15:12:12 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
g_object_unref (tmp);
|
2010-12-14 15:34:34 -06:00
|
|
|
} else {
|
2010-12-13 13:11:51 -06:00
|
|
|
/* Couldn't get secrets from system settings, so now we ask the
|
|
|
|
|
* agents for secrets. Let the Agent Manager handle which agents
|
|
|
|
|
* we'll ask and in which order.
|
|
|
|
|
*/
|
2013-05-21 11:45:09 -05:00
|
|
|
request_next_agent (parent);
|
2010-12-13 13:11:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-05-21 11:45:09 -05:00
|
|
|
get_complete_cb (Request *parent,
|
2011-01-31 23:10:33 -06:00
|
|
|
GHashTable *secrets,
|
2011-02-02 12:17:58 -06:00
|
|
|
const char *agent_dbus_owner,
|
2011-03-31 18:39:09 -05:00
|
|
|
const char *agent_username,
|
2011-01-31 23:10:33 -06:00
|
|
|
GError *error,
|
|
|
|
|
gpointer user_data)
|
2010-12-13 13:11:51 -06:00
|
|
|
{
|
|
|
|
|
NMAgentManager *self = NM_AGENT_MANAGER (user_data);
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
2013-05-21 11:45:09 -05:00
|
|
|
ConnectionRequest *req = (ConnectionRequest *) parent;
|
2010-12-13 13:11:51 -06:00
|
|
|
|
2011-01-27 10:41:02 -06:00
|
|
|
/* Send secrets back to the requesting object */
|
2010-12-13 13:11:51 -06:00
|
|
|
req->callback (self,
|
2013-05-21 11:45:09 -05:00
|
|
|
parent->reqid,
|
2011-02-02 12:17:58 -06:00
|
|
|
agent_dbus_owner,
|
2011-03-31 18:39:09 -05:00
|
|
|
agent_username,
|
2013-05-21 11:45:09 -05:00
|
|
|
req->current_has_modify,
|
2011-01-26 13:32:25 -06:00
|
|
|
req->setting_name,
|
2011-02-02 12:17:58 -06:00
|
|
|
req->flags,
|
2011-01-27 10:41:02 -06:00
|
|
|
error ? NULL : secrets,
|
|
|
|
|
error,
|
2010-12-13 13:11:51 -06:00
|
|
|
req->callback_data,
|
|
|
|
|
req->other_data2,
|
|
|
|
|
req->other_data3);
|
|
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
g_hash_table_remove (priv->requests, GUINT_TO_POINTER (parent->reqid));
|
2010-12-13 13:11:51 -06:00
|
|
|
}
|
|
|
|
|
|
2011-01-31 23:10:33 -06:00
|
|
|
static void
|
2013-05-21 11:45:09 -05:00
|
|
|
get_cancel_cb (Request *parent)
|
2011-01-31 23:10:33 -06:00
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
ConnectionRequest *req = (ConnectionRequest *) parent;
|
|
|
|
|
|
|
|
|
|
req->current_has_modify = FALSE;
|
|
|
|
|
if (parent->current && parent->current_call_id)
|
|
|
|
|
nm_secret_agent_cancel_secrets (parent->current, parent->current_call_id);
|
2011-01-31 23:10:33 -06:00
|
|
|
}
|
|
|
|
|
|
2010-12-13 13:11:51 -06:00
|
|
|
guint32
|
|
|
|
|
nm_agent_manager_get_secrets (NMAgentManager *self,
|
|
|
|
|
NMConnection *connection,
|
2011-01-26 18:36:08 -06:00
|
|
|
gboolean filter_by_uid,
|
|
|
|
|
gulong uid_filter,
|
2011-01-27 10:41:02 -06:00
|
|
|
GHashTable *existing_secrets,
|
2010-12-13 13:11:51 -06:00
|
|
|
const char *setting_name,
|
2011-03-29 22:53:22 -05:00
|
|
|
NMSettingsGetSecretsFlags flags,
|
2013-06-19 17:51:09 -05:00
|
|
|
const char **hints,
|
2010-12-13 13:11:51 -06:00
|
|
|
NMAgentSecretsResultFunc callback,
|
|
|
|
|
gpointer callback_data,
|
|
|
|
|
gpointer other_data2,
|
|
|
|
|
gpointer other_data3)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
2013-05-21 11:45:09 -05:00
|
|
|
Request *parent;
|
|
|
|
|
ConnectionRequest *req;
|
2010-12-13 13:11:51 -06:00
|
|
|
|
|
|
|
|
g_return_val_if_fail (self != NULL, 0);
|
2011-01-27 10:41:02 -06:00
|
|
|
g_return_val_if_fail (NM_IS_CONNECTION (connection), 0);
|
2010-12-13 13:11:51 -06:00
|
|
|
g_return_val_if_fail (callback != NULL, 0);
|
|
|
|
|
|
2010-12-14 15:34:34 -06:00
|
|
|
nm_log_dbg (LOGD_SETTINGS,
|
2013-05-21 11:45:09 -05:00
|
|
|
"Secrets requested for connection %s (%s/%s)",
|
2010-12-14 15:34:34 -06:00
|
|
|
nm_connection_get_path (connection),
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_connection_get_id (connection),
|
2010-12-14 15:34:34 -06:00
|
|
|
setting_name);
|
|
|
|
|
|
2011-02-07 13:58:05 -06:00
|
|
|
/* NOTE: a few things in the Request handling depend on existing_secrets
|
|
|
|
|
* being NULL if there aren't any system-owned secrets for this connection.
|
|
|
|
|
* This in turn depends on nm_connection_to_hash() and nm_setting_to_hash()
|
|
|
|
|
* both returning NULL if they didn't hash anything.
|
|
|
|
|
*/
|
|
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
req = connection_request_new_get (connection,
|
|
|
|
|
filter_by_uid,
|
|
|
|
|
uid_filter,
|
|
|
|
|
existing_secrets,
|
|
|
|
|
setting_name,
|
|
|
|
|
"getting",
|
|
|
|
|
flags,
|
2013-06-19 17:51:09 -05:00
|
|
|
hints,
|
2013-05-21 11:45:09 -05:00
|
|
|
callback,
|
|
|
|
|
callback_data,
|
|
|
|
|
other_data2,
|
|
|
|
|
other_data3,
|
|
|
|
|
get_complete_cb,
|
|
|
|
|
self,
|
|
|
|
|
get_next_cb,
|
|
|
|
|
get_cancel_cb);
|
|
|
|
|
parent = (Request *) req;
|
|
|
|
|
g_hash_table_insert (priv->requests, GUINT_TO_POINTER (parent->reqid), req);
|
2010-12-13 13:11:51 -06:00
|
|
|
|
2011-01-31 23:10:33 -06:00
|
|
|
/* Kick off the request */
|
2011-06-15 12:15:52 -05:00
|
|
|
if (!(req->flags & NM_SETTINGS_GET_SECRETS_FLAG_ONLY_SYSTEM))
|
2013-05-21 11:45:09 -05:00
|
|
|
request_add_agents (self, parent);
|
|
|
|
|
parent->idle_id = g_idle_add (get_start, req);
|
|
|
|
|
return parent->reqid;
|
2010-12-13 13:11:51 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
|
nm_agent_manager_cancel_secrets (NMAgentManager *self,
|
|
|
|
|
guint32 request_id)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (self != NULL);
|
|
|
|
|
g_return_if_fail (request_id > 0);
|
|
|
|
|
|
|
|
|
|
g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (self)->requests,
|
|
|
|
|
GUINT_TO_POINTER (request_id));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************/
|
|
|
|
|
|
2011-01-31 23:10:33 -06:00
|
|
|
static void
|
|
|
|
|
save_done_cb (NMSecretAgent *agent,
|
|
|
|
|
gconstpointer call_id,
|
|
|
|
|
GHashTable *secrets,
|
|
|
|
|
GError *error,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
Request *parent = user_data;
|
|
|
|
|
ConnectionRequest *req = user_data;
|
2011-02-02 12:17:58 -06:00
|
|
|
const char *agent_dbus_owner;
|
2011-01-31 23:10:33 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
g_return_if_fail (call_id == parent->current_call_id);
|
2011-01-31 23:10:33 -06:00
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent failed save secrets request %p/%s: (%d) %s",
|
2011-02-02 16:19:15 -06:00
|
|
|
nm_secret_agent_get_description (agent),
|
2013-05-21 11:45:09 -05:00
|
|
|
req, parent->detail,
|
2011-02-02 16:19:15 -06:00
|
|
|
error ? error->code : -1,
|
|
|
|
|
(error && error->message) ? error->message : "(unknown)");
|
2011-01-31 23:10:33 -06:00
|
|
|
/* Try the next agent */
|
2013-05-21 11:45:09 -05:00
|
|
|
request_next_agent (parent);
|
2011-01-31 23:10:33 -06:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent saved secrets for request %p/%s",
|
2011-02-02 16:19:15 -06:00
|
|
|
nm_secret_agent_get_description (agent),
|
2013-05-21 11:45:09 -05:00
|
|
|
req, parent->detail);
|
2011-01-31 23:10:33 -06:00
|
|
|
|
2011-02-02 12:17:58 -06:00
|
|
|
agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent);
|
2013-05-21 11:45:09 -05:00
|
|
|
req_complete_success (parent, NULL, NULL, agent_dbus_owner);
|
2011-01-31 23:10:33 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-05-21 11:45:09 -05:00
|
|
|
save_next_cb (Request *parent)
|
2011-01-31 23:10:33 -06:00
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
ConnectionRequest *req = (ConnectionRequest *) parent;
|
2011-01-31 23:10:33 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
parent->current_call_id = nm_secret_agent_save_secrets (parent->current,
|
|
|
|
|
req->connection,
|
|
|
|
|
save_done_cb,
|
|
|
|
|
req);
|
|
|
|
|
if (parent->current_call_id == NULL) {
|
2011-01-31 23:10:33 -06:00
|
|
|
/* Shouldn't hit this, but handle it anyway */
|
2013-05-21 11:45:09 -05:00
|
|
|
g_warn_if_fail (parent->current_call_id != NULL);
|
|
|
|
|
request_next_agent (parent);
|
2011-01-31 23:10:33 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
save_complete_cb (Request *req,
|
|
|
|
|
GHashTable *secrets,
|
2011-02-02 12:17:58 -06:00
|
|
|
const char *agent_dbus_owner,
|
2011-03-31 18:39:09 -05:00
|
|
|
const char *agent_username,
|
2011-01-31 23:10:33 -06:00
|
|
|
GError *error,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (user_data)->requests,
|
|
|
|
|
GUINT_TO_POINTER (req->reqid));
|
2011-01-31 23:10:33 -06:00
|
|
|
}
|
|
|
|
|
|
2011-01-31 23:33:46 -06:00
|
|
|
guint32
|
|
|
|
|
nm_agent_manager_save_secrets (NMAgentManager *self,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
gboolean filter_by_uid,
|
|
|
|
|
gulong uid_filter)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
2013-05-21 11:45:09 -05:00
|
|
|
ConnectionRequest *req;
|
|
|
|
|
Request *parent;
|
2011-01-31 23:33:46 -06:00
|
|
|
|
|
|
|
|
g_return_val_if_fail (self != NULL, 0);
|
|
|
|
|
g_return_val_if_fail (NM_IS_CONNECTION (connection), 0);
|
|
|
|
|
|
|
|
|
|
nm_log_dbg (LOGD_SETTINGS,
|
2013-05-21 11:45:09 -05:00
|
|
|
"Saving secrets for connection %s (%s)",
|
|
|
|
|
nm_connection_get_path (connection),
|
|
|
|
|
nm_connection_get_id (connection));
|
|
|
|
|
|
|
|
|
|
req = connection_request_new_other (connection,
|
|
|
|
|
filter_by_uid,
|
|
|
|
|
uid_filter,
|
|
|
|
|
"saving",
|
|
|
|
|
save_complete_cb,
|
|
|
|
|
self,
|
|
|
|
|
save_next_cb);
|
|
|
|
|
parent = (Request *) req;
|
|
|
|
|
g_hash_table_insert (priv->requests, GUINT_TO_POINTER (parent->reqid), req);
|
2011-01-31 23:33:46 -06:00
|
|
|
|
|
|
|
|
/* Kick off the request */
|
2013-05-21 11:45:09 -05:00
|
|
|
request_add_agents (self, parent);
|
|
|
|
|
parent->idle_id = g_idle_add (request_start, req);
|
|
|
|
|
return parent->reqid;
|
2011-01-31 23:33:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
delete_done_cb (NMSecretAgent *agent,
|
|
|
|
|
gconstpointer call_id,
|
|
|
|
|
GHashTable *secrets,
|
|
|
|
|
GError *error,
|
|
|
|
|
gpointer user_data)
|
2011-01-31 23:10:33 -06:00
|
|
|
{
|
|
|
|
|
Request *req = user_data;
|
|
|
|
|
|
2011-01-31 23:33:46 -06:00
|
|
|
g_return_if_fail (call_id == req->current_call_id);
|
|
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent failed delete secrets request %p/%s: (%d) %s",
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_secret_agent_get_description (agent), req, req->detail,
|
2011-02-02 16:19:15 -06:00
|
|
|
error ? error->code : -1,
|
|
|
|
|
(error && error->message) ? error->message : "(unknown)");
|
2011-01-31 23:33:46 -06:00
|
|
|
} else {
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) agent deleted secrets for request %p/%s",
|
2013-05-21 11:45:09 -05:00
|
|
|
nm_secret_agent_get_description (agent), req, req->detail);
|
2011-01-31 23:33:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Tell the next agent to delete secrets */
|
2013-05-21 11:45:09 -05:00
|
|
|
request_next_agent (req);
|
2011-01-31 23:33:46 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2013-05-21 11:45:09 -05:00
|
|
|
delete_next_cb (Request *parent)
|
2011-01-31 23:33:46 -06:00
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
ConnectionRequest *req = (ConnectionRequest *) parent;
|
2011-01-31 23:33:46 -06:00
|
|
|
|
2013-05-21 11:45:09 -05:00
|
|
|
parent->current_call_id = nm_secret_agent_delete_secrets (parent->current,
|
|
|
|
|
req->connection,
|
|
|
|
|
delete_done_cb,
|
|
|
|
|
req);
|
|
|
|
|
if (parent->current_call_id == NULL) {
|
2011-01-31 23:33:46 -06:00
|
|
|
/* Shouldn't hit this, but handle it anyway */
|
2013-05-21 11:45:09 -05:00
|
|
|
g_warn_if_fail (parent->current_call_id != NULL);
|
|
|
|
|
request_next_agent (parent);
|
2011-01-31 23:33:46 -06:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
delete_complete_cb (Request *req,
|
|
|
|
|
GHashTable *secrets,
|
2011-02-02 12:17:58 -06:00
|
|
|
const char *agent_dbus_owner,
|
2011-03-31 18:39:09 -05:00
|
|
|
const char *agent_username,
|
2011-01-31 23:33:46 -06:00
|
|
|
GError *error,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
2013-05-21 11:45:09 -05:00
|
|
|
g_hash_table_remove (NM_AGENT_MANAGER_GET_PRIVATE (user_data)->requests,
|
|
|
|
|
GUINT_TO_POINTER (req->reqid));
|
2011-01-31 23:10:33 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
guint32
|
2011-01-31 23:33:46 -06:00
|
|
|
nm_agent_manager_delete_secrets (NMAgentManager *self,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
gboolean filter_by_uid,
|
|
|
|
|
gulong uid_filter)
|
2011-01-31 23:10:33 -06:00
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
2013-05-21 11:45:09 -05:00
|
|
|
ConnectionRequest *req;
|
|
|
|
|
Request *parent;
|
2011-01-31 23:10:33 -06:00
|
|
|
|
|
|
|
|
g_return_val_if_fail (self != NULL, 0);
|
|
|
|
|
g_return_val_if_fail (NM_IS_CONNECTION (connection), 0);
|
|
|
|
|
|
|
|
|
|
nm_log_dbg (LOGD_SETTINGS,
|
2013-05-21 11:45:09 -05:00
|
|
|
"Deleting secrets for connection %s (%s)",
|
|
|
|
|
nm_connection_get_path (connection),
|
|
|
|
|
nm_connection_get_id (connection));
|
|
|
|
|
|
|
|
|
|
req = connection_request_new_other (connection,
|
|
|
|
|
filter_by_uid,
|
|
|
|
|
uid_filter,
|
|
|
|
|
"deleting",
|
|
|
|
|
delete_complete_cb,
|
|
|
|
|
self,
|
|
|
|
|
delete_next_cb);
|
|
|
|
|
parent = (Request *) req;
|
|
|
|
|
g_hash_table_insert (priv->requests, GUINT_TO_POINTER (parent->reqid), req);
|
2011-01-31 23:10:33 -06:00
|
|
|
|
|
|
|
|
/* Kick off the request */
|
2013-05-21 11:45:09 -05:00
|
|
|
request_add_agents (self, parent);
|
|
|
|
|
parent->idle_id = g_idle_add (request_start, req);
|
|
|
|
|
return parent->reqid;
|
2011-01-31 23:10:33 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************/
|
|
|
|
|
|
2011-07-01 14:36:01 -05:00
|
|
|
NMSecretAgent *
|
|
|
|
|
nm_agent_manager_get_agent_by_user (NMAgentManager *self, const char *username)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, priv->agents);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) {
|
|
|
|
|
if (g_strcmp0 (nm_secret_agent_get_owner_username (agent), username) == 0)
|
|
|
|
|
return agent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************/
|
|
|
|
|
|
2013-06-20 23:07:49 -05:00
|
|
|
gboolean
|
|
|
|
|
nm_agent_manager_all_agents_have_capability (NMAgentManager *manager,
|
|
|
|
|
gboolean filter_by_uid,
|
|
|
|
|
gulong owner_uid,
|
|
|
|
|
NMSecretAgentCapabilities capability)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (manager);
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, priv->agents);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) {
|
|
|
|
|
if (filter_by_uid && nm_secret_agent_get_owner_uid (agent) != owner_uid)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!(nm_secret_agent_get_capabilities (agent) & capability))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*************************************************************/
|
|
|
|
|
|
2010-12-10 12:38:19 -06:00
|
|
|
static void
|
|
|
|
|
name_owner_changed_cb (NMDBusManager *dbus_mgr,
|
|
|
|
|
const char *name,
|
|
|
|
|
const char *old_owner,
|
|
|
|
|
const char *new_owner,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
if (old_owner) {
|
|
|
|
|
/* The agent quit, so remove it and let interested clients know */
|
|
|
|
|
remove_agent (NM_AGENT_MANAGER (user_data), old_owner);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2011-07-01 14:34:08 -05:00
|
|
|
static void
|
|
|
|
|
agent_permissions_changed_done (NMAuthChain *chain,
|
|
|
|
|
GError *error,
|
|
|
|
|
DBusGMethodInvocation *context,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManager *self = NM_AGENT_MANAGER (user_data);
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
NMSecretAgent *agent;
|
2012-10-08 12:52:15 -05:00
|
|
|
gboolean share_protected = FALSE, share_open = FALSE;
|
2011-07-01 14:34:08 -05:00
|
|
|
|
|
|
|
|
priv->chains = g_slist_remove (priv->chains, chain);
|
|
|
|
|
|
|
|
|
|
agent = nm_auth_chain_get_data (chain, "agent");
|
2012-10-08 12:52:15 -05:00
|
|
|
g_assert (agent);
|
2011-07-01 14:34:08 -05:00
|
|
|
|
|
|
|
|
if (error) {
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) failed to request updated agent permissions",
|
|
|
|
|
nm_secret_agent_get_description (agent));
|
|
|
|
|
} else {
|
|
|
|
|
nm_log_dbg (LOGD_AGENTS, "(%s) updated agent permissions",
|
|
|
|
|
nm_secret_agent_get_description (agent));
|
|
|
|
|
|
2012-10-08 12:52:15 -05:00
|
|
|
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;
|
2011-07-01 14:34:08 -05:00
|
|
|
}
|
|
|
|
|
|
2012-10-08 12:52:15 -05:00
|
|
|
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);
|
|
|
|
|
|
2011-07-01 14:34:08 -05:00
|
|
|
nm_auth_chain_unref (chain);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
authority_changed_cb (gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManager *self = NM_AGENT_MANAGER (user_data);
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
|
|
|
|
|
/* Recheck the permissions of all secret agents */
|
|
|
|
|
g_hash_table_iter_init (&iter, priv->agents);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) {
|
|
|
|
|
NMAuthChain *chain;
|
|
|
|
|
|
|
|
|
|
/* Kick off permissions requests for this agent */
|
2013-07-29 10:40:11 -05:00
|
|
|
chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (agent),
|
|
|
|
|
NULL,
|
|
|
|
|
agent_permissions_changed_done,
|
|
|
|
|
self);
|
2012-10-08 12:52:15 -05:00
|
|
|
g_assert (chain);
|
|
|
|
|
priv->chains = g_slist_append (priv->chains, chain);
|
2011-07-01 14:34:08 -05:00
|
|
|
|
|
|
|
|
/* Make sure if the agent quits while the permissions call is in progress
|
|
|
|
|
* that the object sticks around until our callback.
|
|
|
|
|
*/
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-12-10 12:38:19 -06:00
|
|
|
/*************************************************************/
|
|
|
|
|
|
|
|
|
|
NMAgentManager *
|
2011-01-27 10:41:02 -06:00
|
|
|
nm_agent_manager_get (void)
|
2010-12-10 12:38:19 -06:00
|
|
|
{
|
2011-01-27 10:41:02 -06:00
|
|
|
static NMAgentManager *singleton = NULL;
|
2010-12-10 12:38:19 -06:00
|
|
|
NMAgentManagerPrivate *priv;
|
|
|
|
|
|
2011-01-27 10:41:02 -06:00
|
|
|
if (singleton)
|
|
|
|
|
return g_object_ref (singleton);
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2011-01-27 10:41:02 -06:00
|
|
|
singleton = (NMAgentManager *) g_object_new (NM_TYPE_AGENT_MANAGER, NULL);
|
|
|
|
|
g_assert (singleton);
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2011-01-27 10:41:02 -06:00
|
|
|
priv = NM_AGENT_MANAGER_GET_PRIVATE (singleton);
|
|
|
|
|
priv->session_monitor = nm_session_monitor_get ();
|
|
|
|
|
priv->dbus_mgr = nm_dbus_manager_get ();
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2012-10-04 16:42:03 -05:00
|
|
|
nm_dbus_manager_register_object (priv->dbus_mgr, NM_DBUS_PATH_AGENT_MANAGER, singleton);
|
2011-01-27 10:41:02 -06:00
|
|
|
|
|
|
|
|
g_signal_connect (priv->dbus_mgr,
|
|
|
|
|
NM_DBUS_MANAGER_NAME_OWNER_CHANGED,
|
|
|
|
|
G_CALLBACK (name_owner_changed_cb),
|
|
|
|
|
singleton);
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2011-07-01 14:34:08 -05:00
|
|
|
nm_auth_changed_func_register (authority_changed_cb, singleton);
|
|
|
|
|
|
2011-01-27 10:41:02 -06:00
|
|
|
return singleton;
|
2010-12-10 12:38:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_agent_manager_init (NMAgentManager *self)
|
|
|
|
|
{
|
2010-12-13 13:11:51 -06:00
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
|
|
|
|
|
priv->agents = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
|
|
|
|
|
priv->requests = g_hash_table_new_full (g_direct_hash,
|
|
|
|
|
g_direct_equal,
|
|
|
|
|
NULL,
|
|
|
|
|
(GDestroyNotify) request_free);
|
2010-12-10 12:38:19 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
dispose (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (object);
|
|
|
|
|
|
2011-02-02 16:19:15 -06:00
|
|
|
if (!priv->disposed) {
|
|
|
|
|
priv->disposed = TRUE;
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2011-07-01 14:34:08 -05:00
|
|
|
nm_auth_changed_func_unregister (authority_changed_cb, NM_AGENT_MANAGER (object));
|
|
|
|
|
|
2013-10-22 13:24:49 +02:00
|
|
|
g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_unref);
|
2011-07-01 14:34:08 -05:00
|
|
|
|
2011-02-02 16:19:15 -06:00
|
|
|
g_hash_table_destroy (priv->agents);
|
|
|
|
|
g_hash_table_destroy (priv->requests);
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2011-02-02 16:19:15 -06:00
|
|
|
g_object_unref (priv->session_monitor);
|
2013-04-10 11:37:05 -05:00
|
|
|
priv->dbus_mgr = NULL;
|
2011-02-02 16:19:15 -06:00
|
|
|
}
|
2010-12-10 12:38:19 -06:00
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (nm_agent_manager_parent_class)->dispose (object);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2010-12-14 11:12:56 -06:00
|
|
|
nm_agent_manager_class_init (NMAgentManagerClass *agent_manager_class)
|
2010-12-10 12:38:19 -06:00
|
|
|
{
|
2010-12-14 11:12:56 -06:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (agent_manager_class);
|
2010-12-10 12:38:19 -06:00
|
|
|
|
2010-12-14 11:12:56 -06:00
|
|
|
g_type_class_add_private (agent_manager_class, sizeof (NMAgentManagerPrivate));
|
2010-12-10 12:38:19 -06:00
|
|
|
|
|
|
|
|
/* virtual methods */
|
|
|
|
|
object_class->dispose = dispose;
|
|
|
|
|
|
2011-06-28 15:48:12 +02:00
|
|
|
/* Signals */
|
|
|
|
|
signals[AGENT_REGISTERED] =
|
|
|
|
|
g_signal_new ("agent-registered",
|
|
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
|
G_STRUCT_OFFSET (NMAgentManagerClass, agent_registered),
|
|
|
|
|
NULL, NULL,
|
|
|
|
|
g_cclosure_marshal_VOID__OBJECT,
|
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
|
G_TYPE_OBJECT);
|
|
|
|
|
|
2010-12-14 11:12:56 -06:00
|
|
|
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (agent_manager_class),
|
|
|
|
|
&dbus_glib_nm_agent_manager_object_info);
|
|
|
|
|
|
2010-12-10 12:38:19 -06:00
|
|
|
dbus_g_error_domain_register (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_DBUS_INTERFACE_AGENT_MANAGER,
|
|
|
|
|
NM_TYPE_AGENT_MANAGER_ERROR);
|
|
|
|
|
}
|