NetworkAgent: add support for VPN connections

VPN secrets are stored by the plugins, that provide separate
helpers for authentication. This commit adds the support for invoking
the binaries and pass them connection details.
For plugins that support it (as exposed by their keyfile), we invoke
them in "external-ui-mode" and expect a set of metadata about the
secrets which is used to build a shell styled dialog.

https://bugzilla.gnome.org/show_bug.cgi?id=658484
This commit is contained in:
Giovanni Campagna
2011-11-03 21:57:33 +01:00
parent 62c0088dd8
commit 92276c5e70
5 changed files with 423 additions and 35 deletions

View File

@ -22,6 +22,7 @@
#include "config.h"
#include <string.h>
#include <gnome-keyring.h>
#include <dbus/dbus-glib.h>
#include "shell-network-agent.h"
@ -47,6 +48,8 @@ typedef struct {
/* <gchar *setting_key, gchar *secret> */
GHashTable *entries;
GHashTable *vpn_entries;
gboolean is_vpn;
} ShellAgentRequest;
struct _ShellNetworkAgentPrivate {
@ -68,7 +71,6 @@ shell_agent_request_free (gpointer data)
g_object_unref (request->connection);
g_free (request->setting_name);
g_strfreev (request->hints);
g_hash_table_destroy (request->entries);
g_slice_free (ShellAgentRequest, request);
@ -122,7 +124,8 @@ request_secrets_from_ui (ShellAgentRequest *request)
request->request_id,
request->connection,
request->setting_name,
request->hints);
request->hints,
(int)request->flags);
}
static void
@ -274,11 +277,17 @@ get_secrets_keyring_cb (GnomeKeyringResult result,
&& (attr->type == GNOME_KEYRING_ATTRIBUTE_TYPE_STRING))
{
gchar *secret_name = g_strdup (attr->value.string);
GValue *secret_value = g_slice_new0 (GValue);
g_value_init (secret_value, G_TYPE_STRING);
g_value_set_string (secret_value, item->secret);
g_hash_table_insert (closure->entries, secret_name, secret_value);
if (!closure->is_vpn)
{
GValue *secret_value = g_slice_new0 (GValue);
g_value_init (secret_value, G_TYPE_STRING);
g_value_set_string (secret_value, item->secret);
g_hash_table_insert (closure->entries, secret_name, secret_value);
}
else
g_hash_table_insert (closure->vpn_entries, secret_name, g_strdup (item->secret));
if (closure->hints)
n_found += strv_has (closure->hints, secret_name);
@ -293,7 +302,6 @@ get_secrets_keyring_cb (GnomeKeyringResult result,
if (n_found == 0 &&
(closure->flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION))
{
/* Even if n_found == 0, secrets is not necessarily empty */
nm_connection_update_secrets (closure->connection, closure->setting_name, closure->entries, NULL);
request_secrets_from_ui (closure);
@ -327,17 +335,8 @@ shell_network_agent_get_secrets (NMSecretAgent *agent,
NMSettingConnection *setting_connection;
const char *connection_type;
/* VPN secrets are currently unimplemented - bail out early */
setting_connection = nm_connection_get_setting_connection (connection);
connection_type = nm_setting_connection_get_connection_type (setting_connection);
if (strcmp (connection_type, "vpn") == 0)
{
GError *error = g_error_new (NM_SECRET_AGENT_ERROR,
NM_SECRET_AGENT_ERROR_AGENT_CANCELED,
"VPN secrets are currently unhandled.");
callback (NM_SECRET_AGENT (self), connection, NULL, error, callback_data);
return;
}
request = g_slice_new (ShellAgentRequest);
request->self = g_object_ref (self);
@ -347,8 +346,24 @@ shell_network_agent_get_secrets (NMSecretAgent *agent,
request->flags = flags;
request->callback = callback;
request->callback_data = callback_data;
request->is_vpn = !strcmp(connection_type, NM_SETTING_VPN_SETTING_NAME);
request->keyring_op = NULL;
request->entries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, gvalue_destroy_notify);
if (request->is_vpn)
{
GValue *secret_value;
request->vpn_entries = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
secret_value = g_slice_new0 (GValue);
g_value_init (secret_value, dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_STRING));
g_value_take_boxed (secret_value, request->vpn_entries);
g_hash_table_insert (request->entries, g_strdup(NM_SETTING_VPN_SECRETS), secret_value);
}
else
request->vpn_entries = NULL;
request->request_id = g_strdup_printf ("%s/%s", connection_path, setting_name);
g_hash_table_replace (self->priv->requests, request->request_id, request);
@ -388,17 +403,24 @@ shell_network_agent_set_password (ShellNetworkAgent *self,
priv = self->priv;
request = g_hash_table_lookup (priv->requests, request_id);
value = g_slice_new0 (GValue);
g_value_init (value, G_TYPE_STRING);
g_value_set_string (value, setting_value);
if (!request->is_vpn)
{
value = g_slice_new0 (GValue);
g_value_init (value, G_TYPE_STRING);
g_value_set_string (value, setting_value);
g_hash_table_replace (request->entries, g_strdup (setting_key), value);
g_hash_table_replace (request->entries, g_strdup (setting_key), value);
}
else
{
g_hash_table_replace (request->vpn_entries, g_strdup (setting_key), g_strdup (setting_value));
}
}
void
shell_network_agent_respond (ShellNetworkAgent *self,
gchar *request_id,
gboolean canceled)
shell_network_agent_respond (ShellNetworkAgent *self,
gchar *request_id,
ShellNetworkAgentResponse response)
{
ShellNetworkAgentPrivate *priv;
ShellAgentRequest *request;
@ -410,7 +432,7 @@ shell_network_agent_respond (ShellNetworkAgent *self,
priv = self->priv;
request = g_hash_table_lookup (priv->requests, request_id);
if (canceled)
if (response == SHELL_NETWORK_AGENT_USER_CANCELED)
{
GError *error = g_error_new (NM_SECRET_AGENT_ERROR,
NM_SECRET_AGENT_ERROR_USER_CANCELED,
@ -422,10 +444,24 @@ shell_network_agent_respond (ShellNetworkAgent *self,
return;
}
if (response == SHELL_NETWORK_AGENT_INTERNAL_ERROR)
{
GError *error = g_error_new (NM_SECRET_AGENT_ERROR,
NM_SECRET_AGENT_ERROR_INTERNAL_ERROR,
"An internal error occurred while processing the request.");
request->callback (NM_SECRET_AGENT (self), request->connection, NULL, error, request->callback_data);
g_error_free (error);
g_hash_table_remove (priv->requests, request_id);
return;
}
/* response == SHELL_NETWORK_AGENT_CONFIRMED */
/* Save updated secrets */
dup = nm_connection_duplicate (request->connection);
nm_connection_update_secrets (dup, request->setting_name, request->entries, NULL);
nm_connection_update_secrets (dup, request->setting_name, request->entries, NULL);
nm_secret_agent_save_secrets (NM_SECRET_AGENT (self), dup, NULL, NULL);
outer = g_hash_table_new (g_str_hash, g_str_equal);
@ -776,11 +812,12 @@ shell_network_agent_class_init (ShellNetworkAgentClass *klass)
NULL, /* accu_data */
NULL, /* marshaller */
G_TYPE_NONE, /* return */
3, /* n_params */
5, /* n_params */
G_TYPE_STRING,
NM_TYPE_CONNECTION,
G_TYPE_STRING,
G_TYPE_STRV);
G_TYPE_STRV,
G_TYPE_INT);
signals[SIGNAL_CANCEL_REQUEST] = g_signal_new ("cancel-request",
G_TYPE_FROM_CLASS (klass),

View File

@ -9,6 +9,12 @@
G_BEGIN_DECLS
typedef enum {
SHELL_NETWORK_AGENT_CONFIRMED,
SHELL_NETWORK_AGENT_USER_CANCELED,
SHELL_NETWORK_AGENT_INTERNAL_ERROR
} ShellNetworkAgentResponse;
typedef struct _ShellNetworkAgent ShellNetworkAgent;
typedef struct _ShellNetworkAgentClass ShellNetworkAgentClass;
typedef struct _ShellNetworkAgentPrivate ShellNetworkAgentPrivate;
@ -45,7 +51,7 @@ void shell_network_agent_set_password (ShellNetworkAgent *self,
gchar *setting_value);
void shell_network_agent_respond (ShellNetworkAgent *self,
gchar *request_id,
gboolean canceled);
ShellNetworkAgentResponse response);
/* If these are kept in sync with nm-applet, secrets will be shared */
#define SHELL_KEYRING_UUID_TAG "connection-uuid"

View File

@ -2,6 +2,9 @@
#include "config.h"
#include <sys/types.h>
#include <sys/wait.h>
#include "shell-util.h"
#include <glib/gi18n-lib.h>
#include <gtk/gtk.h>
@ -861,3 +864,26 @@ shell_session_is_active_for_systemd (void)
return TRUE;
#endif
}
/**
* shell_util_wifexited:
* @status: the status returned by wait() or waitpid()
* @exit: (out): the actual exit status of the process
*
* Implements libc standard WIFEXITED, that cannot be used JS
* code.
* Returns: TRUE if the process exited normally, FALSE otherwise
*/
gboolean
shell_util_wifexited (int status,
int *exit)
{
gboolean ret;
ret = WIFEXITED(status);
if (ret)
*exit = WEXITSTATUS(status);
return ret;
}

View File

@ -52,6 +52,9 @@ void shell_shader_effect_set_double_uniform (ClutterShaderEffect *effect,
gboolean shell_session_is_active_for_systemd (void);
gboolean shell_util_wifexited (int status,
int *exit);
G_END_DECLS
#endif /* __SHELL_UTIL_H__ */