mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-06 03:28:03 +02:00
settings: merge branch 'th/secret-agent-rh1253407'
Several fixes and refactoring for NMSecretAgent and NMAgentManager. https://bugzilla.redhat.com/show_bug.cgi?id=1253407
This commit is contained in:
commit
da1b6c2c32
7 changed files with 554 additions and 229 deletions
|
|
@ -175,6 +175,7 @@
|
|||
(cond) ? (prefix) : "", \
|
||||
(cond) ? (str) : (str_else), \
|
||||
(cond) ? (suffix) : ""
|
||||
#define NM_PRINT_FMT_QUOTE_STRING(arg) NM_PRINT_FMT_QUOTED((arg), "\"", (arg), "\"", "(null)")
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
|
|||
|
|
@ -269,6 +269,11 @@ _nm_dbus_proxy_call_sync (GDBusProxy *proxy,
|
|||
*
|
||||
* Checks if @error is set and corresponds to the D-Bus error @dbus_error_name.
|
||||
*
|
||||
* This should only be used for "foreign" D-Bus errors (eg, errors
|
||||
* from BlueZ or wpa_supplicant). All NetworkManager D-Bus errors
|
||||
* should be properly mapped by gdbus to one of the domains/codes in
|
||||
* nm-errors.h.
|
||||
*
|
||||
* Returns: %TRUE or %FALSE
|
||||
*/
|
||||
gboolean
|
||||
|
|
|
|||
|
|
@ -847,10 +847,38 @@ nm_bus_manager_unregister_object (NMBusManager *self, gpointer object)
|
|||
g_dbus_interface_skeleton_unexport (G_DBUS_INTERFACE_SKELETON (object));
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_bus_manager_connection_is_private (NMBusManager *self,
|
||||
GDBusConnection *connection)
|
||||
{
|
||||
NMBusManagerPrivate *priv;
|
||||
GSList *iter;
|
||||
|
||||
g_return_val_if_fail (NM_IS_BUS_MANAGER (self), FALSE);
|
||||
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
|
||||
|
||||
if (g_dbus_connection_get_unique_name (connection))
|
||||
return FALSE;
|
||||
|
||||
/* Assert that we still track the private connection. The caller
|
||||
* of nm_bus_manager_connection_is_private() want's to subscribe
|
||||
* to NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED, thus the signal
|
||||
* never comes if we don't track the connection. */
|
||||
priv = NM_BUS_MANAGER_GET_PRIVATE (self);
|
||||
for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) {
|
||||
PrivateServer *s = iter->data;
|
||||
|
||||
if (g_hash_table_contains (s->connections,
|
||||
connection))
|
||||
return TRUE;
|
||||
}
|
||||
g_return_val_if_reached (TRUE);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_bus_manager_new_proxy:
|
||||
* @self: the #NMBusManager
|
||||
* @context: the method call context this proxy should be created
|
||||
* @connection: the GDBusConnection for which this connection should be created
|
||||
* @proxy_type: the type of #GDBusProxy to create
|
||||
* @name: any name on the message bus
|
||||
* @path: name of the object instance to call methods on
|
||||
|
|
@ -865,23 +893,20 @@ nm_bus_manager_unregister_object (NMBusManager *self, gpointer object)
|
|||
*/
|
||||
GDBusProxy *
|
||||
nm_bus_manager_new_proxy (NMBusManager *self,
|
||||
GDBusMethodInvocation *context,
|
||||
GDBusConnection *connection,
|
||||
GType proxy_type,
|
||||
const char *name,
|
||||
const char *path,
|
||||
const char *iface)
|
||||
{
|
||||
NMBusManagerPrivate *priv = NM_BUS_MANAGER_GET_PRIVATE (self);
|
||||
GDBusConnection *connection;
|
||||
GSList *iter;
|
||||
const char *owner;
|
||||
GDBusProxy *proxy;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_val_if_fail (g_type_is_a (proxy_type, G_TYPE_DBUS_PROXY), NULL);
|
||||
|
||||
connection = g_dbus_method_invocation_get_connection (context);
|
||||
g_assert (connection);
|
||||
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
|
||||
|
||||
/* Might be a private connection, for which @name is fake */
|
||||
for (iter = priv->private_servers; iter; iter = g_slist_next (iter)) {
|
||||
|
|
|
|||
|
|
@ -72,6 +72,9 @@ gboolean nm_bus_manager_get_caller_info (NMBusManager *self,
|
|||
gulong *out_uid,
|
||||
gulong *out_pid);
|
||||
|
||||
gboolean nm_bus_manager_connection_is_private (NMBusManager *self,
|
||||
GDBusConnection *connection);
|
||||
|
||||
gboolean nm_bus_manager_get_unix_user (NMBusManager *self,
|
||||
const char *sender,
|
||||
gulong *out_uid);
|
||||
|
|
@ -97,7 +100,7 @@ void nm_bus_manager_private_server_register (NMBusManager *self,
|
|||
const char *tag);
|
||||
|
||||
GDBusProxy *nm_bus_manager_new_proxy (NMBusManager *self,
|
||||
GDBusMethodInvocation *context,
|
||||
GDBusConnection *connection,
|
||||
GType proxy_type,
|
||||
const char *name,
|
||||
const char *path,
|
||||
|
|
|
|||
|
|
@ -40,6 +40,42 @@
|
|||
|
||||
#include "nmdbus-agent-manager.h"
|
||||
|
||||
NM_DEFINE_SINGLETON_INSTANCE (NMAgentManager);
|
||||
|
||||
#define _NMLOG_PREFIX_NAME "agent-manager"
|
||||
#define _NMLOG_DOMAIN LOGD_AGENTS
|
||||
#define _NMLOG(level, agent, ...) \
|
||||
G_STMT_START { \
|
||||
if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \
|
||||
char __prefix1[32]; \
|
||||
char __prefix2[128]; \
|
||||
NMSecretAgent *__agent = (agent); \
|
||||
\
|
||||
if (!(self)) \
|
||||
g_snprintf (__prefix1, sizeof (__prefix1), "%s%s", ""_NMLOG_PREFIX_NAME"", "[]"); \
|
||||
else if ((self) != singleton_instance) \
|
||||
g_snprintf (__prefix1, sizeof (__prefix1), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \
|
||||
else \
|
||||
g_strlcpy (__prefix1, _NMLOG_PREFIX_NAME, sizeof (__prefix1)); \
|
||||
if (__agent) { \
|
||||
g_snprintf (__prefix2, sizeof (__prefix2), \
|
||||
": req[%p, %s]", \
|
||||
__agent, \
|
||||
nm_secret_agent_get_description (__agent)); \
|
||||
} else \
|
||||
__prefix2[0] = '\0'; \
|
||||
_nm_log ((level), (_NMLOG_DOMAIN), 0, \
|
||||
"%s%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
||||
__prefix1, __prefix2 _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define LOG_REQ_FMT "[%p/%s%s%s]"
|
||||
#define LOG_REQ_ARG(req) (req), NM_PRINT_FMT_QUOTE_STRING ((req)->detail)
|
||||
|
||||
#define LOG_REQ2_FMT "[%p/%s%s%s/%s%s%s]"
|
||||
#define LOG_REQ2_ARG(req) (req), NM_PRINT_FMT_QUOTE_STRING ((req)->parent.detail), NM_PRINT_FMT_QUOTE_STRING ((req)->setting_name)
|
||||
|
||||
G_DEFINE_TYPE (NMAgentManager, nm_agent_manager, NM_TYPE_EXPORTED_OBJECT)
|
||||
|
||||
#define NM_AGENT_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
|
||||
|
|
@ -94,8 +130,7 @@ remove_agent (NMAgentManager *self, const char *owner)
|
|||
if (!agent)
|
||||
return FALSE;
|
||||
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent unregistered or disappeared",
|
||||
nm_secret_agent_get_description (agent));
|
||||
_LOGD (agent, "agent unregistered or disappeared");
|
||||
|
||||
/* Remove this agent from any in-progress secrets requests */
|
||||
g_hash_table_iter_init (&iter, priv->requests);
|
||||
|
|
@ -221,8 +256,7 @@ agent_register_permissions_done (NMAuthChain *chain,
|
|||
|
||||
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));
|
||||
_LOGD (agent, "agent registered");
|
||||
g_dbus_method_invocation_return_value (context, NULL);
|
||||
|
||||
/* Signal an agent was registered */
|
||||
|
|
@ -308,8 +342,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
|
|||
g_signal_connect (agent, NM_SECRET_AGENT_DISCONNECTED,
|
||||
G_CALLBACK (agent_disconnected_cb), self);
|
||||
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) requesting permissions",
|
||||
nm_secret_agent_get_description (agent));
|
||||
_LOGD (agent, "requesting permissions");
|
||||
|
||||
/* Kick off permissions requests for this agent */
|
||||
chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self);
|
||||
|
|
@ -388,6 +421,8 @@ typedef void (*RequestCancelFunc) (Request *req);
|
|||
|
||||
/* Basic secrets request structure */
|
||||
struct _Request {
|
||||
NMAgentManager *self;
|
||||
|
||||
guint32 reqid;
|
||||
char *detail;
|
||||
char *verb;
|
||||
|
|
@ -396,17 +431,11 @@ struct _Request {
|
|||
|
||||
/* Current agent being asked for secrets */
|
||||
NMSecretAgent *current;
|
||||
gconstpointer current_call_id;
|
||||
NMSecretAgentCallId current_call_id;
|
||||
|
||||
/* Stores the sorted list of NMSecretAgents which will be asked for secrets */
|
||||
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;
|
||||
|
||||
guint32 idle_id;
|
||||
|
||||
RequestAddAgentFunc add_agent_callback;
|
||||
|
|
@ -423,6 +452,7 @@ static guint32 next_req_id = 1;
|
|||
|
||||
static Request *
|
||||
request_new (gsize struct_size,
|
||||
NMAgentManager *self,
|
||||
const char *detail,
|
||||
const char *verb,
|
||||
NMAuthSubject *subject,
|
||||
|
|
@ -436,6 +466,7 @@ request_new (gsize struct_size,
|
|||
Request *req;
|
||||
|
||||
req = g_malloc0 (struct_size);
|
||||
req->self = g_object_ref (self);
|
||||
req->reqid = next_req_id++;
|
||||
req->detail = g_strdup (detail);
|
||||
req->verb = g_strdup (verb);
|
||||
|
|
@ -466,7 +497,12 @@ request_free (Request *req)
|
|||
g_free (req->detail);
|
||||
g_free (req->verb);
|
||||
g_slist_free_full (req->pending, g_object_unref);
|
||||
g_slist_free (req->asked);
|
||||
|
||||
g_object_unref (req->self);
|
||||
|
||||
if (req->current)
|
||||
g_object_unref (req->current);
|
||||
|
||||
memset (req, 0, sizeof (Request));
|
||||
g_free (req);
|
||||
}
|
||||
|
|
@ -532,11 +568,12 @@ agent_compare_func (gconstpointer aa, gconstpointer bb, gpointer user_data)
|
|||
static void
|
||||
request_add_agent (Request *req, NMSecretAgent *agent)
|
||||
{
|
||||
NMAgentManager *self;
|
||||
|
||||
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;
|
||||
self = req->self;
|
||||
|
||||
if (req->add_agent_callback && !req->add_agent_callback (req, agent))
|
||||
return;
|
||||
|
|
@ -548,18 +585,16 @@ request_add_agent (Request *req, NMSecretAgent *agent)
|
|||
agent_uid = nm_secret_agent_get_owner_uid (agent);
|
||||
subject_uid = nm_auth_subject_get_unix_process_uid (req->subject);
|
||||
if (agent_uid != subject_uid) {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s "
|
||||
"(uid %ld not required %ld)",
|
||||
nm_secret_agent_get_description (agent),
|
||||
req, req->detail,
|
||||
(long)agent_uid, (long)subject_uid);
|
||||
_LOGD (agent, "agent ignored for secrets request "LOG_REQ_FMT" "
|
||||
"(uid %ld not required %ld)",
|
||||
LOG_REQ_ARG (req),
|
||||
(long) agent_uid, (long) subject_uid);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent allowed for secrets request %p/%s",
|
||||
nm_secret_agent_get_description (agent),
|
||||
req, req->detail);
|
||||
_LOGD (agent, "agent allowed for secrets request "LOG_REQ_FMT,
|
||||
LOG_REQ_ARG (req));
|
||||
|
||||
/* Add this agent to the list, sorted appropriately */
|
||||
req->pending = g_slist_insert_sorted_with_data (req->pending,
|
||||
|
|
@ -583,25 +618,28 @@ request_add_agents (NMAgentManager *self, Request *req)
|
|||
static void
|
||||
request_next_agent (Request *req)
|
||||
{
|
||||
NMAgentManager *self;
|
||||
GError *error = NULL;
|
||||
|
||||
req->current_call_id = NULL;
|
||||
if (req->current)
|
||||
g_object_unref (req->current);
|
||||
self = req->self;
|
||||
|
||||
if (req->current) {
|
||||
if (req->current_call_id)
|
||||
nm_secret_agent_cancel_secrets (req->current, req->current_call_id);
|
||||
g_clear_object (&req->current);
|
||||
}
|
||||
g_warn_if_fail (!req->current_call_id);
|
||||
|
||||
if (req->pending) {
|
||||
/* Send the request to the next agent */
|
||||
req->current = req->pending->data;
|
||||
req->pending = g_slist_remove (req->pending, req->current);
|
||||
|
||||
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);
|
||||
_LOGD (req->current, "agent %s secrets for request "LOG_REQ_FMT,
|
||||
req->verb, LOG_REQ_ARG (req));
|
||||
|
||||
req->next_callback (req);
|
||||
} else {
|
||||
req->current = NULL;
|
||||
|
||||
/* 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,
|
||||
|
|
@ -614,18 +652,26 @@ request_next_agent (Request *req)
|
|||
static void
|
||||
request_remove_agent (Request *req, NMSecretAgent *agent, GSList **pending_reqs)
|
||||
{
|
||||
NMAgentManager *self;
|
||||
|
||||
g_return_if_fail (req != NULL);
|
||||
g_return_if_fail (agent != NULL);
|
||||
|
||||
req->pending = g_slist_remove (req->pending, agent);
|
||||
self = req->self;
|
||||
|
||||
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);
|
||||
nm_assert (!g_slist_find (req->pending, agent));
|
||||
|
||||
_LOGD (agent, "current agent removed from secrets request "LOG_REQ_FMT,
|
||||
LOG_REQ_ARG (req));
|
||||
*pending_reqs = g_slist_prepend (*pending_reqs, req);
|
||||
} else {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent removed from secrets request %p/%s",
|
||||
nm_secret_agent_get_description (agent), req, req->detail);
|
||||
req->pending = g_slist_remove (req->pending, agent);
|
||||
|
||||
_LOGD (agent, "agent removed from secrets request "LOG_REQ_FMT,
|
||||
LOG_REQ_ARG (req));
|
||||
|
||||
g_object_unref (agent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -682,16 +728,18 @@ connection_request_free (gpointer data)
|
|||
static gboolean
|
||||
connection_request_add_agent (Request *parent, NMSecretAgent *agent)
|
||||
{
|
||||
NMAgentManager *self;
|
||||
ConnectionRequest *req = (ConnectionRequest *) parent;
|
||||
NMAuthSubject *subject = nm_secret_agent_get_subject(agent);
|
||||
|
||||
self = parent->self;
|
||||
|
||||
/* Ensure the caller's username exists in the connection's permissions,
|
||||
* or that the permissions is empty (ie, visible by everyone).
|
||||
*/
|
||||
if (!nm_auth_is_subject_in_acl (req->connection, subject, NULL)) {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent ignored for secrets request %p/%s (not in ACL)",
|
||||
nm_secret_agent_get_description (agent),
|
||||
parent, parent->detail);
|
||||
_LOGD (agent, "agent ignored for secrets request "LOG_REQ_FMT" (not in ACL)",
|
||||
LOG_REQ_ARG (parent));
|
||||
/* Connection not visible to this agent's user */
|
||||
return FALSE;
|
||||
}
|
||||
|
|
@ -700,7 +748,8 @@ connection_request_add_agent (Request *parent, NMSecretAgent *agent)
|
|||
}
|
||||
|
||||
static ConnectionRequest *
|
||||
connection_request_new_get (NMConnection *connection,
|
||||
connection_request_new_get (NMAgentManager *self,
|
||||
NMConnection *connection,
|
||||
NMAuthSubject *subject,
|
||||
GVariant *existing_secrets,
|
||||
const char *setting_name,
|
||||
|
|
@ -719,6 +768,7 @@ connection_request_new_get (NMConnection *connection,
|
|||
ConnectionRequest *req;
|
||||
|
||||
req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest),
|
||||
self,
|
||||
nm_connection_get_id (connection),
|
||||
verb,
|
||||
subject,
|
||||
|
|
@ -744,7 +794,8 @@ connection_request_new_get (NMConnection *connection,
|
|||
}
|
||||
|
||||
static ConnectionRequest *
|
||||
connection_request_new_other (NMConnection *connection,
|
||||
connection_request_new_other (NMAgentManager *self,
|
||||
NMConnection *connection,
|
||||
NMAuthSubject *subject,
|
||||
const char *verb,
|
||||
RequestCompleteFunc complete_callback,
|
||||
|
|
@ -754,6 +805,7 @@ connection_request_new_other (NMConnection *connection,
|
|||
ConnectionRequest *req;
|
||||
|
||||
req = (ConnectionRequest *) request_new (sizeof (ConnectionRequest),
|
||||
self,
|
||||
nm_connection_get_id (connection),
|
||||
verb,
|
||||
subject,
|
||||
|
|
@ -770,11 +822,12 @@ connection_request_new_other (NMConnection *connection,
|
|||
|
||||
static void
|
||||
get_done_cb (NMSecretAgent *agent,
|
||||
gconstpointer call_id,
|
||||
NMSecretAgentCallId call_id,
|
||||
GVariant *secrets,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAgentManager *self;
|
||||
Request *parent = user_data;
|
||||
ConnectionRequest *req = user_data;
|
||||
GVariant *setting_secrets;
|
||||
|
|
@ -783,15 +836,24 @@ get_done_cb (NMSecretAgent *agent,
|
|||
char *agent_uname = NULL;
|
||||
|
||||
g_return_if_fail (call_id == parent->current_call_id);
|
||||
g_return_if_fail (agent == parent->current);
|
||||
|
||||
self = parent->self;
|
||||
|
||||
parent->current_call_id = NULL;
|
||||
|
||||
if (error) {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent failed secrets request %p/%s/%s: (%d) %s",
|
||||
nm_secret_agent_get_description (agent),
|
||||
req, parent->detail, req->setting_name,
|
||||
error ? error->code : -1,
|
||||
(error && error->message) ? error->message : "(unknown)");
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||
_LOGD (agent, "get secrets request cancelled: "LOG_REQ2_FMT,
|
||||
LOG_REQ2_ARG (req));
|
||||
return;
|
||||
}
|
||||
|
||||
if (_nm_dbus_error_has_name (error, NM_DBUS_INTERFACE_SECRET_AGENT ".UserCanceled")) {
|
||||
_LOGD (agent, "agent failed secrets request "LOG_REQ2_FMT": %s",
|
||||
LOG_REQ2_ARG (req),
|
||||
error->message);
|
||||
|
||||
if (g_error_matches (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_USER_CANCELED)) {
|
||||
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
|
||||
NM_AGENT_MANAGER_ERROR_USER_CANCELED,
|
||||
"User canceled the secrets request.");
|
||||
|
|
@ -808,17 +870,15 @@ get_done_cb (NMSecretAgent *agent,
|
|||
/* Ensure the setting we wanted secrets for got returned and has something in it */
|
||||
setting_secrets = g_variant_lookup_value (secrets, req->setting_name, NM_VARIANT_TYPE_SETTING);
|
||||
if (!setting_secrets || !g_variant_n_children (setting_secrets)) {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent returned no secrets for request %p/%s/%s",
|
||||
nm_secret_agent_get_description (agent),
|
||||
req, parent->detail, req->setting_name);
|
||||
_LOGD (agent, "agent returned no secrets for request "LOG_REQ2_FMT,
|
||||
LOG_REQ2_ARG (req));
|
||||
/* Try the next agent */
|
||||
request_next_agent (parent);
|
||||
return;
|
||||
}
|
||||
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent returned secrets for request %p/%s/%s",
|
||||
nm_secret_agent_get_description (agent),
|
||||
req, parent->detail, req->setting_name);
|
||||
_LOGD (agent, "agent returned secrets for request "LOG_REQ2_FMT,
|
||||
LOG_REQ2_ARG (req));
|
||||
|
||||
/* Get the agent's username */
|
||||
pw = getpwuid (nm_secret_agent_get_owner_uid (agent));
|
||||
|
|
@ -900,9 +960,8 @@ get_agent_request_secrets (ConnectionRequest *req, gboolean include_system_secre
|
|||
req->flags,
|
||||
get_done_cb,
|
||||
req);
|
||||
if (parent->current_call_id == NULL) {
|
||||
/* Shouldn't hit this, but handle it anyway */
|
||||
g_warn_if_fail (parent->current_call_id != NULL);
|
||||
if (!parent->current_call_id) {
|
||||
g_warn_if_reached ();
|
||||
request_next_agent (parent);
|
||||
}
|
||||
|
||||
|
|
@ -915,17 +974,19 @@ get_agent_modify_auth_cb (NMAuthChain *chain,
|
|||
GDBusMethodInvocation *context,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAgentManager *self;
|
||||
Request *parent = user_data;
|
||||
ConnectionRequest *req = user_data;
|
||||
const char *perm;
|
||||
|
||||
self = parent->self;
|
||||
|
||||
req->chain = NULL;
|
||||
|
||||
if (error) {
|
||||
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,
|
||||
error->code, error->message ? error->message : "(unknown)");
|
||||
_LOGD (parent->current, "agent "LOG_REQ2_FMT" MODIFY check error: (%d) %s",
|
||||
LOG_REQ2_ARG (req),
|
||||
error->code, error->message ? error->message : "(unknown)");
|
||||
/* Try the next agent */
|
||||
request_next_agent (parent);
|
||||
} else {
|
||||
|
|
@ -938,10 +999,9 @@ get_agent_modify_auth_cb (NMAuthChain *chain,
|
|||
if (nm_auth_chain_get_result (chain, perm) == NM_AUTH_CALL_RESULT_YES)
|
||||
req->current_has_modify = TRUE;
|
||||
|
||||
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");
|
||||
_LOGD (parent->current, "agent "LOG_REQ2_FMT" MODIFY check result %s",
|
||||
LOG_REQ2_ARG (req),
|
||||
req->current_has_modify ? "YES" : "NO");
|
||||
|
||||
get_agent_request_secrets (req, req->current_has_modify);
|
||||
}
|
||||
|
|
@ -995,10 +1055,13 @@ has_system_secrets (NMConnection *connection)
|
|||
static void
|
||||
get_next_cb (Request *parent)
|
||||
{
|
||||
NMAgentManager *self;
|
||||
ConnectionRequest *req = (ConnectionRequest *) parent;
|
||||
NMSettingConnection *s_con;
|
||||
const char *agent_dbus_owner, *perm;
|
||||
|
||||
self = parent->self;
|
||||
|
||||
req->current_has_modify = FALSE;
|
||||
|
||||
agent_dbus_owner = nm_secret_agent_get_dbus_owner (parent->current);
|
||||
|
|
@ -1011,8 +1074,8 @@ get_next_cb (Request *parent)
|
|||
*/
|
||||
if ( (req->flags != NM_SECRET_AGENT_GET_SECRETS_FLAG_NONE)
|
||||
&& (req->existing_secrets || has_system_secrets (req->connection))) {
|
||||
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);
|
||||
_LOGD (NULL, "("LOG_REQ2_FMT") request has system secrets; checking agent %s for MODIFY",
|
||||
LOG_REQ2_ARG (req), agent_dbus_owner);
|
||||
|
||||
req->chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (parent->current),
|
||||
NULL,
|
||||
|
|
@ -1034,8 +1097,8 @@ get_next_cb (Request *parent)
|
|||
|
||||
nm_auth_chain_add_call (req->chain, perm, TRUE);
|
||||
} else {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) requesting user-owned secrets from agent %s",
|
||||
req, parent->detail, req->setting_name, agent_dbus_owner);
|
||||
_LOGD (NULL, "("LOG_REQ2_FMT") requesting user-owned secrets from agent %s",
|
||||
LOG_REQ2_ARG (req), agent_dbus_owner);
|
||||
|
||||
get_agent_request_secrets (req, FALSE);
|
||||
}
|
||||
|
|
@ -1044,10 +1107,13 @@ get_next_cb (Request *parent)
|
|||
static gboolean
|
||||
get_start (gpointer user_data)
|
||||
{
|
||||
NMAgentManager *self;
|
||||
Request *parent = user_data;
|
||||
ConnectionRequest *req = user_data;
|
||||
GVariant *setting_secrets = NULL;
|
||||
|
||||
self = parent->self;
|
||||
|
||||
parent->idle_id = 0;
|
||||
|
||||
/* Check if there are any existing secrets */
|
||||
|
|
@ -1074,14 +1140,14 @@ get_start (gpointer user_data)
|
|||
/* Do we have everything we need? */
|
||||
if ( (req->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM)
|
||||
|| ((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);
|
||||
_LOGD (NULL, "("LOG_REQ2_FMT") system settings secrets sufficient",
|
||||
LOG_REQ2_ARG (req));
|
||||
|
||||
/* Got everything, we're done */
|
||||
req_complete_success (parent, req->existing_secrets, NULL, NULL);
|
||||
} else {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) system settings secrets insufficient, asking agents",
|
||||
req, parent->detail, req->setting_name);
|
||||
_LOGD (NULL, "("LOG_REQ2_FMT") system settings secrets insufficient, asking agents",
|
||||
LOG_REQ2_ARG (req));
|
||||
|
||||
/* We don't, so ask some agents for additional secrets */
|
||||
if ( req->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS
|
||||
|
|
@ -1180,7 +1246,8 @@ nm_agent_manager_get_secrets (NMAgentManager *self,
|
|||
* both returning NULL if they didn't hash anything.
|
||||
*/
|
||||
|
||||
req = connection_request_new_get (connection,
|
||||
req = connection_request_new_get (self,
|
||||
connection,
|
||||
subject,
|
||||
existing_secrets,
|
||||
setting_name,
|
||||
|
|
@ -1220,32 +1287,40 @@ nm_agent_manager_cancel_secrets (NMAgentManager *self,
|
|||
|
||||
static void
|
||||
save_done_cb (NMSecretAgent *agent,
|
||||
gconstpointer call_id,
|
||||
NMSecretAgentCallId call_id,
|
||||
GVariant *secrets,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
Request *parent = user_data;
|
||||
NMAgentManager *self;
|
||||
ConnectionRequest *req = user_data;
|
||||
Request *parent = (Request *) req;
|
||||
const char *agent_dbus_owner;
|
||||
|
||||
g_return_if_fail (call_id == parent->current_call_id);
|
||||
g_return_if_fail (agent == parent->current);
|
||||
|
||||
self = parent->self;
|
||||
|
||||
parent->current_call_id = NULL;
|
||||
|
||||
if (error) {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent failed save secrets request %p/%s: (%d) %s",
|
||||
nm_secret_agent_get_description (agent),
|
||||
req, parent->detail,
|
||||
error ? error->code : -1,
|
||||
(error && error->message) ? error->message : "(unknown)");
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||
_LOGD (agent, "save secrets request cancelled: "LOG_REQ_FMT,
|
||||
LOG_REQ_ARG (parent));
|
||||
return;
|
||||
}
|
||||
|
||||
_LOGD (agent, "agent failed save secrets request "LOG_REQ_FMT": %s",
|
||||
LOG_REQ_ARG (parent), error->message);
|
||||
/* Try the next agent */
|
||||
request_next_agent (parent);
|
||||
maybe_remove_agent_on_error (agent, error);
|
||||
return;
|
||||
}
|
||||
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent saved secrets for request %p/%s",
|
||||
nm_secret_agent_get_description (agent),
|
||||
req, parent->detail);
|
||||
_LOGD (agent, "agent saved secrets for request "LOG_REQ_FMT,
|
||||
LOG_REQ_ARG (parent));
|
||||
|
||||
agent_dbus_owner = nm_secret_agent_get_dbus_owner (agent);
|
||||
req_complete_success (parent, NULL, NULL, agent_dbus_owner);
|
||||
|
|
@ -1260,9 +1335,8 @@ save_next_cb (Request *parent)
|
|||
req->connection,
|
||||
save_done_cb,
|
||||
req);
|
||||
if (parent->current_call_id == NULL) {
|
||||
/* Shouldn't hit this, but handle it anyway */
|
||||
g_warn_if_fail (parent->current_call_id != NULL);
|
||||
if (!parent->current_call_id) {
|
||||
g_warn_if_reached ();
|
||||
request_next_agent (parent);
|
||||
}
|
||||
}
|
||||
|
|
@ -1296,7 +1370,8 @@ nm_agent_manager_save_secrets (NMAgentManager *self,
|
|||
nm_connection_get_path (connection),
|
||||
nm_connection_get_id (connection));
|
||||
|
||||
req = connection_request_new_other (connection,
|
||||
req = connection_request_new_other (self,
|
||||
connection,
|
||||
subject,
|
||||
"saving",
|
||||
save_complete_cb,
|
||||
|
|
@ -1315,23 +1390,33 @@ nm_agent_manager_save_secrets (NMAgentManager *self,
|
|||
|
||||
static void
|
||||
delete_done_cb (NMSecretAgent *agent,
|
||||
gconstpointer call_id,
|
||||
GVariant *secrets,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
NMSecretAgentCallId call_id,
|
||||
GVariant *secrets,
|
||||
GError *error,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMAgentManager *self;
|
||||
Request *req = user_data;
|
||||
|
||||
g_return_if_fail (call_id == req->current_call_id);
|
||||
g_return_if_fail (agent == req->current);
|
||||
|
||||
self = req->self;
|
||||
|
||||
req->current_call_id = NULL;
|
||||
|
||||
if (error) {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent failed delete secrets request %p/%s: (%d) %s",
|
||||
nm_secret_agent_get_description (agent), req, req->detail,
|
||||
error ? error->code : -1,
|
||||
(error && error->message) ? error->message : "(unknown)");
|
||||
if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
||||
_LOGD (agent, "delete secrets request cancelled: "LOG_REQ_FMT,
|
||||
LOG_REQ_ARG (req));
|
||||
return;
|
||||
}
|
||||
|
||||
_LOGD (agent, "agent failed delete secrets request "LOG_REQ_FMT": %s",
|
||||
LOG_REQ_ARG (req), error->message);
|
||||
} else {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) agent deleted secrets for request %p/%s",
|
||||
nm_secret_agent_get_description (agent), req, req->detail);
|
||||
_LOGD (agent, "agent deleted secrets for request "LOG_REQ_FMT,
|
||||
LOG_REQ_ARG (req));
|
||||
}
|
||||
|
||||
/* Tell the next agent to delete secrets */
|
||||
|
|
@ -1349,9 +1434,8 @@ delete_next_cb (Request *parent)
|
|||
req->connection,
|
||||
delete_done_cb,
|
||||
req);
|
||||
if (parent->current_call_id == NULL) {
|
||||
/* Shouldn't hit this, but handle it anyway */
|
||||
g_warn_if_fail (parent->current_call_id != NULL);
|
||||
if (!parent->current_call_id) {
|
||||
g_warn_if_reached ();
|
||||
request_next_agent (parent);
|
||||
}
|
||||
}
|
||||
|
|
@ -1386,7 +1470,8 @@ nm_agent_manager_delete_secrets (NMAgentManager *self,
|
|||
nm_connection_get_id (connection));
|
||||
|
||||
subject = nm_auth_subject_new_internal ();
|
||||
req = connection_request_new_other (connection,
|
||||
req = connection_request_new_other (self,
|
||||
connection,
|
||||
subject,
|
||||
"deleting",
|
||||
delete_complete_cb,
|
||||
|
|
@ -1464,12 +1549,10 @@ agent_permissions_changed_done (NMAuthChain *chain,
|
|||
agent = nm_auth_chain_get_data (chain, "agent");
|
||||
g_assert (agent);
|
||||
|
||||
if (error) {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) failed to request updated agent permissions",
|
||||
nm_secret_agent_get_description (agent));
|
||||
} else {
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s) updated agent permissions",
|
||||
nm_secret_agent_get_description (agent));
|
||||
if (error)
|
||||
_LOGD (agent, "failed to request updated agent permissions");
|
||||
else {
|
||||
_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;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,26 @@
|
|||
|
||||
#include "nmdbus-secret-agent.h"
|
||||
|
||||
#define _NMLOG_PREFIX_NAME "secret-agent"
|
||||
#define _NMLOG_DOMAIN LOGD_AGENTS
|
||||
#define _NMLOG(level, ...) \
|
||||
G_STMT_START { \
|
||||
if (nm_logging_enabled ((level), (_NMLOG_DOMAIN))) { \
|
||||
char __prefix[32]; \
|
||||
\
|
||||
if ((self)) \
|
||||
g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", ""_NMLOG_PREFIX_NAME"", (self)); \
|
||||
else \
|
||||
g_strlcpy (__prefix, _NMLOG_PREFIX_NAME, sizeof (__prefix)); \
|
||||
_nm_log ((level), (_NMLOG_DOMAIN), 0, \
|
||||
"%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \
|
||||
__prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
|
||||
} \
|
||||
} G_STMT_END
|
||||
|
||||
#define LOG_REQ_FMT "req[%p,%s,%s%s%s%s]"
|
||||
#define LOG_REQ_ARG(req) (req), (req)->dbus_command, NM_PRINT_FMT_QUOTE_STRING ((req)->path), ((req)->cancellable ? "" : " (cancelled)")
|
||||
|
||||
G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT)
|
||||
|
||||
#define NM_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
|
||||
|
|
@ -45,11 +65,14 @@ typedef struct {
|
|||
char *owner_username;
|
||||
char *dbus_owner;
|
||||
NMSecretAgentCapabilities capabilities;
|
||||
guint32 hash;
|
||||
|
||||
GSList *permissions;
|
||||
|
||||
NMDBusSecretAgent *proxy;
|
||||
NMBusManager *bus_mgr;
|
||||
GDBusConnection *connection;
|
||||
gboolean connection_is_private;
|
||||
guint on_disconnected_id;
|
||||
|
||||
GHashTable *requests;
|
||||
} NMSecretAgentPrivate;
|
||||
|
|
@ -63,17 +86,22 @@ static guint signals[LAST_SIGNAL] = { 0 };
|
|||
|
||||
/*************************************************************/
|
||||
|
||||
typedef struct {
|
||||
struct _NMSecretAgentCallId {
|
||||
NMSecretAgent *agent;
|
||||
GCancellable *cancellable;
|
||||
char *path;
|
||||
const char *dbus_command;
|
||||
char *setting_name;
|
||||
gboolean is_get_secrets;
|
||||
NMSecretAgentCallback callback;
|
||||
gpointer callback_data;
|
||||
} Request;
|
||||
};
|
||||
|
||||
typedef struct _NMSecretAgentCallId Request;
|
||||
|
||||
static Request *
|
||||
request_new (NMSecretAgent *agent,
|
||||
request_new (NMSecretAgent *self,
|
||||
const char *dbus_command, /* this must be a static string. */
|
||||
const char *path,
|
||||
const char *setting_name,
|
||||
NMSecretAgentCallback callback,
|
||||
|
|
@ -82,26 +110,60 @@ request_new (NMSecretAgent *agent,
|
|||
Request *r;
|
||||
|
||||
r = g_slice_new0 (Request);
|
||||
r->agent = agent;
|
||||
r->agent = self;
|
||||
r->path = g_strdup (path);
|
||||
r->setting_name = g_strdup (setting_name);
|
||||
r->dbus_command = dbus_command,
|
||||
r->callback = callback;
|
||||
r->callback_data = callback_data;
|
||||
r->cancellable = g_cancellable_new ();
|
||||
_LOGT ("request "LOG_REQ_FMT": created", LOG_REQ_ARG (r));
|
||||
return r;
|
||||
}
|
||||
#define request_new(self,dbus_command,path,setting_name,callback,callback_data) request_new(self,""dbus_command"",path,setting_name,callback,callback_data)
|
||||
|
||||
static void
|
||||
request_free (Request *r)
|
||||
{
|
||||
NMSecretAgent *self = r->agent;
|
||||
|
||||
_LOGT ("request "LOG_REQ_FMT": destroyed", LOG_REQ_ARG (r));
|
||||
g_free (r->path);
|
||||
g_free (r->setting_name);
|
||||
g_object_unref (r->cancellable);
|
||||
if (r->cancellable)
|
||||
g_object_unref (r->cancellable);
|
||||
g_slice_free (Request, r);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
request_check_return (Request *r)
|
||||
{
|
||||
NMSecretAgentPrivate *priv;
|
||||
|
||||
if (!r->cancellable)
|
||||
return FALSE;
|
||||
|
||||
g_return_val_if_fail (NM_IS_SECRET_AGENT (r->agent), FALSE);
|
||||
|
||||
priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent);
|
||||
|
||||
if (!g_hash_table_remove (priv->requests, r))
|
||||
g_return_val_if_reached (FALSE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static char *
|
||||
_create_description (const char *dbus_owner, const char *identifier, gulong uid)
|
||||
{
|
||||
return g_strdup_printf ("%s/%s/%lu",
|
||||
dbus_owner,
|
||||
identifier,
|
||||
uid);
|
||||
}
|
||||
|
||||
const char *
|
||||
nm_secret_agent_get_description (NMSecretAgent *agent)
|
||||
{
|
||||
|
|
@ -111,10 +173,9 @@ nm_secret_agent_get_description (NMSecretAgent *agent)
|
|||
|
||||
priv = NM_SECRET_AGENT_GET_PRIVATE (agent);
|
||||
if (!priv->description) {
|
||||
priv->description = g_strdup_printf ("%s/%s/%lu",
|
||||
priv->dbus_owner,
|
||||
priv->identifier,
|
||||
nm_auth_subject_get_unix_process_uid (priv->subject));
|
||||
priv->description = _create_description (priv->dbus_owner,
|
||||
priv->identifier,
|
||||
nm_auth_subject_get_unix_process_uid (priv->subject));
|
||||
}
|
||||
|
||||
return priv->description;
|
||||
|
|
@ -168,14 +229,6 @@ nm_secret_agent_get_capabilities (NMSecretAgent *agent)
|
|||
return NM_SECRET_AGENT_GET_PRIVATE (agent)->capabilities;
|
||||
}
|
||||
|
||||
guint32
|
||||
nm_secret_agent_get_hash (NMSecretAgent *agent)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), 0);
|
||||
|
||||
return NM_SECRET_AGENT_GET_PRIVATE (agent)->hash;
|
||||
}
|
||||
|
||||
NMAuthSubject *
|
||||
nm_secret_agent_get_subject (NMSecretAgent *agent)
|
||||
{
|
||||
|
|
@ -262,24 +315,22 @@ get_callback (GObject *proxy,
|
|||
gpointer user_data)
|
||||
{
|
||||
Request *r = user_data;
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent);
|
||||
GVariant *secrets = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_cancellable_is_cancelled (r->cancellable)) {
|
||||
if (request_check_return (r)) {
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent);
|
||||
gs_free_error GError *error = NULL;
|
||||
gs_unref_variant GVariant *secrets = NULL;
|
||||
|
||||
nmdbus_secret_agent_call_get_secrets_finish (priv->proxy, &secrets, result, &error);
|
||||
if (error)
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
|
||||
r->callback (r->agent, r, secrets, error, r->callback_data);
|
||||
g_clear_pointer (&secrets, g_variant_unref);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
g_hash_table_remove (priv->requests, r);
|
||||
request_free (r);
|
||||
}
|
||||
|
||||
gconstpointer
|
||||
NMSecretAgentCallId
|
||||
nm_secret_agent_get_secrets (NMSecretAgent *self,
|
||||
NMConnection *connection,
|
||||
const char *setting_name,
|
||||
|
|
@ -306,7 +357,9 @@ nm_secret_agent_get_secrets (NMSecretAgent *self,
|
|||
flags &= ~NM_SECRET_AGENT_GET_SECRETS_FLAG_ONLY_SYSTEM;
|
||||
flags &= ~NM_SECRET_AGENT_GET_SECRETS_FLAG_NO_ERRORS;
|
||||
|
||||
r = request_new (self, nm_connection_get_path (connection), setting_name, callback, callback_data);
|
||||
r = request_new (self, "GetSecrets", nm_connection_get_path (connection), setting_name, callback, callback_data);
|
||||
r->is_get_secrets = TRUE;
|
||||
g_hash_table_add (priv->requests, r);
|
||||
nmdbus_secret_agent_call_get_secrets (priv->proxy,
|
||||
dict,
|
||||
nm_connection_get_path (connection),
|
||||
|
|
@ -315,11 +368,12 @@ nm_secret_agent_get_secrets (NMSecretAgent *self,
|
|||
flags,
|
||||
r->cancellable,
|
||||
get_callback, r);
|
||||
g_hash_table_insert (priv->requests, r, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static void
|
||||
cancel_done (GObject *proxy, GAsyncResult *result, gpointer user_data)
|
||||
{
|
||||
|
|
@ -327,33 +381,85 @@ cancel_done (GObject *proxy, GAsyncResult *result, gpointer user_data)
|
|||
GError *error = NULL;
|
||||
|
||||
if (!nmdbus_secret_agent_call_cancel_get_secrets_finish (NMDBUS_SECRET_AGENT (proxy), result, &error)) {
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
nm_log_dbg (LOGD_AGENTS, "(%s): agent failed to cancel secrets: %s",
|
||||
description, error->message);
|
||||
nm_log_dbg (LOGD_AGENTS, "%s%s%s: agent failed to cancel secrets: %s",
|
||||
NM_PRINT_FMT_QUOTED (description, "(", description, ")", "???"),
|
||||
error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
g_free (description);
|
||||
}
|
||||
|
||||
static void
|
||||
do_cancel_secrets (NMSecretAgent *self, Request *r, gboolean disposing)
|
||||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
GCancellable *cancellable;
|
||||
NMSecretAgentCallback callback;
|
||||
gpointer callback_data;
|
||||
|
||||
g_return_if_fail (r->agent == self);
|
||||
g_return_if_fail (r->cancellable);
|
||||
|
||||
if ( r->is_get_secrets
|
||||
&& priv->proxy) {
|
||||
/* for GetSecrets call, we must cancel the request. */
|
||||
nmdbus_secret_agent_call_cancel_get_secrets (priv->proxy,
|
||||
r->path, r->setting_name,
|
||||
NULL,
|
||||
cancel_done,
|
||||
g_strdup (nm_secret_agent_get_description (self)));
|
||||
}
|
||||
|
||||
cancellable = r->cancellable;
|
||||
callback = r->callback;
|
||||
callback_data = r->callback_data;
|
||||
|
||||
/* During g_cancellable_cancel() the d-bus method might return synchronously.
|
||||
* Clear r->cancellable first, so that it doesn't actually do anything.
|
||||
* After that, @r might be already freed. */
|
||||
r->cancellable = NULL;
|
||||
g_cancellable_cancel (cancellable);
|
||||
g_object_unref (cancellable);
|
||||
|
||||
/* Don't free the request @r. It will be freed when the d-bus call returns.
|
||||
* Only clear r->cancellable to indicate that the request was cancelled. */
|
||||
|
||||
if (callback) {
|
||||
GError *error = NULL;
|
||||
|
||||
if (disposing) {
|
||||
/* hijack an error code. G_IO_ERROR_CANCELLED is only used synchronously
|
||||
* when the user calls nm_act_request_cancel_secrets().
|
||||
* When the user disposes the instance, we also invoke the callback synchronously,
|
||||
* but with a different error-reason. */
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Disposing NMSecretAgent instance");
|
||||
} else {
|
||||
g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
|
||||
"Request cancelled");
|
||||
}
|
||||
/* @r might be a dangling pointer at this point. However, that is no problem
|
||||
* to pass it as (opaque) call_id. */
|
||||
callback (self, r, NULL, error, callback_data);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nm_secret_agent_cancel_secrets (NMSecretAgent *self, gconstpointer call)
|
||||
nm_secret_agent_cancel_secrets (NMSecretAgent *self, NMSecretAgentCallId call_id)
|
||||
{
|
||||
NMSecretAgentPrivate *priv;
|
||||
Request *r = (gpointer) call;
|
||||
Request *r = call_id;
|
||||
|
||||
g_return_if_fail (NM_IS_SECRET_AGENT (self));
|
||||
g_return_if_fail (r);
|
||||
|
||||
g_return_if_fail (self != NULL);
|
||||
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
g_return_if_fail (priv->proxy != NULL);
|
||||
g_return_if_fail (r != NULL);
|
||||
if (!g_hash_table_remove (priv->requests, r))
|
||||
g_return_if_reached ();
|
||||
|
||||
g_cancellable_cancel (r->cancellable);
|
||||
|
||||
nmdbus_secret_agent_call_cancel_get_secrets (priv->proxy,
|
||||
r->path, r->setting_name,
|
||||
NULL,
|
||||
cancel_done,
|
||||
g_strdup (nm_secret_agent_get_description (self)));
|
||||
do_cancel_secrets (self, r, FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
|
@ -364,21 +470,21 @@ agent_save_cb (GObject *proxy,
|
|||
gpointer user_data)
|
||||
{
|
||||
Request *r = user_data;
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_cancellable_is_cancelled (r->cancellable)) {
|
||||
if (request_check_return (r)) {
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent);
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
nmdbus_secret_agent_call_save_secrets_finish (priv->proxy, result, &error);
|
||||
if (error)
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
r->callback (r->agent, r, NULL, error, r->callback_data);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
g_hash_table_remove (priv->requests, r);
|
||||
request_free (r);
|
||||
}
|
||||
|
||||
gconstpointer
|
||||
NMSecretAgentCallId
|
||||
nm_secret_agent_save_secrets (NMSecretAgent *self,
|
||||
NMConnection *connection,
|
||||
NMSecretAgentCallback callback,
|
||||
|
|
@ -398,35 +504,39 @@ nm_secret_agent_save_secrets (NMSecretAgent *self,
|
|||
/* Caller should have ensured that only agent-owned secrets exist in 'connection' */
|
||||
dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
|
||||
|
||||
r = request_new (self, cpath, NULL, callback, callback_data);
|
||||
r = request_new (self, "SaveSecrets", cpath, NULL, callback, callback_data);
|
||||
g_hash_table_add (priv->requests, r);
|
||||
nmdbus_secret_agent_call_save_secrets (priv->proxy,
|
||||
dict, cpath,
|
||||
NULL,
|
||||
NULL, /* cancelling the request does *not* cancel the D-Bus call. */
|
||||
agent_save_cb, r);
|
||||
g_hash_table_insert (priv->requests, r, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static void
|
||||
agent_delete_cb (GObject *proxy,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
Request *r = user_data;
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent);
|
||||
GError *error = NULL;
|
||||
|
||||
if (!g_cancellable_is_cancelled (r->cancellable)) {
|
||||
if (request_check_return (r)) {
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (r->agent);
|
||||
gs_free_error GError *error = NULL;
|
||||
|
||||
nmdbus_secret_agent_call_delete_secrets_finish (priv->proxy, result, &error);
|
||||
if (error)
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
r->callback (r->agent, r, NULL, error, r->callback_data);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
g_hash_table_remove (priv->requests, r);
|
||||
request_free (r);
|
||||
}
|
||||
|
||||
gconstpointer
|
||||
NMSecretAgentCallId
|
||||
nm_secret_agent_delete_secrets (NMSecretAgent *self,
|
||||
NMConnection *connection,
|
||||
NMSecretAgentCallback callback,
|
||||
|
|
@ -446,34 +556,80 @@ nm_secret_agent_delete_secrets (NMSecretAgent *self,
|
|||
/* No secrets sent; agents must be smart enough to track secrets using the UUID or something */
|
||||
dict = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_NO_SECRETS);
|
||||
|
||||
r = request_new (self, cpath, NULL, callback, callback_data);
|
||||
r = request_new (self, "DeleteSecrets", cpath, NULL, callback, callback_data);
|
||||
g_hash_table_add (priv->requests, r);
|
||||
nmdbus_secret_agent_call_delete_secrets (priv->proxy,
|
||||
dict, cpath,
|
||||
NULL,
|
||||
NULL, /* cancelling the request does *not* cancel the D-Bus call. */
|
||||
agent_delete_cb, r);
|
||||
g_hash_table_insert (priv->requests, r, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static void
|
||||
name_owner_changed_cb (GObject *proxy,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
_on_disconnected_cleanup (NMSecretAgentPrivate *priv)
|
||||
{
|
||||
if (priv->on_disconnected_id) {
|
||||
if (priv->connection_is_private) {
|
||||
g_signal_handler_disconnect (priv->bus_mgr,
|
||||
priv->on_disconnected_id);
|
||||
} else {
|
||||
g_dbus_connection_signal_unsubscribe (priv->connection,
|
||||
priv->on_disconnected_id);
|
||||
}
|
||||
priv->on_disconnected_id = 0;
|
||||
}
|
||||
|
||||
g_clear_object (&priv->connection);
|
||||
g_clear_object (&priv->proxy);
|
||||
g_clear_object (&priv->bus_mgr);
|
||||
}
|
||||
|
||||
static void
|
||||
_on_disconnected_private_connection (NMBusManager *mgr,
|
||||
GDBusConnection *connection,
|
||||
NMSecretAgent *self)
|
||||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
|
||||
if (priv->connection != connection)
|
||||
return;
|
||||
|
||||
_LOGT ("private connection disconnected");
|
||||
|
||||
_on_disconnected_cleanup (priv);
|
||||
g_signal_emit (self, signals[DISCONNECTED], 0);
|
||||
}
|
||||
|
||||
static void
|
||||
_on_disconnected_name_owner_changed (GDBusConnection *connection,
|
||||
const gchar *sender_name,
|
||||
const gchar *object_path,
|
||||
const gchar *interface_name,
|
||||
const gchar *signal_name,
|
||||
GVariant *parameters,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSecretAgent *self = NM_SECRET_AGENT (user_data);
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
char *owner;
|
||||
const char *old_owner, *new_owner;
|
||||
|
||||
owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (proxy));
|
||||
if (!owner) {
|
||||
g_signal_handlers_disconnect_by_func (priv->proxy, name_owner_changed_cb, self);
|
||||
g_clear_object (&priv->proxy);
|
||||
g_variant_get (parameters,
|
||||
"(&s&s&s)",
|
||||
NULL,
|
||||
&old_owner,
|
||||
&new_owner);
|
||||
|
||||
_LOGT ("name-owner-changed: %s%s%s => %s%s%s",
|
||||
NM_PRINT_FMT_QUOTE_STRING (old_owner),
|
||||
NM_PRINT_FMT_QUOTE_STRING (new_owner));
|
||||
|
||||
if (!*new_owner) {
|
||||
_on_disconnected_cleanup (priv);
|
||||
g_signal_emit (self, signals[DISCONNECTED], 0);
|
||||
|
||||
g_clear_pointer (&priv->dbus_owner, g_free);
|
||||
} else
|
||||
g_free (owner);
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
|
@ -486,44 +642,83 @@ nm_secret_agent_new (GDBusMethodInvocation *context,
|
|||
{
|
||||
NMSecretAgent *self;
|
||||
NMSecretAgentPrivate *priv;
|
||||
char *hash_str;
|
||||
const char *dbus_owner;
|
||||
struct passwd *pw;
|
||||
GDBusProxy *proxy;
|
||||
char *owner_username = NULL;
|
||||
char *description = NULL;
|
||||
char buf_subject[64];
|
||||
gulong uid;
|
||||
GDBusConnection *connection;
|
||||
|
||||
g_return_val_if_fail (context != NULL, NULL);
|
||||
g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
|
||||
g_return_val_if_fail (nm_auth_subject_is_unix_process (subject), NULL);
|
||||
g_return_val_if_fail (identifier != NULL, NULL);
|
||||
|
||||
pw = getpwuid (nm_auth_subject_get_unix_process_uid (subject));
|
||||
g_return_val_if_fail (pw != NULL, NULL);
|
||||
g_return_val_if_fail (pw->pw_name[0] != '\0', NULL);
|
||||
connection = g_dbus_method_invocation_get_connection (context);
|
||||
|
||||
g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
|
||||
|
||||
uid = nm_auth_subject_get_unix_process_uid (subject);
|
||||
|
||||
pw = getpwuid (uid);
|
||||
if (pw && pw->pw_name && pw->pw_name[0])
|
||||
owner_username = g_strdup (pw->pw_name);
|
||||
|
||||
dbus_owner = nm_auth_subject_get_unix_process_dbus_sender (subject);
|
||||
|
||||
self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL);
|
||||
|
||||
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
|
||||
priv->bus_mgr = g_object_ref (nm_bus_manager_get ());
|
||||
priv->connection = g_object_ref (connection);
|
||||
priv->connection_is_private = nm_bus_manager_connection_is_private (priv->bus_mgr, connection);
|
||||
|
||||
_LOGT ("constructed: %s, owner=%s%s%s (%s), private-connection=%d, unique-name=%s%s%s",
|
||||
(description = _create_description (dbus_owner, identifier, uid)),
|
||||
NM_PRINT_FMT_QUOTE_STRING (owner_username),
|
||||
nm_auth_subject_to_string (subject, buf_subject, sizeof (buf_subject)),
|
||||
priv->connection_is_private,
|
||||
NM_PRINT_FMT_QUOTE_STRING (g_dbus_connection_get_unique_name (priv->connection)));
|
||||
|
||||
priv->identifier = g_strdup (identifier);
|
||||
priv->owner_username = g_strdup (pw->pw_name);
|
||||
priv->dbus_owner = g_strdup (nm_auth_subject_get_unix_process_dbus_sender (subject));
|
||||
priv->owner_username = owner_username;
|
||||
priv->dbus_owner = g_strdup (dbus_owner);
|
||||
priv->description = description;
|
||||
priv->capabilities = capabilities;
|
||||
priv->subject = g_object_ref (subject);
|
||||
|
||||
hash_str = g_strdup_printf ("%16lu%s", nm_auth_subject_get_unix_process_uid (subject), identifier);
|
||||
priv->hash = g_str_hash (hash_str);
|
||||
g_free (hash_str);
|
||||
|
||||
proxy = nm_bus_manager_new_proxy (nm_bus_manager_get (),
|
||||
context,
|
||||
proxy = nm_bus_manager_new_proxy (priv->bus_mgr,
|
||||
priv->connection,
|
||||
NMDBUS_TYPE_SECRET_AGENT_PROXY,
|
||||
priv->dbus_owner,
|
||||
NM_DBUS_PATH_SECRET_AGENT,
|
||||
NM_DBUS_INTERFACE_SECRET_AGENT);
|
||||
g_assert (proxy);
|
||||
g_signal_connect (proxy, "notify::g-name-owner",
|
||||
G_CALLBACK (name_owner_changed_cb),
|
||||
self);
|
||||
priv->proxy = NMDBUS_SECRET_AGENT (proxy);
|
||||
|
||||
/* we cannot subscribe to notify::g-name-owner because that doesn't work
|
||||
* for unique names and it doesn't work for private connections. */
|
||||
if (priv->connection_is_private) {
|
||||
priv->on_disconnected_id = g_signal_connect (priv->bus_mgr,
|
||||
NM_BUS_MANAGER_PRIVATE_CONNECTION_DISCONNECTED,
|
||||
G_CALLBACK (_on_disconnected_private_connection),
|
||||
self);
|
||||
} else {
|
||||
priv->on_disconnected_id = g_dbus_connection_signal_subscribe (priv->connection,
|
||||
"org.freedesktop.DBus", /* name */
|
||||
"org.freedesktop.DBus", /* interface */
|
||||
"NameOwnerChanged", /* signal name */
|
||||
"/org/freedesktop/DBus", /* path */
|
||||
priv->dbus_owner, /* arg0 */
|
||||
G_DBUS_SIGNAL_FLAGS_NONE,
|
||||
_on_disconnected_name_owner_changed,
|
||||
self,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
|
@ -532,16 +727,25 @@ nm_secret_agent_init (NMSecretAgent *self)
|
|||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
|
||||
priv->requests = g_hash_table_new_full (g_direct_hash, g_direct_equal,
|
||||
NULL, (GDestroyNotify) request_free);
|
||||
priv->requests = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object);
|
||||
NMSecretAgent *self = NM_SECRET_AGENT (object);
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
GHashTableIter iter;
|
||||
Request *r;
|
||||
|
||||
g_hash_table_iter_init (&iter, priv->requests);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &r, NULL)) {
|
||||
g_hash_table_iter_remove (&iter);
|
||||
do_cancel_secrets (self, r, TRUE);
|
||||
}
|
||||
|
||||
_on_disconnected_cleanup (priv);
|
||||
|
||||
g_clear_object (&priv->proxy);
|
||||
g_clear_object (&priv->subject);
|
||||
|
||||
G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object);
|
||||
|
|
@ -550,16 +754,20 @@ dispose (GObject *object)
|
|||
static void
|
||||
finalize (GObject *object)
|
||||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object);
|
||||
NMSecretAgent *self = NM_SECRET_AGENT (object);
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
|
||||
g_free (priv->description);
|
||||
g_free (priv->identifier);
|
||||
g_free (priv->owner_username);
|
||||
g_free (priv->dbus_owner);
|
||||
|
||||
g_slist_free_full (priv->permissions, g_free);
|
||||
g_hash_table_destroy (priv->requests);
|
||||
|
||||
G_OBJECT_CLASS (nm_secret_agent_parent_class)->finalize (object);
|
||||
|
||||
_LOGT ("finalized");
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ typedef struct {
|
|||
void (*disconnected) (NMSecretAgent *self);
|
||||
} NMSecretAgentClass;
|
||||
|
||||
typedef struct _NMSecretAgentCallId *NMSecretAgentCallId;
|
||||
|
||||
GType nm_secret_agent_get_type (void);
|
||||
|
||||
NMSecretAgent *nm_secret_agent_new (GDBusMethodInvocation *context,
|
||||
|
|
@ -64,8 +66,6 @@ gulong nm_secret_agent_get_pid (NMSecretAgent *agent);
|
|||
|
||||
NMSecretAgentCapabilities nm_secret_agent_get_capabilities (NMSecretAgent *agent);
|
||||
|
||||
guint32 nm_secret_agent_get_hash (NMSecretAgent *agent);
|
||||
|
||||
NMAuthSubject *nm_secret_agent_get_subject (NMSecretAgent *agent);
|
||||
|
||||
void nm_secret_agent_add_permission (NMSecretAgent *agent,
|
||||
|
|
@ -76,30 +76,30 @@ gboolean nm_secret_agent_has_permission (NMSecretAgent *agent,
|
|||
const char *permission);
|
||||
|
||||
typedef void (*NMSecretAgentCallback) (NMSecretAgent *agent,
|
||||
gconstpointer call,
|
||||
NMSecretAgentCallId call_id,
|
||||
GVariant *new_secrets, /* NULL for save & delete */
|
||||
GError *error,
|
||||
gpointer user_data);
|
||||
|
||||
gconstpointer nm_secret_agent_get_secrets (NMSecretAgent *agent,
|
||||
NMConnection *connection,
|
||||
const char *setting_name,
|
||||
const char **hints,
|
||||
NMSecretAgentGetSecretsFlags flags,
|
||||
NMSecretAgentCallback callback,
|
||||
gpointer callback_data);
|
||||
NMSecretAgentCallId nm_secret_agent_get_secrets (NMSecretAgent *agent,
|
||||
NMConnection *connection,
|
||||
const char *setting_name,
|
||||
const char **hints,
|
||||
NMSecretAgentGetSecretsFlags flags,
|
||||
NMSecretAgentCallback callback,
|
||||
gpointer callback_data);
|
||||
|
||||
void nm_secret_agent_cancel_secrets (NMSecretAgent *agent,
|
||||
gconstpointer call_id);
|
||||
NMSecretAgentCallId call_id);
|
||||
|
||||
gconstpointer nm_secret_agent_save_secrets (NMSecretAgent *agent,
|
||||
NMConnection *connection,
|
||||
NMSecretAgentCallback callback,
|
||||
gpointer callback_data);
|
||||
NMSecretAgentCallId nm_secret_agent_save_secrets (NMSecretAgent *agent,
|
||||
NMConnection *connection,
|
||||
NMSecretAgentCallback callback,
|
||||
gpointer callback_data);
|
||||
|
||||
gconstpointer nm_secret_agent_delete_secrets (NMSecretAgent *agent,
|
||||
NMConnection *connection,
|
||||
NMSecretAgentCallback callback,
|
||||
gpointer callback_data);
|
||||
NMSecretAgentCallId nm_secret_agent_delete_secrets (NMSecretAgent *agent,
|
||||
NMConnection *connection,
|
||||
NMSecretAgentCallback callback,
|
||||
gpointer callback_data);
|
||||
|
||||
#endif /* __NETWORKMANAGER_SECRET_AGENT_H__ */
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue