On Tue, 2014-08-19 at 11:06 -0500, David Woodhouse wrote: > Sitting on a crappy hotel network this week, I'm annoyed by how often I > have to reauthenticate to my VPN server. I'd *really* like the secrets > to be cached so that it can just *work* when I fall off the wireless and > rejoin. > > It doesn't look *so* hard to do this with a hack in > nm-openconnect-service itself. When we connect, remember the secrets > locally (and disable the "quit" signal so we don't exit on idle). > > If we later get a need_secrets() call, and if we already have them > locally (although they won't be in the settings dictionary that we're > sent), then just return FALSE. We'll get a connect() call, and we can > use the cached secrets to make the connection. If the connection *fails* > then invalidate the cached secrets. > > That kind of works, but it's ugly. And at the very least, we'd really > like to differentiate between a disconnect call which happens because > the physical network went down, and a disconnect call triggered by > explicit user request. We'd probably want to sign off and terminate (and > forget) the session on the latter, but keep it alive and cached in the > former case. > > But really, rather than hacking this up in the vpn service itself, > perhaps what I want here is a new secret flag called something like > NM_SETTING_SECRET_SAVED_NON_PERSISTENT — which allows the secret to be > stored, but only in *memory* for the lifetime of a given session. And > then they could be automatically discarded when the user explicitly > requests a disconnect, etc. > > Thoughts?
(Full citation preserved since I'm not sure the original got through.
Yay for crappy hotel networks)
Here's my hack, now that it's actually working:
diff --git a/src/nm-openconnect-service-openconnect-helper.c
b/src/nm-openconnect-service-openconnect-helper.c
index 2fa6852..7ad5e75 100644
--- a/src/nm-openconnect-service-openconnect-helper.c
+++ b/src/nm-openconnect-service-openconnect-helper.c
@@ -620,6 +620,19 @@ main (int argc, char *argv[])
if (val)
g_hash_table_insert (ip6config, NM_VPN_PLUGIN_IP6_CONFIG_DNS,
val);
+ /* Session timeout */
+ tmp = getenv ("CISCO_CSTP_OPTIONS");
+ while (tmp) {
+ if (!strncmp(tmp, "X-CSTP-Session-Timeout=", 23)) {
+ val = uint_to_gvalue (strtol (tmp + 23, NULL, 10));
+ g_hash_table_insert(config,
"openconnect_session_timeout", val);
+ break;
+ }
+ tmp = strchr(tmp, '\n');
+ if (tmp)
+ tmp++;
+ }
+
/* Routes */
val = get_ip6_routes ();
if (val) {
diff --git a/src/nm-openconnect-service.c b/src/nm-openconnect-service.c
index 7dcf964..d23640d 100644
--- a/src/nm-openconnect-service.c
+++ b/src/nm-openconnect-service.c
@@ -54,6 +54,12 @@
G_DEFINE_TYPE (NMOPENCONNECTPlugin, nm_openconnect_plugin, NM_TYPE_VPN_PLUGIN)
typedef struct {
+ char *uuid;
+ char *cookie;
+ char *gateway;
+ char *gwcert;
+ time_t cookie_start;
+ unsigned long cookie_validity;
GPid pid;
char *tun_name;
} NMOPENCONNECTPluginPrivate;
@@ -103,6 +109,7 @@ static ValidProperty valid_secrets[] = {
{ NULL, G_TYPE_NONE, 0, 0 }
};
+
static uid_t tun_owner;
static gid_t tun_group;
static gboolean debug = FALSE;
@@ -114,6 +121,7 @@ typedef struct ValidateInfo {
gboolean have_items;
} ValidateInfo;
+
static void
validate_one_property (const char *key, const char *value, gpointer user_data)
{
@@ -387,6 +395,8 @@ nm_openconnect_start_openconnect_binary
(NMOPENCONNECTPlugin *plugin,
/* The actual gateway to use (after redirection) comes from the auth
dialog, so it's in the secrets hash not the properties */
props_vpn_gw = nm_setting_vpn_get_secret (s_vpn,
NM_OPENCONNECT_KEY_GATEWAY);
+ if (!props_vpn_gw || !strlen (props_vpn_gw) )
+ props_vpn_gw = priv->gateway;
if (!props_vpn_gw || !strlen (props_vpn_gw) ) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
@@ -397,6 +407,8 @@ nm_openconnect_start_openconnect_binary
(NMOPENCONNECTPlugin *plugin,
}
props_cookie = nm_setting_vpn_get_secret (s_vpn,
NM_OPENCONNECT_KEY_COOKIE);
+ if (!props_cookie || !strlen (props_cookie) )
+ props_cookie = priv->cookie;
if (!props_cookie || !strlen (props_cookie)) {
g_set_error (error,
NM_VPN_PLUGIN_ERROR,
@@ -406,6 +418,8 @@ nm_openconnect_start_openconnect_binary
(NMOPENCONNECTPlugin *plugin,
return -1;
}
props_gwcert = nm_setting_vpn_get_secret (s_vpn,
NM_OPENCONNECT_KEY_GWCERT);
+ if (!props_gwcert || !strlen (props_gwcert) )
+ props_gwcert = priv->gwcert;
props_cacert = nm_setting_vpn_get_data_item (s_vpn,
NM_OPENCONNECT_KEY_CACERT);
props_mtu = nm_setting_vpn_get_data_item (s_vpn,
NM_OPENCONNECT_KEY_MTU);
@@ -452,6 +466,9 @@ nm_openconnect_start_openconnect_binary
(NMOPENCONNECTPlugin *plugin,
g_ptr_array_add (openconnect_argv, NULL);
+ /* Only allow the cookie reuse when connections are successful */
+ priv->cookie_validity = 0;
+
if (!g_spawn_async_with_pipes (NULL, (char **) openconnect_argv->pdata,
NULL,
G_SPAWN_DO_NOT_REAP_CHILD,
openconnect_drop_child_privs,
priv->tun_name,
@@ -507,16 +524,34 @@ real_connect (NMVPNPlugin *plugin,
}
static gboolean
+cached_secrets_valid (NMVPNPlugin *plugin, NMSettingVPN *s_vpn, const char
*uuid)
+{
+ NMOPENCONNECTPluginPrivate *priv = NM_OPENCONNECT_PLUGIN_GET_PRIVATE
(plugin);
+
+ if (!uuid || !priv->uuid || !priv->cookie_validity ||
strcmp(priv->uuid, uuid))
+ return FALSE;
+
+ /* Only use cached cookie if it's valid for at least an hour */
+ if ((priv->cookie_start + priv->cookie_validity) > time(NULL) + 3600)
+ return TRUE;
+
+ return FALSE;
+}
+
+static gboolean
real_need_secrets (NMVPNPlugin *plugin,
NMConnection *connection,
char **setting_name,
GError **error)
{
+ NMOPENCONNECTPluginPrivate *priv = NM_OPENCONNECT_PLUGIN_GET_PRIVATE
(plugin);
NMSettingVPN *s_vpn;
+ const char *gateway, *cookie, *gwcert, *uuid;
g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+ uuid = nm_connection_get_uuid (connection);
s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection,
NM_TYPE_SETTING_VPN));
if (!s_vpn) {
g_set_error (error,
@@ -530,18 +565,26 @@ real_need_secrets (NMVPNPlugin *plugin,
/* We just need the WebVPN cookie, and the final IP address of the
gateway
(after HTTP redirects, which do happen). All the certificate/SecurID
nonsense can be handled for us, in the user's context, by
auth-dialog */
- if (!nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GATEWAY)) {
- *setting_name = NM_SETTING_VPN_SETTING_NAME;
- return TRUE;
- }
- if (!nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_COOKIE)) {
- *setting_name = NM_SETTING_VPN_SETTING_NAME;
- return TRUE;
- }
- if (!nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GWCERT)) {
+ gateway = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GATEWAY);
+ cookie = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_COOKIE);
+ gwcert = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GWCERT);
+ if (!gateway || !cookie || !gwcert) {
+ if (cached_secrets_valid(plugin, s_vpn, uuid))
+ return FALSE;
+
*setting_name = NM_SETTING_VPN_SETTING_NAME;
return TRUE;
}
+
+ g_free(priv->uuid);
+ priv->uuid = g_strdup(uuid);
+ g_free(priv->cookie);
+ priv->cookie = g_strdup(cookie);
+ g_free(priv->gwcert);
+ priv->gwcert = g_strdup(gwcert);
+ g_free(priv->gateway);
+ priv->gateway = g_strdup(gateway);
+ priv->cookie_start = time(NULL);
return FALSE;
}
@@ -629,6 +672,18 @@ quit_mainloop (NMOPENCONNECTPlugin *plugin, gpointer
user_data)
g_main_loop_quit ((GMainLoop *) user_data);
}
+static void got_config (NMOPENCONNECTPlugin *plugin, GHashTable *config,
+ gpointer user_data)
+{
+ NMOPENCONNECTPluginPrivate *priv = NM_OPENCONNECT_PLUGIN_GET_PRIVATE
(plugin);
+ GValue *val = g_hash_table_lookup (config,
"openconnect_session_timeout");
+
+ if (!val)
+ return;
+
+ priv->cookie_validity = g_value_get_uint(val);
+}
+
int main (int argc, char *argv[])
{
NMOPENCONNECTPlugin *plugin;
@@ -684,6 +739,8 @@ int main (int argc, char *argv[])
if (!persist)
g_signal_connect (plugin, "quit", G_CALLBACK (quit_mainloop),
loop);
+ g_signal_connect (plugin, "config", G_CALLBACK (got_config), plugin);
+
setup_signals ();
g_main_loop_run (loop);
--
dwmw2
smime.p7s
Description: S/MIME cryptographic signature
_______________________________________________ networkmanager-list mailing list [email protected] https://mail.gnome.org/mailman/listinfo/networkmanager-list
