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

Attachment: smime.p7s
Description: S/MIME cryptographic signature

_______________________________________________
networkmanager-list mailing list
[email protected]
https://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to