charon-nm: Support reauthentication and redirection
authorTobias Brunner <tobias@strongswan.org>
Thu, 6 Feb 2020 16:36:46 +0000 (17:36 +0100)
committerTobias Brunner <tobias@strongswan.org>
Fri, 14 Feb 2020 12:55:42 +0000 (13:55 +0100)
src/charon-nm/nm/nm_service.c

index b096ad0..2f8206d 100644 (file)
@@ -248,57 +248,82 @@ static void signal_failure(NMVpnServicePlugin *plugin, NMVpnPluginFailure failur
        nm_vpn_service_plugin_failure(plugin, failure);
 }
 
-/**
- * Implementation of listener_t.ike_state_change
- */
-static bool ike_state_change(listener_t *listener, ike_sa_t *ike_sa,
-                                                        ike_sa_state_t state)
+METHOD(listener_t, ike_state_change, bool,
+       NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, ike_sa_state_t state)
 {
-       NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
-
-       if (private->ike_sa == ike_sa && state == IKE_DESTROYING)
+       if (this->ike_sa == ike_sa && state == IKE_DESTROYING)
        {
-               signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
+               signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
                return FALSE;
        }
        return TRUE;
 }
 
-/**
- * Implementation of listener_t.child_state_change
- */
-static bool child_state_change(listener_t *listener, ike_sa_t *ike_sa,
-                                                          child_sa_t *child_sa, child_sa_state_t state)
+METHOD(listener_t, child_state_change, bool,
+       NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+       child_sa_state_t state)
 {
-       NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
-
-       if (private->ike_sa == ike_sa && state == CHILD_DESTROYING)
+       if (this->ike_sa == ike_sa && state == CHILD_DESTROYING)
        {
-               signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
+               signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
                return FALSE;
        }
        return TRUE;
 }
 
-/**
- * Implementation of listener_t.child_updown
- */
-static bool child_updown(listener_t *listener, ike_sa_t *ike_sa,
-                                                child_sa_t *child_sa, bool up)
+METHOD(listener_t, ike_rekey, bool,
+       NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new)
 {
-       NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
+       if (this->ike_sa == old)
+       {       /* follow a rekeyed IKE_SA */
+               this->ike_sa = new;
+       }
+       return TRUE;
+}
+
+METHOD(listener_t, ike_reestablish_pre, bool,
+       NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new)
+{
+       if (this->ike_sa == old)
+       {       /* ignore child state changes during redirects etc. (task migration) */
+               this->listener.child_state_change = NULL;
+       }
+       return TRUE;
+}
 
-       if (private->ike_sa == ike_sa)
+METHOD(listener_t, ike_reestablish_post, bool,
+       NMStrongswanPluginPrivate *this, ike_sa_t *old, ike_sa_t *new,
+       bool initiated)
+{
+       if (this->ike_sa == old && initiated)
+       {       /* if we get redirected during IKE_AUTH we just migrate to the new SA */
+               this->ike_sa = new;
+               /* re-register hooks to detect initiation failures */
+               this->listener.ike_state_change = _ike_state_change;
+               this->listener.child_state_change = _child_state_change;
+       }
+       return TRUE;
+}
+
+METHOD(listener_t, child_updown, bool,
+       NMStrongswanPluginPrivate *this, ike_sa_t *ike_sa, child_sa_t *child_sa,
+       bool up)
+{
+       if (this->ike_sa == ike_sa)
        {
                if (up)
                {       /* disable initiate-failure-detection hooks */
-                       private->listener.ike_state_change = NULL;
-                       private->listener.child_state_change = NULL;
-                       signal_ip_config(private->plugin, ike_sa, child_sa);
+                       this->listener.ike_state_change = NULL;
+                       this->listener.child_state_change = NULL;
+                       signal_ip_config(this->plugin, ike_sa, child_sa);
                }
                else
                {
-                       signal_failure(private->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
+                       if (ike_sa->has_condition(ike_sa, COND_REAUTHENTICATING))
+                       {       /* we ignore this during reauthentication */
+                               return TRUE;
+                       }
+                       signal_failure(this->plugin, NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
                        return FALSE;
                }
        }
@@ -306,20 +331,6 @@ static bool child_updown(listener_t *listener, ike_sa_t *ike_sa,
 }
 
 /**
- * Implementation of listener_t.ike_rekey
- */
-static bool ike_rekey(listener_t *listener, ike_sa_t *old, ike_sa_t *new)
-{
-       NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener;
-
-       if (private->ike_sa == old)
-       {       /* follow a rekeyed IKE_SA */
-               private->ike_sa = new;
-       }
-       return TRUE;
-}
-
-/**
  * Find a certificate for which we have a private key on a smartcard
  */
 static identification_t *find_smartcard_key(NMStrongswanPluginPrivate *priv,
@@ -827,8 +838,8 @@ static gboolean connect_(NMVpnServicePlugin *plugin, NMConnection *connection,
         * Register listener, enable  initiate-failure-detection hooks
         */
        priv->ike_sa = ike_sa;
-       priv->listener.ike_state_change = ike_state_change;
-       priv->listener.child_state_change = child_state_change;
+       priv->listener.ike_state_change = _ike_state_change;
+       priv->listener.child_state_change = _child_state_change;
        charon->bus->add_listener(charon->bus, &priv->listener);
 
        /**
@@ -968,8 +979,10 @@ static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin)
        priv = NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin);
        priv->plugin = NM_VPN_SERVICE_PLUGIN(plugin);
        memset(&priv->listener, 0, sizeof(listener_t));
-       priv->listener.child_updown = child_updown;
-       priv->listener.ike_rekey = ike_rekey;
+       priv->listener.child_updown = _child_updown;
+       priv->listener.ike_rekey = _ike_rekey;
+       priv->listener.ike_reestablish_pre = _ike_reestablish_pre;
+       priv->listener.ike_reestablish_post = _ike_reestablish_post;
        priv->name = NULL;
 }