[network-manager-openvpn/dcbw/need-secrets: 1/5] core: implement asynchronous secrets
- From: Dan Williams <dcbw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [network-manager-openvpn/dcbw/need-secrets: 1/5] core: implement asynchronous secrets
- Date: Wed, 17 Jul 2013 19:38:35 +0000 (UTC)
commit 5926f0f168f87378366c4b9c37d055f2e4950213
Author: Dan Williams <dcbw redhat com>
Date: Fri Jun 21 11:56:31 2013 -0500
core: implement asynchronous secrets
Request secrets from NetworkManager when openvpn asks us for them,
instead of trying to figure out what we need before connecting.
src/nm-openvpn-service.c | 383 +++++++++++++++++++++++++---------------------
1 files changed, 208 insertions(+), 175 deletions(-)
---
diff --git a/src/nm-openvpn-service.c b/src/nm-openvpn-service.c
index 7b4cbd7..150092f 100644
--- a/src/nm-openvpn-service.c
+++ b/src/nm-openvpn-service.c
@@ -69,11 +69,13 @@ G_DEFINE_TYPE (NMOpenvpnPlugin, nm_openvpn_plugin, NM_TYPE_VPN_PLUGIN)
#define NM_OPENVPN_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_OPENVPN_PLUGIN,
NMOpenvpnPluginPrivate))
typedef struct {
+ char *default_username;
char *username;
char *password;
char *priv_key_pass;
char *proxy_username;
char *proxy_password;
+ char *pending_auth;
GIOChannel *socket_channel;
guint socket_channel_eventid;
} NMOpenvpnPluginIOData;
@@ -268,17 +270,8 @@ nm_openvpn_secrets_validate (NMSettingVPN *s_vpn, GError **error)
ValidateInfo info = { &valid_secrets[0], &validate_error, FALSE };
nm_setting_vpn_foreach_secret (s_vpn, validate_one_property, &info);
- if (!info.have_items) {
- g_set_error (error,
- NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "%s",
- _("No VPN secrets!"));
- return FALSE;
- }
-
if (validate_error) {
- *error = validate_error;
+ g_propagate_error (error, validate_error);
return FALSE;
}
return TRUE;
@@ -304,6 +297,7 @@ nm_openvpn_disconnect_management_socket (NMOpenvpnPlugin *plugin)
g_free (io_data->username);
g_free (io_data->proxy_username);
+ g_free (io_data->pending_auth);
if (io_data->password)
memset (io_data->password, 0, strlen (io_data->password));
@@ -398,6 +392,92 @@ write_user_pass (GIOChannel *channel,
}
static gboolean
+handle_auth (NMOpenvpnPluginIOData *io_data,
+ const char *requested_auth,
+ const char **out_message,
+ char ***out_hints)
+{
+ gboolean handled = FALSE;
+ guint i = 0;
+ char **hints = NULL;
+
+ g_return_val_if_fail (requested_auth != NULL, FALSE);
+ g_return_val_if_fail (out_message != NULL, FALSE);
+ g_return_val_if_fail (out_hints != NULL, FALSE);
+
+ if (strcmp (requested_auth, "Auth") == 0) {
+ const char *username = io_data->username;
+
+ /* Fall back to the default username if it wasn't overridden by the user */
+ if (!username)
+ username = io_data->default_username;
+
+ if (username != NULL && io_data->password != NULL) {
+ write_user_pass (io_data->socket_channel,
+ requested_auth,
+ username,
+ io_data->password);
+ } else {
+ hints = g_new0 (char *, 3);
+ if (!username) {
+ hints[i++] = NM_OPENVPN_KEY_USERNAME;
+ *out_message = _("A username is required.");
+ }
+ if (!io_data->password) {
+ hints[i++] = NM_OPENVPN_KEY_PASSWORD;
+ *out_message = _("A password is required.");
+ }
+ if (!username && !io_data->password)
+ *out_message = _("A username and password are required.");
+ }
+ handled = TRUE;
+ } else if (!strcmp (requested_auth, "Private Key")) {
+ if (io_data->priv_key_pass) {
+ char *qpass, *buf;
+
+ /* Quote strings passed back to openvpn */
+ qpass = ovpn_quote_string (io_data->priv_key_pass);
+ buf = g_strdup_printf ("password \"%s\" \"%s\"\n", requested_auth, qpass);
+ memset (qpass, 0, strlen (qpass));
+ g_free (qpass);
+
+ /* Will always write everything in blocking channels (on success) */
+ g_io_channel_write_chars (io_data->socket_channel, buf, strlen (buf), NULL, NULL);
+ g_io_channel_flush (io_data->socket_channel, NULL);
+ g_free (buf);
+ } else {
+ hints = g_new0 (char *, 2);
+ hints[i++] = NM_OPENVPN_KEY_CERTPASS;
+ *out_message = _("A private key password is required.");
+ }
+ handled = TRUE;
+ } else if (strcmp (requested_auth, "HTTP Proxy") == 0) {
+ if (io_data->proxy_username != NULL && io_data->proxy_password != NULL) {
+ write_user_pass (io_data->socket_channel,
+ requested_auth,
+ io_data->proxy_username,
+ io_data->proxy_password);
+ } else {
+ hints = g_new0 (char *, 3);
+ if (!io_data->proxy_username) {
+ hints[i++] = NM_OPENVPN_KEY_HTTP_PROXY_USERNAME;
+ *out_message = _("An HTTP Proxy username is required.");
+ }
+ if (!io_data->proxy_password) {
+ hints[i++] = NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD;
+ *out_message = _("An HTTP Proxy password is required.");
+ }
+ if (!io_data->proxy_username && !io_data->proxy_password)
+ *out_message = _("An HTTP Proxy username and password are required.");
+ }
+ handled = TRUE;
+ }
+
+ *out_hints = hints;
+ return handled;
+}
+
+static gboolean
handle_management_socket (NMVPNPlugin *plugin,
GIOChannel *source,
GIOCondition condition,
@@ -405,7 +485,9 @@ handle_management_socket (NMVPNPlugin *plugin,
{
NMOpenvpnPluginIOData *io_data = NM_OPENVPN_PLUGIN_GET_PRIVATE (plugin)->io_data;
gboolean again = TRUE;
- char *str = NULL, *auth = NULL, *buf;
+ char *str = NULL, *auth = NULL;
+ const char *message = NULL;
+ char **hints = NULL;
if (!(condition & G_IO_IN))
return TRUE;
@@ -416,41 +498,33 @@ handle_management_socket (NMVPNPlugin *plugin,
if (strlen (str) < 1)
goto out;
+ if (debug)
+ g_message ("VPN request '%s'", str);
+
auth = get_detail (str, ">PASSWORD:Need '");
if (auth) {
- if (strcmp (auth, "Auth") == 0) {
- if (io_data->username != NULL && io_data->password != NULL)
- write_user_pass (source, auth, io_data->username, io_data->password);
- else
- g_warning ("Auth requested but one of username or password is missing");
- } else if (!strcmp (auth, "Private Key")) {
- if (io_data->priv_key_pass) {
- char *qpass;
-
- /* Quote strings passed back to openvpn */
- qpass = ovpn_quote_string (io_data->priv_key_pass);
- buf = g_strdup_printf ("password \"%s\" \"%s\"\n", auth, qpass);
- memset (qpass, 0, strlen (qpass));
- g_free (qpass);
-
- /* Will always write everything in blocking channels (on success) */
- g_io_channel_write_chars (source, buf, strlen (buf), NULL, NULL);
- g_io_channel_flush (source, NULL);
- g_free (buf);
- } else
- g_warning ("Certificate password requested but private key password == NULL");
- } else if (strcmp (auth, "HTTP Proxy") == 0) {
- if (io_data->proxy_username != NULL && io_data->proxy_password != NULL)
- write_user_pass (source, auth, io_data->proxy_username,
io_data->proxy_password);
- else
- g_warning ("HTTP Proxy auth requested but either proxy username or password
is missing");
+ if (io_data->pending_auth)
+ g_free (io_data->pending_auth);
+ io_data->pending_auth = auth;
+
+ if (handle_auth (io_data, auth, &message, &hints)) {
+ /* Request new secrets if we need any */
+ if (message) {
+ if (debug) {
+ char *joined = hints ? g_strjoinv (",", (char **) hints) : "none";
+ g_message ("Requesting new secrets: '%s' (%s)", message, joined);
+ g_free (joined);
+ }
+ nm_vpn_plugin_secrets_required (plugin, message, (const char **) hints);
+ }
+ if (hints)
+ g_free (hints); /* elements are 'const' */
} else {
- g_warning ("No clue what to send for username/password request for '%s'", auth);
+ g_warning ("Unhandled management socket request '%s'", auth);
if (out_failure)
*out_failure = NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED;
again = FALSE;
}
- g_free (auth);
}
auth = get_detail (str, ">PASSWORD:Verification Failed: '");
@@ -727,6 +801,48 @@ add_cert_args (GPtrArray *args, NMSettingVPN *s_vpn)
}
}
+static void
+update_io_data_from_vpn_setting (NMOpenvpnPluginIOData *io_data,
+ NMSettingVPN *s_vpn,
+ const char *default_username)
+{
+ const char *tmp;
+
+ if (default_username) {
+ g_free (io_data->default_username);
+ io_data->default_username = g_strdup (default_username);
+ }
+
+ g_free (io_data->username);
+ tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_USERNAME);
+ io_data->username = tmp ? g_strdup (tmp) : NULL;
+
+ if (io_data->password) {
+ memset (io_data->password, 0, strlen (io_data->password));
+ g_free (io_data->password);
+ }
+ tmp = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_PASSWORD);
+ io_data->password = tmp ? g_strdup (tmp) : NULL;
+
+ if (io_data->priv_key_pass) {
+ memset (io_data->priv_key_pass, 0, strlen (io_data->priv_key_pass));
+ g_free (io_data->priv_key_pass);
+ }
+ tmp = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_CERTPASS);
+ io_data->priv_key_pass = tmp ? g_strdup (tmp) : NULL;
+
+ g_free (io_data->proxy_username);
+ tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_USERNAME);
+ io_data->proxy_username = tmp ? g_strdup (tmp) : NULL;
+
+ if (io_data->proxy_password) {
+ memset (io_data->proxy_password, 0, strlen (io_data->proxy_password));
+ g_free (io_data->proxy_password);
+ }
+ tmp = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD);
+ io_data->proxy_password = tmp ? g_strdup (tmp) : NULL;
+}
+
static gboolean
nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
NMSettingVPN *s_vpn,
@@ -762,9 +878,8 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
}
}
- tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE);
- connection_type = validate_connection_type (tmp);
- if (!connection_type) {
+ connection_type = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE);
+ if (!validate_connection_type (connection_type)) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
@@ -1086,86 +1201,13 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
|| nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_USERNAME)) {
priv->io_data = g_malloc0 (sizeof (NMOpenvpnPluginIOData));
-
- tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_USERNAME);
- priv->io_data->username = tmp ? g_strdup (tmp) : NULL;
- /* Use the default username if it wasn't overridden by the user */
- if (!priv->io_data->username && default_username)
- priv->io_data->username = g_strdup (default_username);
-
- tmp = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_PASSWORD);
- priv->io_data->password = tmp ? g_strdup (tmp) : NULL;
-
- tmp = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_CERTPASS);
- priv->io_data->priv_key_pass = tmp ? g_strdup (tmp) : NULL;
-
- tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_USERNAME);
- priv->io_data->proxy_username = tmp ? g_strdup (tmp) : NULL;
-
- tmp = nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD);
- priv->io_data->proxy_password = tmp ? g_strdup (tmp) : NULL;
-
+ update_io_data_from_vpn_setting (priv->io_data, s_vpn, default_username);
nm_openvpn_schedule_connect_timer (plugin);
}
return TRUE;
}
-static const char *
-check_need_secrets (NMSettingVPN *s_vpn, gboolean *need_secrets)
-{
- const char *tmp, *key, *ctype;
- NMSettingSecretFlags secret_flags = NM_SETTING_SECRET_FLAG_NONE;
-
- g_return_val_if_fail (s_vpn != NULL, FALSE);
- g_return_val_if_fail (need_secrets != NULL, FALSE);
-
- *need_secrets = FALSE;
-
- tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE);
- ctype = validate_connection_type (tmp);
- if (!ctype)
- return NULL;
-
- if (!strcmp (ctype, NM_OPENVPN_CONTYPE_PASSWORD_TLS)) {
- /* Will require a password and maybe private key password */
- key = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_KEY);
- if (is_encrypted (key) && !nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_CERTPASS))
- *need_secrets = TRUE;
-
- if (!nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_PASSWORD)) {
- *need_secrets = TRUE;
- if (nm_setting_get_secret_flags (NM_SETTING (s_vpn), NM_OPENVPN_KEY_PASSWORD,
&secret_flags, NULL)) {
- if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
- *need_secrets = FALSE;
- }
- }
- } else if (!strcmp (ctype, NM_OPENVPN_CONTYPE_PASSWORD)) {
- /* Will require a password */
- if (!nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_PASSWORD)) {
- *need_secrets = TRUE;
- if (nm_setting_get_secret_flags (NM_SETTING (s_vpn), NM_OPENVPN_KEY_PASSWORD,
&secret_flags, NULL)) {
- if (secret_flags & NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
- *need_secrets = FALSE;
- }
- }
- } else if (!strcmp (ctype, NM_OPENVPN_CONTYPE_TLS)) {
- /* May require private key password */
- key = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_KEY);
- if (is_encrypted (key) && !nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_CERTPASS))
- *need_secrets = TRUE;
- } else {
- /* Static key doesn't need passwords */
- }
-
- /* HTTP Proxy might require a password; assume so if there's an HTTP proxy username */
- tmp = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_USERNAME);
- if (tmp && !nm_setting_vpn_get_secret (s_vpn, NM_OPENVPN_KEY_HTTP_PROXY_PASSWORD))
- *need_secrets = TRUE;
-
- return ctype;
-}
-
static gboolean
real_connect (NMVPNPlugin *plugin,
NMConnection *connection,
@@ -1174,55 +1216,35 @@ real_connect (NMVPNPlugin *plugin,
NMSettingVPN *s_vpn;
const char *connection_type;
const char *user_name;
- gboolean need_secrets;
s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
if (!s_vpn) {
- g_set_error (error,
- NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
- "%s",
- _("Could not process the request because the VPN connection settings were
invalid."));
+ g_set_error_literal (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+ _("Could not process the request because the VPN connection settings
were invalid."));
return FALSE;
}
- /* Check if we need secrets and validate the connection type */
- connection_type = check_need_secrets (s_vpn, &need_secrets);
- if (!connection_type) {
- g_set_error (error,
- NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "%s",
- _("Invalid connection type."));
+ connection_type = nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_CONNECTION_TYPE);
+ if (!validate_connection_type (connection_type)) {
+ g_set_error_literal (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+ _("Could not process the request because the openvpn connection type was
invalid."));
return FALSE;
}
- user_name = nm_setting_vpn_get_user_name (s_vpn);
-
- /* Need a username for any password-based connection types */
- if ( !strcmp (connection_type, NM_OPENVPN_CONTYPE_PASSWORD_TLS)
- || !strcmp (connection_type, NM_OPENVPN_CONTYPE_PASSWORD)) {
- if (!user_name && !nm_setting_vpn_get_data_item (s_vpn, NM_OPENVPN_KEY_USERNAME)) {
- g_set_error (error,
- NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
- "%s",
- _("Could not process the request because no username was provided."));
- return FALSE;
- }
- }
-
/* Validate the properties */
if (!nm_openvpn_properties_validate (s_vpn, error))
return FALSE;
/* Validate secrets */
- if (need_secrets) {
- if (!nm_openvpn_secrets_validate (s_vpn, error))
- return FALSE;
- }
+ if (!nm_openvpn_secrets_validate (s_vpn, error))
+ return FALSE;
/* Finally try to start OpenVPN */
+ user_name = nm_setting_vpn_get_user_name (s_vpn);
if (!nm_openvpn_start_openvpn_binary (NM_OPENVPN_PLUGIN (plugin), s_vpn, user_name, error))
return FALSE;
@@ -1235,42 +1257,52 @@ real_need_secrets (NMVPNPlugin *plugin,
char **setting_name,
GError **error)
{
- NMSettingVPN *s_vpn;
- const char *connection_type;
- gboolean need_secrets = FALSE;
-
- g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
- g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+ /* Secrets are request asynchronously during Connect() */
+ return FALSE;
+}
- if (debug) {
- g_message ("%s: connection -------------------------------------", __func__);
- nm_connection_dump (connection);
- }
+static gboolean
+real_new_secrets (NMVPNPlugin *plugin,
+ NMConnection *connection,
+ GError **error)
+{
+ NMOpenvpnPluginPrivate *priv = NM_OPENVPN_PLUGIN_GET_PRIVATE (plugin);
+ NMSettingVPN *s_vpn;
+ const char *message = NULL;
+ char **hints = NULL;
s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
if (!s_vpn) {
- g_set_error (error,
- NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
- "%s",
- _("Could not process the request because the VPN connection settings were
invalid."));
+ g_set_error_literal (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+ _("Could not process the request because the VPN connection settings
were invalid."));
return FALSE;
}
- connection_type = check_need_secrets (s_vpn, &need_secrets);
- if (!connection_type) {
- g_set_error (error,
- NM_VPN_PLUGIN_ERROR,
- NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
- "%s",
- _("Invalid connection type."));
+ if (debug)
+ g_message ("VPN received new secrets; sending to management interface");
+
+ update_io_data_from_vpn_setting (priv->io_data, s_vpn, NULL);
+
+ g_warn_if_fail (priv->io_data->pending_auth);
+ if (!handle_auth (priv->io_data, priv->io_data->pending_auth, &message, &hints)) {
+ g_set_error_literal (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_GENERAL,
+ _("Unhandled pending authentication."));
return FALSE;
}
- if (need_secrets)
- *setting_name = NM_SETTING_VPN_SETTING_NAME;
-
- return need_secrets;
+ /* Request new secrets if we need any */
+ if (message) {
+ if (debug)
+ g_message ("Requesting new secrets: '%s'", message);
+ nm_vpn_plugin_secrets_required (plugin, message, (const char **) hints);
+ }
+ if (hints)
+ g_free (hints); /* elements are 'const' */
+ return TRUE;
}
static gboolean
@@ -1320,6 +1352,7 @@ nm_openvpn_plugin_class_init (NMOpenvpnPluginClass *plugin_class)
parent_class->connect = real_connect;
parent_class->need_secrets = real_need_secrets;
parent_class->disconnect = real_disconnect;
+ parent_class->new_secrets = real_new_secrets;
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]