|
|
|
|
@ -35,15 +35,9 @@ typedef struct {
|
|
|
|
|
NMAuthManager *auth_mgr;
|
|
|
|
|
NMSessionMonitor *session_monitor;
|
|
|
|
|
|
|
|
|
|
/* Auth chains for checking agent permissions */
|
|
|
|
|
GSList *chains;
|
|
|
|
|
CList agent_lst_head;
|
|
|
|
|
|
|
|
|
|
/* Hashed by owner name, not identifier, since two agents in different
|
|
|
|
|
* sessions can use the same identifier.
|
|
|
|
|
*/
|
|
|
|
|
GHashTable *agents;
|
|
|
|
|
|
|
|
|
|
CList requests;
|
|
|
|
|
CList request_lst_head;
|
|
|
|
|
|
|
|
|
|
guint64 agent_version_id;
|
|
|
|
|
} NMAgentManagerPrivate;
|
|
|
|
|
@ -119,6 +113,8 @@ static void _con_del_request_start (Request *req);
|
|
|
|
|
|
|
|
|
|
static gboolean _con_get_try_complete_early (Request *req);
|
|
|
|
|
|
|
|
|
|
static void agent_disconnected_cb (NMSecretAgent *agent, gpointer user_data);
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
guint64
|
|
|
|
|
@ -152,7 +148,7 @@ _request_type_to_string (RequestType request_type, gboolean verbose)
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
struct _NMAgentManagerCallId {
|
|
|
|
|
CList lst_request;
|
|
|
|
|
CList request_lst;
|
|
|
|
|
|
|
|
|
|
NMAgentManager *self;
|
|
|
|
|
|
|
|
|
|
@ -201,40 +197,73 @@ struct _NMAgentManagerCallId {
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
remove_agent (NMAgentManager *self, const char *owner)
|
|
|
|
|
static NMSecretAgent *
|
|
|
|
|
_agent_find_by_owner (NMAgentManagerPrivate *priv,
|
|
|
|
|
const char *owner)
|
|
|
|
|
{
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
|
|
|
|
|
c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) {
|
|
|
|
|
if (nm_streq (nm_secret_agent_get_dbus_owner (agent), owner))
|
|
|
|
|
return agent;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMSecretAgent *
|
|
|
|
|
_agent_find_by_identifier_and_uid (NMAgentManagerPrivate *priv,
|
|
|
|
|
const char *identifier,
|
|
|
|
|
gulong sender_uid)
|
|
|
|
|
{
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
|
|
|
|
|
c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) {
|
|
|
|
|
if ( nm_streq0 (nm_secret_agent_get_identifier (agent), identifier)
|
|
|
|
|
&& sender_uid == nm_secret_agent_get_owner_uid (agent))
|
|
|
|
|
return agent;
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
_agent_remove (NMAgentManager *self, NMSecretAgent *agent)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
CList *iter, *safe;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (owner != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
/* Make sure this agent has already registered */
|
|
|
|
|
agent = g_hash_table_lookup (priv->agents, owner);
|
|
|
|
|
if (!agent)
|
|
|
|
|
return FALSE;
|
|
|
|
|
nm_assert (NM_IS_SECRET_AGENT (agent));
|
|
|
|
|
nm_assert (c_list_contains (&priv->agent_lst_head, &agent->agent_lst));
|
|
|
|
|
|
|
|
|
|
_LOGD (agent, "agent unregistered or disappeared");
|
|
|
|
|
|
|
|
|
|
/* Remove this agent from any in-progress secrets requests */
|
|
|
|
|
c_list_for_each_safe (iter, safe, &priv->requests)
|
|
|
|
|
request_remove_agent (c_list_entry (iter, Request, lst_request), agent);
|
|
|
|
|
nm_clear_pointer (&agent->auth_chain, nm_auth_chain_destroy);
|
|
|
|
|
|
|
|
|
|
/* And dispose of the agent */
|
|
|
|
|
g_hash_table_remove (priv->agents, owner);
|
|
|
|
|
return TRUE;
|
|
|
|
|
c_list_unlink (&agent->agent_lst);
|
|
|
|
|
|
|
|
|
|
g_signal_handlers_disconnect_by_func (agent, G_CALLBACK (agent_disconnected_cb), self);
|
|
|
|
|
|
|
|
|
|
/* Remove this agent from any in-progress secrets requests */
|
|
|
|
|
c_list_for_each_safe (iter, safe, &priv->request_lst_head)
|
|
|
|
|
request_remove_agent (c_list_entry (iter, Request, request_lst), agent);
|
|
|
|
|
|
|
|
|
|
g_object_unref (agent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Call this *after* calling request_next_agent() */
|
|
|
|
|
static void
|
|
|
|
|
maybe_remove_agent_on_error (NMSecretAgent *agent,
|
|
|
|
|
maybe_remove_agent_on_error (NMAgentManager *self,
|
|
|
|
|
NMSecretAgent *agent,
|
|
|
|
|
GError *error)
|
|
|
|
|
{
|
|
|
|
|
if ( g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)
|
|
|
|
|
|| g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED)
|
|
|
|
|
|| g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER))
|
|
|
|
|
remove_agent (nm_agent_manager_get (), nm_secret_agent_get_dbus_owner (agent));
|
|
|
|
|
if ( !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CLOSED)
|
|
|
|
|
&& !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_DISCONNECTED)
|
|
|
|
|
&& !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!c_list_is_empty (&agent->agent_lst))
|
|
|
|
|
_agent_remove (self, agent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
@ -295,70 +324,92 @@ validate_identifier (const char *identifier, GError **error)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
agent_register_permissions_done (NMAuthChain *chain,
|
|
|
|
|
GDBusMethodInvocation *context,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
_agent_permissions_check_done (NMAuthChain *chain,
|
|
|
|
|
GDBusMethodInvocation *context,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManager *self = NM_AGENT_MANAGER (user_data);
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
const char *sender;
|
|
|
|
|
NMAuthCallResult result;
|
|
|
|
|
CList *iter;
|
|
|
|
|
Request *request;
|
|
|
|
|
|
|
|
|
|
nm_assert (G_IS_DBUS_METHOD_INVOCATION (context));
|
|
|
|
|
|
|
|
|
|
priv->chains = g_slist_remove (priv->chains, chain);
|
|
|
|
|
nm_assert (!context || G_IS_DBUS_METHOD_INVOCATION (context));
|
|
|
|
|
|
|
|
|
|
agent = nm_auth_chain_steal_data (chain, "agent");
|
|
|
|
|
nm_assert (agent);
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
nm_assert (NM_IS_SECRET_AGENT (agent));
|
|
|
|
|
nm_assert (agent->auth_chain == chain);
|
|
|
|
|
nm_assert (agent->fully_registered == (!context));
|
|
|
|
|
nm_assert (c_list_contains (&priv->agent_lst_head, &agent->agent_lst));
|
|
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
agent->auth_chain = NULL;
|
|
|
|
|
|
|
|
|
|
nm_secret_agent_add_permission (agent,
|
|
|
|
|
NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED,
|
|
|
|
|
(nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED) == NM_AUTH_CALL_RESULT_YES));
|
|
|
|
|
nm_secret_agent_add_permission (agent,
|
|
|
|
|
NM_AUTH_PERMISSION_WIFI_SHARE_OPEN,
|
|
|
|
|
(nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN) == NM_AUTH_CALL_RESULT_YES));
|
|
|
|
|
|
|
|
|
|
if (agent->fully_registered) {
|
|
|
|
|
_LOGD (agent, "updated agent permissions");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_LOGI (agent, "agent registered");
|
|
|
|
|
|
|
|
|
|
agent->fully_registered = TRUE;
|
|
|
|
|
|
|
|
|
|
priv->agent_version_id += 1;
|
|
|
|
|
sender = nm_secret_agent_get_dbus_owner (agent);
|
|
|
|
|
g_hash_table_insert (priv->agents, g_strdup (sender), agent);
|
|
|
|
|
_LOGI (agent, "agent registered");
|
|
|
|
|
|
|
|
|
|
g_dbus_method_invocation_return_value (context, NULL);
|
|
|
|
|
|
|
|
|
|
/* Signal an agent was registered */
|
|
|
|
|
g_signal_emit (self, signals[AGENT_REGISTERED], 0, agent);
|
|
|
|
|
c_list_for_each_entry (request, &priv->request_lst_head, request_lst)
|
|
|
|
|
request_add_agent (request, agent);
|
|
|
|
|
|
|
|
|
|
/* Add this agent to any in-progress secrets requests */
|
|
|
|
|
c_list_for_each (iter, &priv->requests)
|
|
|
|
|
request_add_agent (c_list_entry (iter, Request, lst_request), agent);
|
|
|
|
|
g_signal_emit (self, signals[AGENT_REGISTERED], 0, agent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static NMSecretAgent *
|
|
|
|
|
find_agent_by_identifier_and_uid (NMAgentManager *self,
|
|
|
|
|
const char *identifier,
|
|
|
|
|
gulong sender_uid)
|
|
|
|
|
static NMAuthChain *
|
|
|
|
|
_agent_create_auth_chain (NMAgentManager *self,
|
|
|
|
|
NMSecretAgent *agent,
|
|
|
|
|
GDBusMethodInvocation *context)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
NMAuthChain *chain;
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
_LOGD (agent, "requesting permissions");
|
|
|
|
|
|
|
|
|
|
nm_assert ( !agent->auth_chain
|
|
|
|
|
|| (agent->fully_registered == (!nm_auth_chain_get_context (agent->auth_chain))));
|
|
|
|
|
|
|
|
|
|
if ( agent->auth_chain
|
|
|
|
|
&& !context
|
|
|
|
|
&& !agent->fully_registered) {
|
|
|
|
|
/* we restart the authorization check (without a @context), but the currently
|
|
|
|
|
* pending auth-chain carries a context. We need to pass it on as we replace
|
|
|
|
|
* the auth-chain. */
|
|
|
|
|
context = nm_auth_chain_get_context (agent->auth_chain);
|
|
|
|
|
nm_assert (context);
|
|
|
|
|
}
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (agent),
|
|
|
|
|
context,
|
|
|
|
|
_agent_permissions_check_done,
|
|
|
|
|
self);
|
|
|
|
|
|
|
|
|
|
nm_auth_chain_set_data (chain, "agent", agent, NULL);
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
nm_clear_pointer (&agent->auth_chain, nm_auth_chain_destroy);
|
|
|
|
|
agent->auth_chain = chain;
|
|
|
|
|
return chain;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
agent_disconnected_cb (NMSecretAgent *agent, gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
/* The agent quit, so remove it and let interested clients know */
|
|
|
|
|
remove_agent (NM_AGENT_MANAGER (user_data),
|
|
|
|
|
nm_secret_agent_get_dbus_owner (agent));
|
|
|
|
|
_agent_remove (NM_AGENT_MANAGER (user_data), agent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
@ -368,65 +419,44 @@ agent_manager_register_with_capabilities (NMAgentManager *self,
|
|
|
|
|
guint32 capabilities)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
NMAuthSubject *subject;
|
|
|
|
|
gs_unref_object NMAuthSubject *subject = NULL;
|
|
|
|
|
gulong sender_uid = G_MAXULONG;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
NMAuthChain *chain;
|
|
|
|
|
|
|
|
|
|
subject = nm_dbus_manager_new_auth_subject_from_context (context);
|
|
|
|
|
if (!subject) {
|
|
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_PERMISSION_DENIED,
|
|
|
|
|
NM_UTILS_ERROR_MSG_REQ_UID_UKNOWN);
|
|
|
|
|
goto done;
|
|
|
|
|
g_dbus_method_invocation_take_error (context, error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
sender_uid = nm_auth_subject_get_unix_process_uid (subject);
|
|
|
|
|
|
|
|
|
|
/* Validate the identifier */
|
|
|
|
|
if (!validate_identifier (identifier, &error))
|
|
|
|
|
goto done;
|
|
|
|
|
if (!validate_identifier (identifier, &error)) {
|
|
|
|
|
g_dbus_method_invocation_take_error (context, error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Only one agent for each identifier is allowed per user */
|
|
|
|
|
if (find_agent_by_identifier_and_uid (self, identifier, sender_uid)) {
|
|
|
|
|
if (_agent_find_by_identifier_and_uid (priv, 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;
|
|
|
|
|
g_dbus_method_invocation_take_error (context, error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Success, add the new agent */
|
|
|
|
|
agent = nm_secret_agent_new (context, subject, identifier, capabilities);
|
|
|
|
|
if (!agent) {
|
|
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_FAILED,
|
|
|
|
|
"Failed to initialize the agent");
|
|
|
|
|
goto done;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_signal_connect (agent, NM_SECRET_AGENT_DISCONNECTED,
|
|
|
|
|
G_CALLBACK (agent_disconnected_cb), self);
|
|
|
|
|
|
|
|
|
|
_LOGD (agent, "requesting permissions");
|
|
|
|
|
c_list_link_tail (&priv->agent_lst_head, &agent->agent_lst);
|
|
|
|
|
|
|
|
|
|
/* Kick off permissions requests for this agent */
|
|
|
|
|
chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self);
|
|
|
|
|
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 {
|
|
|
|
|
g_object_unref (agent);
|
|
|
|
|
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_FAILED,
|
|
|
|
|
"Unable to start agent authentication.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
done:
|
|
|
|
|
if (error)
|
|
|
|
|
g_dbus_method_invocation_take_error (context, error);
|
|
|
|
|
g_clear_object (&subject);
|
|
|
|
|
_agent_create_auth_chain (self, agent, context);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
@ -470,8 +500,11 @@ impl_agent_manager_unregister (NMDBusObject *obj,
|
|
|
|
|
GVariant *parameters)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManager *self = NM_AGENT_MANAGER (obj);
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
|
|
|
|
|
if (!remove_agent (self, sender)) {
|
|
|
|
|
agent = _agent_find_by_owner (priv, sender);
|
|
|
|
|
if (!agent) {
|
|
|
|
|
g_dbus_method_invocation_return_error_literal (invocation,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR,
|
|
|
|
|
NM_AGENT_MANAGER_ERROR_NOT_REGISTERED,
|
|
|
|
|
@ -479,6 +512,8 @@ impl_agent_manager_unregister (NMDBusObject *obj,
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_agent_remove (self, agent);
|
|
|
|
|
|
|
|
|
|
g_dbus_method_invocation_return_value (invocation, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -497,7 +532,7 @@ request_new (NMAgentManager *self,
|
|
|
|
|
req->request_type = request_type;
|
|
|
|
|
req->detail = g_strdup (detail);
|
|
|
|
|
req->subject = g_object_ref (subject);
|
|
|
|
|
c_list_link_tail (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &req->lst_request);
|
|
|
|
|
c_list_link_tail (&NM_AGENT_MANAGER_GET_PRIVATE (self)->request_lst_head, &req->request_lst);
|
|
|
|
|
return req;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -583,7 +618,7 @@ req_complete_cancel (Request *req, gboolean is_disposing)
|
|
|
|
|
gs_free_error GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
nm_assert (req && req->self);
|
|
|
|
|
nm_assert (!c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (req->self)->requests, &req->lst_request));
|
|
|
|
|
nm_assert (!c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (req->self)->request_lst_head, &req->request_lst));
|
|
|
|
|
|
|
|
|
|
nm_utils_error_set_cancelled (&error, is_disposing, "NMAgentManager");
|
|
|
|
|
req_complete_release (req, NULL, NULL, NULL, error);
|
|
|
|
|
@ -598,9 +633,9 @@ req_complete (Request *req,
|
|
|
|
|
{
|
|
|
|
|
NMAgentManager *self = req->self;
|
|
|
|
|
|
|
|
|
|
nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &req->lst_request));
|
|
|
|
|
nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->request_lst_head, &req->request_lst));
|
|
|
|
|
|
|
|
|
|
c_list_unlink (&req->lst_request);
|
|
|
|
|
c_list_unlink (&req->request_lst);
|
|
|
|
|
|
|
|
|
|
req_complete_release (req, secrets, agent_dbus_owner, agent_username, error);
|
|
|
|
|
}
|
|
|
|
|
@ -710,12 +745,12 @@ static void
|
|
|
|
|
request_add_agents (NMAgentManager *self, Request *req)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
gpointer data;
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) {
|
|
|
|
|
if (agent->fully_registered)
|
|
|
|
|
request_add_agent (req, agent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
@ -868,7 +903,7 @@ _con_get_request_done (NMSecretAgent *agent,
|
|
|
|
|
|
|
|
|
|
/* Try the next agent */
|
|
|
|
|
request_next_agent (req);
|
|
|
|
|
maybe_remove_agent_on_error (agent, error);
|
|
|
|
|
maybe_remove_agent_on_error (self, agent, error);
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
@ -1037,7 +1072,7 @@ _con_get_request_start (Request *req)
|
|
|
|
|
NULL,
|
|
|
|
|
_con_get_request_start_validated,
|
|
|
|
|
req);
|
|
|
|
|
g_assert (req->con.chain);
|
|
|
|
|
nm_assert (req->con.chain);
|
|
|
|
|
|
|
|
|
|
/* 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
|
|
|
|
|
@ -1188,7 +1223,6 @@ nm_agent_manager_get_secrets (NMAgentManager *self,
|
|
|
|
|
req->con.get.callback = callback;
|
|
|
|
|
req->con.get.callback_data = callback_data;
|
|
|
|
|
|
|
|
|
|
/* Kick off the request */
|
|
|
|
|
if (!(req->con.get.flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM))
|
|
|
|
|
request_add_agents (self, req);
|
|
|
|
|
req->idle_id = g_idle_add (request_start, req);
|
|
|
|
|
@ -1203,9 +1237,9 @@ nm_agent_manager_cancel_secrets (NMAgentManager *self,
|
|
|
|
|
g_return_if_fail (request_id);
|
|
|
|
|
g_return_if_fail (request_id->request_type == REQUEST_TYPE_CON_GET);
|
|
|
|
|
|
|
|
|
|
nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->requests, &request_id->lst_request));
|
|
|
|
|
nm_assert (c_list_contains (&NM_AGENT_MANAGER_GET_PRIVATE (self)->request_lst_head, &request_id->request_lst));
|
|
|
|
|
|
|
|
|
|
c_list_unlink (&request_id->lst_request);
|
|
|
|
|
c_list_unlink (&request_id->request_lst);
|
|
|
|
|
|
|
|
|
|
req_complete_cancel (request_id, FALSE);
|
|
|
|
|
}
|
|
|
|
|
@ -1242,7 +1276,7 @@ _con_save_request_done (NMSecretAgent *agent,
|
|
|
|
|
LOG_REQ_ARG (req), error->message);
|
|
|
|
|
/* Try the next agent */
|
|
|
|
|
request_next_agent (req);
|
|
|
|
|
maybe_remove_agent_on_error (agent, error);
|
|
|
|
|
maybe_remove_agent_on_error (self, agent, error);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -1291,7 +1325,6 @@ nm_agent_manager_save_secrets (NMAgentManager *self,
|
|
|
|
|
req->con.path = g_strdup (path);
|
|
|
|
|
req->con.connection = g_object_ref (connection);
|
|
|
|
|
|
|
|
|
|
/* Kick off the request */
|
|
|
|
|
request_add_agents (self, req);
|
|
|
|
|
req->idle_id = g_idle_add (request_start, req);
|
|
|
|
|
}
|
|
|
|
|
@ -1333,7 +1366,7 @@ _con_del_request_done (NMSecretAgent *agent,
|
|
|
|
|
/* Tell the next agent to delete secrets */
|
|
|
|
|
request_next_agent (req);
|
|
|
|
|
if (error)
|
|
|
|
|
maybe_remove_agent_on_error (agent, error);
|
|
|
|
|
maybe_remove_agent_on_error (self, agent, error);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
@ -1376,27 +1409,36 @@ nm_agent_manager_delete_secrets (NMAgentManager *self,
|
|
|
|
|
req->con.connection = g_object_ref (connection);
|
|
|
|
|
g_object_unref (subject);
|
|
|
|
|
|
|
|
|
|
/* Kick off the request */
|
|
|
|
|
request_add_agents (self, req);
|
|
|
|
|
req->idle_id = g_idle_add (request_start, req);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
NMSecretAgent *
|
|
|
|
|
nm_agent_manager_get_agent_by_user (NMAgentManager *self, const char *username)
|
|
|
|
|
gboolean
|
|
|
|
|
nm_agent_manager_has_agent_with_permission (NMAgentManager *self,
|
|
|
|
|
const char *username,
|
|
|
|
|
const char *permission)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
NMAgentManagerPrivate *priv;
|
|
|
|
|
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;
|
|
|
|
|
g_return_val_if_fail (NM_IS_AGENT_MANAGER (self), FALSE);
|
|
|
|
|
g_return_val_if_fail (username, FALSE);
|
|
|
|
|
g_return_val_if_fail (permission, FALSE);
|
|
|
|
|
|
|
|
|
|
priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
|
|
|
|
|
c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) {
|
|
|
|
|
if (!agent->fully_registered)
|
|
|
|
|
continue;
|
|
|
|
|
if (!nm_streq0 (nm_secret_agent_get_owner_username (agent), username))
|
|
|
|
|
continue;
|
|
|
|
|
if (nm_secret_agent_has_permission (agent, permission))
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
@ -1407,17 +1449,16 @@ nm_agent_manager_all_agents_have_capability (NMAgentManager *manager,
|
|
|
|
|
NMSecretAgentCapabilities capability)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (manager);
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
gboolean subject_is_unix_process = (nm_auth_subject_get_subject_type (subject) == NM_AUTH_SUBJECT_TYPE_UNIX_PROCESS);
|
|
|
|
|
gulong subject_uid = subject_is_unix_process ? nm_auth_subject_get_unix_process_uid (subject) : 0u;
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, priv->agents);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &agent)) {
|
|
|
|
|
c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst) {
|
|
|
|
|
if (!agent->fully_registered)
|
|
|
|
|
continue;
|
|
|
|
|
if ( subject_is_unix_process
|
|
|
|
|
&& nm_secret_agent_get_owner_uid (agent) != subject_uid)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
if (!(nm_secret_agent_get_capabilities (agent) & capability))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
@ -1427,59 +1468,14 @@ nm_agent_manager_all_agents_have_capability (NMAgentManager *manager,
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
agent_permissions_changed_done (NMAuthChain *chain,
|
|
|
|
|
GDBusMethodInvocation *context,
|
|
|
|
|
gpointer user_data)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManager *self = NM_AGENT_MANAGER (user_data);
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
gboolean share_protected = FALSE, share_open = FALSE;
|
|
|
|
|
|
|
|
|
|
priv->chains = g_slist_remove (priv->chains, chain);
|
|
|
|
|
|
|
|
|
|
agent = nm_auth_chain_get_data (chain, "agent");
|
|
|
|
|
g_assert (agent);
|
|
|
|
|
|
|
|
|
|
_LOGD (agent, "updated agent permissions");
|
|
|
|
|
|
|
|
|
|
if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED) == NM_AUTH_CALL_RESULT_YES)
|
|
|
|
|
share_protected = TRUE;
|
|
|
|
|
if (nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN) == NM_AUTH_CALL_RESULT_YES)
|
|
|
|
|
share_open = TRUE;
|
|
|
|
|
|
|
|
|
|
nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, share_protected);
|
|
|
|
|
nm_secret_agent_add_permission (agent, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, share_open);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
authority_changed_cb (NMAuthManager *auth_manager, NMAgentManager *self)
|
|
|
|
|
{
|
|
|
|
|
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 */
|
|
|
|
|
chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (agent),
|
|
|
|
|
NULL,
|
|
|
|
|
agent_permissions_changed_done,
|
|
|
|
|
self);
|
|
|
|
|
g_assert (chain);
|
|
|
|
|
priv->chains = g_slist_append (priv->chains, chain);
|
|
|
|
|
|
|
|
|
|
/* Make sure if the agent quits while the permissions call is in progress
|
|
|
|
|
* that the object sticks around until our callback.
|
|
|
|
|
*/
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
c_list_for_each_entry (agent, &priv->agent_lst_head, agent_lst)
|
|
|
|
|
_agent_create_auth_chain (self, agent, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
@ -1490,8 +1486,8 @@ nm_agent_manager_init (NMAgentManager *self)
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
|
|
|
|
|
priv->agent_version_id = 1;
|
|
|
|
|
c_list_init (&priv->requests);
|
|
|
|
|
priv->agents = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, g_object_unref);
|
|
|
|
|
c_list_init (&priv->agent_lst_head);
|
|
|
|
|
c_list_init (&priv->request_lst_head);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
@ -1515,23 +1511,18 @@ constructed (GObject *object)
|
|
|
|
|
static void
|
|
|
|
|
dispose (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE ((NMAgentManager *) object);
|
|
|
|
|
CList *iter;
|
|
|
|
|
NMAgentManager *self = NM_AGENT_MANAGER (object);
|
|
|
|
|
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
|
|
|
|
|
Request *request;
|
|
|
|
|
NMSecretAgent *agent;
|
|
|
|
|
|
|
|
|
|
cancel_more:
|
|
|
|
|
c_list_for_each (iter, &priv->requests) {
|
|
|
|
|
c_list_unlink (iter);
|
|
|
|
|
req_complete_cancel (c_list_entry (iter, Request, lst_request), TRUE);
|
|
|
|
|
goto cancel_more;
|
|
|
|
|
while ((request = c_list_first_entry (&priv->request_lst_head, Request, request_lst))) {
|
|
|
|
|
c_list_unlink (&request->request_lst);
|
|
|
|
|
req_complete_cancel (request, TRUE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_slist_free_full (priv->chains, (GDestroyNotify) nm_auth_chain_destroy);
|
|
|
|
|
priv->chains = NULL;
|
|
|
|
|
|
|
|
|
|
if (priv->agents) {
|
|
|
|
|
g_hash_table_destroy (priv->agents);
|
|
|
|
|
priv->agents = NULL;
|
|
|
|
|
}
|
|
|
|
|
while ((agent = c_list_first_entry (&priv->agent_lst_head, NMSecretAgent, agent_lst)))
|
|
|
|
|
_agent_remove (self, agent);
|
|
|
|
|
|
|
|
|
|
if (priv->auth_mgr) {
|
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->auth_mgr,
|
|
|
|
|
|