libnm-glib: add secret agent base class
This commit is contained in:
@@ -55,6 +55,9 @@
|
||||
#define NM_DBUS_INTERFACE_AGENT_MANAGER NM_DBUS_INTERFACE ".AgentManager"
|
||||
#define NM_DBUS_PATH_AGENT_MANAGER "/org/freedesktop/NetworkManager/AgentManager"
|
||||
|
||||
#define NM_DBUS_INTERFACE_SECRET_AGENT NM_DBUS_INTERFACE ".SecretAgent"
|
||||
#define NM_DBUS_PATH_SECRET_AGENT "/org/freedesktop/NetworkManager/SecretAgent"
|
||||
|
||||
/*
|
||||
* Types of NetworkManager states
|
||||
*/
|
||||
|
106
introspection/nm-secret-agent.xml
Normal file
106
introspection/nm-secret-agent.xml
Normal file
@@ -0,0 +1,106 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
|
||||
<node name="/" xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0">
|
||||
|
||||
<interface name="org.freedesktop.NetworkManager.SecretAgent">
|
||||
<tp:docstring>
|
||||
Private D-Bus interface used by secret agents that store and provide
|
||||
secrets to NetworkManager.
|
||||
</tp:docstring>
|
||||
|
||||
<method name="GetSecrets">
|
||||
<tp:docstring>
|
||||
Retrieve and return stored secrets, if any, or request new
|
||||
secrets from the agent's user.
|
||||
</tp:docstring>
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_secret_agent_get_secrets"/>
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="connection" type="a{sa{sv}}" direction="out" tp:type="String_String_Variant_Map_Map">
|
||||
<tp:docstring>
|
||||
Nested settings maps containing the connection for which
|
||||
secrets are being requested.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
<arg name="connection_path" type="o" direction="in">
|
||||
<tp:docstring>
|
||||
Object path of the connection for which secrets are being
|
||||
requested.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
<arg name="setting_name" type="s" direction="in">
|
||||
<tp:docstring>
|
||||
Setting name for which secrets are being requested.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
<arg name="hints" type="as" direction="in">
|
||||
<tp:docstring>
|
||||
Array of strings of key names in the requested setting for
|
||||
which NetworkManager thinks a secrets may be required. The
|
||||
Agent should return any secrets it has, or that it thinks
|
||||
are required, regardless of what hints NetworkManager sends
|
||||
in this request.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
<arg name="request_new" type="b" direction="in">
|
||||
<tp:docstring>
|
||||
If true, new secrets are assumed to be invalid or incorrect,
|
||||
and the agent should ask the user for new secrets. If false,
|
||||
existing secrets should be retrieved from storage and
|
||||
returned without interrupting the user.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
|
||||
<arg name="secrets" type="a{sa{sv}}" direction="out" tp:type="String_String_Variant_Map_Map">
|
||||
<tp:docstring>
|
||||
Nested settings maps containing secrets. Each setting MUST
|
||||
contain at least the 'name' field, containing the name of
|
||||
the setting, and one or more secrets.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
</method>
|
||||
|
||||
<method name="SaveSecrets">
|
||||
<tp:docstring>
|
||||
Save given secrets to backing storage.
|
||||
</tp:docstring>
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_secret_agent_save_secrets"/>
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="connection" type="a{sa{sv}}" direction="out" tp:type="String_String_Variant_Map_Map">
|
||||
<tp:docstring>
|
||||
Nested settings maps containing the entire connection
|
||||
(including secrets), for which the agent should save the
|
||||
secrets to backing storage.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
<arg name="connection_path" type="o" direction="in">
|
||||
<tp:docstring>
|
||||
Object path of the connection for which the agent should
|
||||
save secrets to backing storage.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
</method>
|
||||
|
||||
<method name="DeleteSecrets">
|
||||
<tp:docstring>
|
||||
Delete secrets from backing storage.
|
||||
</tp:docstring>
|
||||
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_secret_agent_delete_secrets"/>
|
||||
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
|
||||
<arg name="connection" type="a{sa{sv}}" direction="out" tp:type="String_String_Variant_Map_Map">
|
||||
<tp:docstring>
|
||||
Nested settings maps containing the entire connection
|
||||
(including secrets), for which the agent should delete the
|
||||
secrets from backing storage.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
<arg name="connection_path" type="o" direction="in">
|
||||
<tp:docstring>
|
||||
Object path of the connection for which the agent should
|
||||
delete secrets from backing storage.
|
||||
</tp:docstring>
|
||||
</arg>
|
||||
</method>
|
||||
|
||||
</interface>
|
||||
|
||||
</node>
|
@@ -18,7 +18,8 @@ BUILT_SOURCES = \
|
||||
nm-ip4-config-bindings.h \
|
||||
nm-dhcp4-config-bindings.h \
|
||||
nm-ip6-config-bindings.h \
|
||||
nm-dhcp6-config-bindings.h
|
||||
nm-dhcp6-config-bindings.h \
|
||||
nm-secret-agent-glue.h
|
||||
|
||||
#####################################################
|
||||
# Deprecated original libnm_glib bits
|
||||
@@ -76,7 +77,8 @@ libnminclude_HEADERS = \
|
||||
nm-ip6-config.h \
|
||||
nm-dhcp6-config.h \
|
||||
nm-remote-connection.h \
|
||||
nm-remote-settings.h
|
||||
nm-remote-settings.h \
|
||||
nm-secret-agent.h
|
||||
|
||||
libnm_glib_la_SOURCES = \
|
||||
nm-object.c \
|
||||
@@ -105,7 +107,8 @@ libnm_glib_la_SOURCES = \
|
||||
nm-dhcp6-config.c \
|
||||
nm-remote-connection.c \
|
||||
nm-remote-connection-private.h \
|
||||
nm-remote-settings.c
|
||||
nm-remote-settings.c \
|
||||
nm-secret-agent.c
|
||||
|
||||
libnm_glib_la_LIBADD = \
|
||||
$(top_builddir)/libnm-util/libnm-util.la \
|
||||
@@ -178,6 +181,9 @@ nm-ip6-config-bindings.h: $(top_srcdir)/introspection/nm-ip6-config.xml
|
||||
nm-dhcp6-config-bindings.h: $(top_srcdir)/introspection/nm-dhcp6-config.xml
|
||||
$(AM_V_GEN) dbus-binding-tool --prefix=nm_dhcp6_config --mode=glib-client --output=$@ $<
|
||||
|
||||
nm-secret-agent-glue.h: $(top_srcdir)/introspection/nm-secret-agent.xml
|
||||
$(AM_V_GEN) dbus-binding-tool --prefix=nm_secret_agent --mode=glib-server --output=$@ $<
|
||||
|
||||
pkgconfigdir = $(libdir)/pkgconfig
|
||||
pkgconfig_DATA = libnm-glib.pc libnm-glib-vpn.pc
|
||||
|
||||
|
638
libnm-glib/nm-secret-agent.c
Normal file
638
libnm-glib/nm-secret-agent.c
Normal file
@@ -0,0 +1,638 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* (C) Copyright 2010 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <NetworkManager.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
|
||||
#include "nm-secret-agent.h"
|
||||
#include "nm-marshal.h"
|
||||
#include "NetworkManager.h"
|
||||
|
||||
static void impl_secret_agent_get_secrets (NMSecretAgent *self,
|
||||
GHashTable *connection_hash,
|
||||
const char *connection_path,
|
||||
const char *setting_name,
|
||||
const char **hints,
|
||||
gboolean request_new,
|
||||
DBusGMethodInvocation *context);
|
||||
|
||||
static void impl_secret_agent_save_secrets (NMSecretAgent *self,
|
||||
GHashTable *connection_hash,
|
||||
const char *connection_path,
|
||||
DBusGMethodInvocation *context);
|
||||
|
||||
static void impl_secret_agent_delete_secrets (NMSecretAgent *self,
|
||||
GHashTable *connection_hash,
|
||||
const char *connection_path,
|
||||
DBusGMethodInvocation *context);
|
||||
|
||||
#include "nm-secret-agent-glue.h"
|
||||
|
||||
G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT)
|
||||
|
||||
#define NM_SECRET_AGENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), \
|
||||
NM_TYPE_SECRET_AGENT, \
|
||||
NMSecretAgentPrivate))
|
||||
|
||||
typedef struct {
|
||||
gboolean registered;
|
||||
|
||||
DBusGConnection *bus;
|
||||
DBusGProxy *dbus_proxy;
|
||||
DBusGProxy *manager_proxy;
|
||||
DBusGProxyCall *reg_call;
|
||||
|
||||
char *nm_owner;
|
||||
|
||||
char *identifier;
|
||||
|
||||
gboolean disposed;
|
||||
} NMSecretAgentPrivate;
|
||||
|
||||
enum {
|
||||
PROP_0,
|
||||
PROP_IDENTIFIER,
|
||||
|
||||
LAST_PROP
|
||||
};
|
||||
|
||||
enum {
|
||||
REGISTRATION_RESULT,
|
||||
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
static guint signals[LAST_SIGNAL] = { 0 };
|
||||
|
||||
|
||||
/********************************************************************/
|
||||
|
||||
GQuark
|
||||
nm_secret_agent_error_quark (void)
|
||||
{
|
||||
static GQuark ret = 0;
|
||||
|
||||
if (G_UNLIKELY (ret == 0))
|
||||
ret = g_quark_from_static_string ("nm-secret-agent-error");
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
|
||||
|
||||
GType
|
||||
nm_secret_agent_error_get_type (void)
|
||||
{
|
||||
static GType etype = 0;
|
||||
|
||||
if (etype == 0) {
|
||||
static const GEnumValue values[] = {
|
||||
/* Sender is not authorized to make this request */
|
||||
ENUM_ENTRY (NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED, "NotAuthorized"),
|
||||
/* Given connection details do not make a valid connection */
|
||||
ENUM_ENTRY (NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, "InvalidConnection"),
|
||||
/* The request was canceled explicitly by the user */
|
||||
ENUM_ENTRY (NM_SECRET_AGENT_ERROR_USER_CANCELED, "UserCanceled"),
|
||||
/* The request was canceled, but not by the user */
|
||||
ENUM_ENTRY (NM_SECRET_AGENT_ERROR_AGENT_CANCELED, "AgentCanceled"),
|
||||
{ 0, 0, 0 }
|
||||
};
|
||||
etype = g_enum_register_static ("NMSecretAgentError", values);
|
||||
}
|
||||
return etype;
|
||||
}
|
||||
|
||||
/*************************************************************/
|
||||
|
||||
static const char *
|
||||
get_nm_owner (NMSecretAgent *self)
|
||||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
GError *error = NULL;
|
||||
char *owner;
|
||||
|
||||
if (!priv->nm_owner) {
|
||||
if (!dbus_g_proxy_call_with_timeout (priv->dbus_proxy,
|
||||
"GetNameOwner", 2000, &error,
|
||||
G_TYPE_STRING, NM_DBUS_SERVICE,
|
||||
G_TYPE_INVALID,
|
||||
G_TYPE_STRING, &owner,
|
||||
G_TYPE_INVALID))
|
||||
return NULL;
|
||||
|
||||
priv->nm_owner = g_strdup (owner);
|
||||
g_free (owner);
|
||||
}
|
||||
|
||||
return priv->nm_owner;
|
||||
}
|
||||
|
||||
static void
|
||||
name_owner_changed (DBusGProxy *proxy,
|
||||
const char *name,
|
||||
const char *old_owner,
|
||||
const char *new_owner,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSecretAgent *self = NM_SECRET_AGENT (user_data);
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
|
||||
if (strcmp (name, NM_DBUS_SERVICE) == 0) {
|
||||
g_free (priv->nm_owner);
|
||||
priv->nm_owner = g_strdup (new_owner);
|
||||
}
|
||||
}
|
||||
|
||||
static NMConnection *
|
||||
verify_request (NMSecretAgent *self,
|
||||
DBusGMethodInvocation *context,
|
||||
GHashTable *connection_hash,
|
||||
GError **error)
|
||||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
NMConnection *connection = NULL;
|
||||
DBusConnection *bus;
|
||||
char *sender;
|
||||
const char *nm_owner;
|
||||
DBusError dbus_error;
|
||||
uid_t sender_uid = G_MAXUINT;
|
||||
GError *local = NULL;
|
||||
|
||||
g_return_val_if_fail (context != NULL, NULL);
|
||||
g_return_val_if_fail (connection_hash != NULL, NULL);
|
||||
|
||||
/* Verify the sender's UID is 0, and that the sender is the same as
|
||||
* NetworkManager's bus name owner.
|
||||
*/
|
||||
|
||||
nm_owner = get_nm_owner (self);
|
||||
if (!nm_owner) {
|
||||
g_set_error_literal (error,
|
||||
NM_SECRET_AGENT_ERROR,
|
||||
NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED,
|
||||
"NetworkManager bus name owner unknown.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
bus = dbus_g_connection_get_connection (priv->bus);
|
||||
if (!bus) {
|
||||
g_set_error_literal (error,
|
||||
NM_SECRET_AGENT_ERROR,
|
||||
NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED,
|
||||
"Failed to get DBus connection.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
sender = dbus_g_method_get_sender (context);
|
||||
if (!sender) {
|
||||
g_set_error_literal (error,
|
||||
NM_SECRET_AGENT_ERROR,
|
||||
NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED,
|
||||
"Failed to get request sender.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Check that the sender matches the current NM bus name owner */
|
||||
if (strcmp (sender, nm_owner) != 0) {
|
||||
g_set_error_literal (error,
|
||||
NM_SECRET_AGENT_ERROR,
|
||||
NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED,
|
||||
"Request sender does not match NetworkManager bus name owner.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
dbus_error_init (&dbus_error);
|
||||
sender_uid = dbus_bus_get_unix_user (bus, sender, &dbus_error);
|
||||
if (dbus_error_is_set (&dbus_error)) {
|
||||
g_set_error (error,
|
||||
NM_SECRET_AGENT_ERROR,
|
||||
NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED,
|
||||
"Failed to get request unix user: (%s) %s.",
|
||||
dbus_error.name, dbus_error.message);
|
||||
dbus_error_free (&dbus_error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (0 != sender_uid) {
|
||||
g_set_error_literal (error,
|
||||
NM_SECRET_AGENT_ERROR,
|
||||
NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED,
|
||||
"Request sender is not root.");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* And make sure the connection is actually valid */
|
||||
connection = nm_connection_new_from_hash (connection_hash, &local);
|
||||
if (!connection) {
|
||||
g_set_error (error,
|
||||
NM_SECRET_AGENT_ERROR,
|
||||
NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
|
||||
"Invalid connection: (%d) %s",
|
||||
local ? local->code : -1,
|
||||
(local && local->message) ? local->message : "(unknown)");
|
||||
g_clear_error (&local);
|
||||
}
|
||||
|
||||
|
||||
out:
|
||||
g_free (sender);
|
||||
return connection;
|
||||
}
|
||||
|
||||
static void
|
||||
impl_secret_agent_get_secrets (NMSecretAgent *self,
|
||||
GHashTable *connection_hash,
|
||||
const char *connection_path,
|
||||
const char *setting_name,
|
||||
const char **hints,
|
||||
gboolean request_new,
|
||||
DBusGMethodInvocation *context)
|
||||
{
|
||||
GError *error = NULL;
|
||||
NMConnection *connection;
|
||||
|
||||
/* Make sure the request comes from NetworkManager and is valid */
|
||||
connection = verify_request (self, context, connection_hash, &error);
|
||||
if (!connection) {
|
||||
dbus_g_method_return_error (context, error);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
NM_SECRET_AGENT_GET_CLASS (self)->get_secrets (self,
|
||||
connection,
|
||||
connection_path,
|
||||
setting_name,
|
||||
hints,
|
||||
request_new,
|
||||
context);
|
||||
g_object_unref (connection);
|
||||
}
|
||||
|
||||
static void
|
||||
impl_secret_agent_save_secrets (NMSecretAgent *self,
|
||||
GHashTable *connection_hash,
|
||||
const char *connection_path,
|
||||
DBusGMethodInvocation *context)
|
||||
{
|
||||
GError *error = NULL;
|
||||
NMConnection *connection;
|
||||
|
||||
/* Make sure the request comes from NetworkManager and is valid */
|
||||
connection = verify_request (self, context, connection_hash, &error);
|
||||
if (!connection) {
|
||||
dbus_g_method_return_error (context, error);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
NM_SECRET_AGENT_GET_CLASS (self)->save_secrets (self,
|
||||
connection,
|
||||
connection_path,
|
||||
context);
|
||||
g_object_unref (connection);
|
||||
}
|
||||
|
||||
static void
|
||||
impl_secret_agent_delete_secrets (NMSecretAgent *self,
|
||||
GHashTable *connection_hash,
|
||||
const char *connection_path,
|
||||
DBusGMethodInvocation *context)
|
||||
{
|
||||
GError *error = NULL;
|
||||
NMConnection *connection;
|
||||
|
||||
/* Make sure the request comes from NetworkManager and is valid */
|
||||
connection = verify_request (self, context, connection_hash, &error);
|
||||
if (!connection) {
|
||||
dbus_g_method_return_error (context, error);
|
||||
g_clear_error (&error);
|
||||
return;
|
||||
}
|
||||
|
||||
NM_SECRET_AGENT_GET_CLASS (self)->delete_secrets (self,
|
||||
connection,
|
||||
connection_path,
|
||||
context);
|
||||
g_object_unref (connection);
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
static void
|
||||
reg_request_cb (DBusGProxy *proxy,
|
||||
DBusGProxyCall *call,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMSecretAgent *self = NM_SECRET_AGENT (user_data);
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
GError *error = NULL;
|
||||
|
||||
priv->reg_call = NULL;
|
||||
|
||||
if (dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INVALID))
|
||||
priv->registered = TRUE;
|
||||
else {
|
||||
/* If registration failed we shouldn't expose ourselves on the bus */
|
||||
dbus_g_connection_unregister_g_object (priv->bus, G_OBJECT (self));
|
||||
}
|
||||
|
||||
g_signal_emit (self, signals[REGISTRATION_RESULT], 0, error);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_secret_agent_register:
|
||||
*
|
||||
* Registers the #NMSecretAgent with the NetworkManager secret manager,
|
||||
* indicating to NetworkManager that the agent is able to provide and save
|
||||
* secrets for connections on behalf of its user. Registration is an
|
||||
* asynchronous operation and its success or failure is indicated via the
|
||||
* 'registration-result' signal.
|
||||
*
|
||||
* Returns: a new %TRUE if registration was successfully requested (this does
|
||||
* not mean registration itself was successful), %FALSE if registration was not
|
||||
* successfully requested.
|
||||
**/
|
||||
gboolean
|
||||
nm_secret_agent_register (NMSecretAgent *self)
|
||||
{
|
||||
NMSecretAgentPrivate *priv;
|
||||
NMSecretAgentClass *class;
|
||||
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
g_return_val_if_fail (NM_IS_SECRET_AGENT (self), FALSE);
|
||||
|
||||
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
|
||||
g_return_val_if_fail (priv->registered == FALSE, FALSE);
|
||||
g_return_val_if_fail (priv->reg_call == NULL, FALSE);
|
||||
g_return_val_if_fail (priv->bus != NULL, FALSE);
|
||||
g_return_val_if_fail (priv->manager_proxy != NULL, FALSE);
|
||||
|
||||
/* Also make sure the subclass can actually respond to secrets requests */
|
||||
class = NM_SECRET_AGENT_GET_CLASS (self);
|
||||
g_return_val_if_fail (class->get_secrets != NULL, FALSE);
|
||||
g_return_val_if_fail (class->save_secrets != NULL, FALSE);
|
||||
g_return_val_if_fail (class->delete_secrets != NULL, FALSE);
|
||||
|
||||
/* Export our secret agent interface before registering with the manager */
|
||||
dbus_g_connection_register_g_object (priv->bus,
|
||||
NM_DBUS_PATH_SECRET_AGENT,
|
||||
G_OBJECT (self));
|
||||
|
||||
priv->reg_call = dbus_g_proxy_begin_call_with_timeout (priv->manager_proxy,
|
||||
"Register",
|
||||
reg_request_cb,
|
||||
self,
|
||||
NULL,
|
||||
G_USEC_PER_SEC * 5,
|
||||
G_TYPE_STRING, priv->identifier,
|
||||
G_TYPE_INVALID);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_secret_agent_unregister:
|
||||
*
|
||||
* Unregisters the #NMSecretAgent with the NetworkManager secret manager,
|
||||
* indicating to NetworkManager that the agent is will no longer provide or
|
||||
* store secrets on behalf of this user.
|
||||
*
|
||||
* Returns: a new %TRUE if unregistration was successful, %FALSE if it was not.
|
||||
**/
|
||||
gboolean
|
||||
nm_secret_agent_unregister (NMSecretAgent *self)
|
||||
{
|
||||
NMSecretAgentPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (self != NULL, FALSE);
|
||||
g_return_val_if_fail (NM_IS_SECRET_AGENT (self), FALSE);
|
||||
|
||||
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
|
||||
g_return_val_if_fail (priv->registered == TRUE, FALSE);
|
||||
g_return_val_if_fail (priv->bus != NULL, FALSE);
|
||||
g_return_val_if_fail (priv->manager_proxy != NULL, FALSE);
|
||||
|
||||
dbus_g_proxy_call_no_reply (priv->manager_proxy, "Unregister", G_TYPE_INVALID);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
static gboolean
|
||||
validate_identifier (const char *identifier)
|
||||
{
|
||||
const char *p = identifier;
|
||||
size_t id_len;
|
||||
|
||||
/* Length between 3 and 255 characters inclusive */
|
||||
id_len = strlen (identifier);
|
||||
if (id_len < 3 || id_len > 255)
|
||||
return FALSE;
|
||||
|
||||
if ((identifier[0] == '.') || (identifier[id_len - 1] == '.'))
|
||||
return FALSE;
|
||||
|
||||
/* FIXME: do complete validation here */
|
||||
while (p && *p) {
|
||||
if (!isalnum (*p) && (*p != '_') && (*p != '-'))
|
||||
return FALSE;
|
||||
if ((*p == '.') && (*(p + 1) == '.'))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
nm_secret_agent_init (NMSecretAgent *self)
|
||||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
GError *error = NULL;
|
||||
|
||||
priv->bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
|
||||
if (!priv->bus) {
|
||||
g_warning ("Couldn't connect to system bus: %s", error->message);
|
||||
g_error_free (error);
|
||||
return;
|
||||
}
|
||||
|
||||
priv->dbus_proxy = dbus_g_proxy_new_for_name (priv->bus,
|
||||
DBUS_SERVICE_DBUS,
|
||||
DBUS_PATH_DBUS,
|
||||
DBUS_INTERFACE_DBUS);
|
||||
if (!priv->dbus_proxy) {
|
||||
g_warning ("Couldn't create messagebus proxy.");
|
||||
return;
|
||||
}
|
||||
|
||||
dbus_g_object_register_marshaller (_nm_marshal_VOID__STRING_STRING_STRING,
|
||||
G_TYPE_NONE,
|
||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
|
||||
G_TYPE_INVALID);
|
||||
dbus_g_proxy_add_signal (priv->dbus_proxy, "NameOwnerChanged",
|
||||
G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING,
|
||||
G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal (priv->dbus_proxy,
|
||||
"NameOwnerChanged",
|
||||
G_CALLBACK (name_owner_changed),
|
||||
self, NULL);
|
||||
|
||||
priv->manager_proxy = dbus_g_proxy_new_for_name (priv->bus,
|
||||
NM_DBUS_SERVICE,
|
||||
NM_DBUS_PATH_AGENT_MANAGER,
|
||||
NM_DBUS_INTERFACE_AGENT_MANAGER);
|
||||
if (!priv->manager_proxy) {
|
||||
g_warning ("Couldn't create NM agent manager proxy.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
get_property (GObject *object,
|
||||
guint prop_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_IDENTIFIER:
|
||||
g_value_set_string (value, priv->identifier);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
set_property (GObject *object,
|
||||
guint prop_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object);
|
||||
const char *identifier;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_IDENTIFIER:
|
||||
identifier = g_value_get_string (value);
|
||||
|
||||
g_return_if_fail (validate_identifier (identifier));
|
||||
|
||||
g_free (priv->identifier);
|
||||
priv->identifier = g_strdup (identifier);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
dispose (GObject *object)
|
||||
{
|
||||
NMSecretAgent *self = NM_SECRET_AGENT (object);
|
||||
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (self);
|
||||
|
||||
if (!priv->disposed) {
|
||||
priv->disposed = TRUE;
|
||||
|
||||
if (priv->registered)
|
||||
nm_secret_agent_unregister (self);
|
||||
|
||||
g_free (priv->identifier);
|
||||
g_free (priv->nm_owner);
|
||||
|
||||
if (priv->dbus_proxy)
|
||||
g_object_unref (priv->dbus_proxy);
|
||||
|
||||
if (priv->manager_proxy)
|
||||
g_object_unref (priv->manager_proxy);
|
||||
|
||||
if (priv->bus)
|
||||
dbus_g_connection_unref (priv->bus);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
static void
|
||||
nm_secret_agent_class_init (NMSecretAgentClass *class)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (class);
|
||||
|
||||
g_type_class_add_private (class, sizeof (NMSecretAgentPrivate));
|
||||
|
||||
/* Virtual methods */
|
||||
object_class->dispose = dispose;
|
||||
object_class->get_property = get_property;
|
||||
object_class->set_property = set_property;
|
||||
|
||||
/**
|
||||
* NMSecretAgent:identifier:
|
||||
*
|
||||
* Identifies this agent; only one agent in each user session may use the
|
||||
* same identifier. Identifier formatting follows the same rules as
|
||||
* D-Bus bus names with the exception that the ':' character is not
|
||||
* allowed. The valid set of characters is "[A-Z][a-z][0-9]_-." and the
|
||||
* identifier is limited in length to 255 characters with a minimum
|
||||
* of 3 characters. An example valid identifier is 'org.gnome.nm-applet'
|
||||
* (without quotes).
|
||||
**/
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_IDENTIFIER,
|
||||
g_param_spec_string (NM_SECRET_AGENT_IDENTIFIER,
|
||||
"Identifier",
|
||||
"Identifier",
|
||||
NULL,
|
||||
G_PARAM_READABLE | G_PARAM_CONSTRUCT_ONLY));
|
||||
|
||||
/**
|
||||
* NMSecretAgent::registration-result:
|
||||
* @agent: the agent that received the signal
|
||||
* @error: the error, if any, that occured while registering
|
||||
*
|
||||
* Indicates the result of a registration request; if @error is NULL the
|
||||
* request was successful.
|
||||
**/
|
||||
signals[REGISTRATION_RESULT] =
|
||||
g_signal_new (REGISTRATION_RESULT,
|
||||
G_OBJECT_CLASS_TYPE (object_class),
|
||||
G_SIGNAL_RUN_FIRST,
|
||||
0, NULL, NULL,
|
||||
g_cclosure_marshal_VOID__POINTER,
|
||||
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
||||
|
||||
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (class),
|
||||
&dbus_glib_nm_secret_agent_object_info);
|
||||
|
||||
dbus_g_error_domain_register (NM_SECRET_AGENT_ERROR,
|
||||
NM_DBUS_INTERFACE_SECRET_AGENT,
|
||||
NM_TYPE_SECRET_AGENT_ERROR);
|
||||
}
|
||||
|
119
libnm-glib/nm-secret-agent.h
Normal file
119
libnm-glib/nm-secret-agent.h
Normal file
@@ -0,0 +1,119 @@
|
||||
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
||||
/*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* (C) Copyright 2010 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef NM_SECRET_AGENT_H
|
||||
#define NM_SECRET_AGENT_H
|
||||
|
||||
#include <dbus/dbus-glib.h>
|
||||
#include <dbus/dbus-glib-lowlevel.h>
|
||||
#include <nm-connection.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define NM_SECRET_AGENT_ERROR (nm_secret_agent_error_quark ())
|
||||
#define NM_TYPE_SECRET_AGENT_ERROR (nm_secret_agent_error_get_type ())
|
||||
|
||||
GQuark nm_secret_agent_error_quark (void);
|
||||
GType nm_secret_agent_error_get_type (void);
|
||||
|
||||
typedef enum {
|
||||
NM_SECRET_AGENT_ERROR_NOT_AUTHORIZED = 0,
|
||||
NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
|
||||
NM_SECRET_AGENT_ERROR_USER_CANCELED,
|
||||
NM_SECRET_AGENT_ERROR_AGENT_CANCELED
|
||||
} NMSecretAgentError;
|
||||
|
||||
|
||||
#define NM_TYPE_SECRET_AGENT (nm_secret_agent_get_type ())
|
||||
#define NM_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgent))
|
||||
#define NM_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_SECRET_AGENT, NMSecretAgentClass))
|
||||
#define NM_IS_SECRET_AGENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_SECRET_AGENT))
|
||||
#define NM_IS_SECRET_AGENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_SECRET_AGENT))
|
||||
#define NM_SECRET_AGENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SECRET_AGENT, NMSecretAgentClass))
|
||||
|
||||
#define NM_SECRET_AGENT_IDENTIFIER "identifier"
|
||||
|
||||
#define NM_SECRET_AGENT_REGISTRATION_RESULT "registration-result"
|
||||
|
||||
typedef struct {
|
||||
GObject parent;
|
||||
} NMSecretAgent;
|
||||
|
||||
typedef struct {
|
||||
GObjectClass parent;
|
||||
|
||||
/* Virtual methods for subclasses */
|
||||
|
||||
/* Called when the subclass should retrieve and return secrets. Subclass
|
||||
* must copy or reference any arguments it may require after returning from
|
||||
* this method, as the arguments will freed (except for 'agent' and
|
||||
* 'context' of course).
|
||||
*/
|
||||
void (*get_secrets) (NMSecretAgent *agent,
|
||||
NMConnection *connection,
|
||||
const char *connection_path,
|
||||
const char *setting_name,
|
||||
const char **hints,
|
||||
gboolean request_new,
|
||||
DBusGMethodInvocation *context);
|
||||
|
||||
/* Called when the subclass should save the secrets contained in the
|
||||
* connection to backing storage. Subclass must copy or reference any
|
||||
* arguments it may require after returning from this method, as the
|
||||
* arguments will freed (except for 'agent' and 'context' of course).
|
||||
*/
|
||||
void (*save_secrets) (NMSecretAgent *agent,
|
||||
NMConnection *connection,
|
||||
const char *connection_path,
|
||||
DBusGMethodInvocation *context);
|
||||
|
||||
/* Called when the subclass should delete the secrets contained in the
|
||||
* connection from backing storage. Subclass must copy or reference any
|
||||
* arguments it may require after returning from this method, as the
|
||||
* arguments will freed (except for 'agent' and 'context' of course).
|
||||
*/
|
||||
void (*delete_secrets) (NMSecretAgent *agent,
|
||||
NMConnection *connection,
|
||||
const char *connection_path,
|
||||
DBusGMethodInvocation *context);
|
||||
|
||||
/* Signals */
|
||||
void (*registration_result) (NMSecretAgent *agent, GError *error);
|
||||
|
||||
/* Padding for future expansion */
|
||||
void (*_reserved1) (void);
|
||||
void (*_reserved2) (void);
|
||||
void (*_reserved3) (void);
|
||||
void (*_reserved4) (void);
|
||||
void (*_reserved5) (void);
|
||||
void (*_reserved6) (void);
|
||||
} NMSecretAgentClass;
|
||||
|
||||
GType nm_secret_agent_get_type (void);
|
||||
|
||||
NMSecretAgent *nm_secret_agent_new (const char *identifier);
|
||||
|
||||
gboolean nm_secret_agent_register (NMSecretAgent *self);
|
||||
|
||||
gboolean nm_secret_agent_unregister (NMSecretAgent *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* NM_SECRET_AGENT_H */
|
Reference in New Issue
Block a user