android: Handle and store IETF remediation instructions
authorTobias Brunner <tobias@strongswan.org>
Fri, 17 May 2013 11:15:14 +0000 (13:15 +0200)
committerTobias Brunner <tobias@strongswan.org>
Mon, 8 Jul 2013 16:49:28 +0000 (18:49 +0200)
src/frontends/android/jni/libandroidbridge/byod/imc_android.c
src/frontends/android/jni/libandroidbridge/charonservice.c
src/frontends/android/jni/libandroidbridge/charonservice.h
src/frontends/android/src/org/strongswan/android/logic/CharonVpnService.java
src/frontends/android/src/org/strongswan/android/logic/VpnStateService.java

index 7067e1f..c60f7ca 100644 (file)
@@ -31,6 +31,7 @@
 #include <ietf/ietf_attr_installed_packages.h>
 #include <ietf/ietf_attr_pa_tnc_error.h>
 #include <ietf/ietf_attr_product_info.h>
+#include <ietf/ietf_attr_remediation_instr.h>
 #include <ietf/ietf_attr_string_version.h>
 #include <ita/ita_attr.h>
 #include <ita/ita_attr_get_settings.h>
@@ -317,6 +318,24 @@ static void handle_ietf_attribute(pen_type_t attr_type, pa_tnc_attr_t *attr,
                }
                enumerator->destroy(enumerator);
        }
+       else if (attr_type.type == IETF_ATTR_REMEDIATION_INSTRUCTIONS)
+       {
+               ietf_attr_remediation_instr_t *attr_cast;
+               pen_type_t param;
+               chunk_t str;
+               char *instr;
+
+               attr_cast = (ietf_attr_remediation_instr_t*)attr;
+               param = attr_cast->get_parameters_type(attr_cast);
+
+               if (pen_type_is(param, PEN_IETF, IETF_REMEDIATION_PARAMETERS_STRING))
+               {
+                       str = attr_cast->get_string(attr_cast, NULL);
+                       instr = strndup(str.ptr, str.len);
+                       charonservice->add_remediation_instr(charonservice, instr);
+                       free (instr);
+               }
+       }
 }
 
 /**
index 115b532..03599b7 100644 (file)
@@ -186,6 +186,37 @@ failed:
        return success;
 }
 
+METHOD(charonservice_t, add_remediation_instr, bool,
+       private_charonservice_t *this, char *instr)
+{
+       JNIEnv *env;
+       jmethodID method_id;
+       jstring jinstr;
+       bool success = FALSE;
+
+       androidjni_attach_thread(&env);
+
+       method_id = (*env)->GetMethodID(env, android_charonvpnservice_class,
+                                                                       "addRemediationInstruction",
+                                                                       "(Ljava/lang/String;)V");
+       if (!method_id)
+       {
+               goto failed;
+       }
+       jinstr = (*env)->NewStringUTF(env, instr);
+       if (!jinstr)
+       {
+               goto failed;
+       }
+       (*env)->CallVoidMethod(env, this->vpn_service, method_id, jinstr);
+       success = !androidjni_exception_occurred(env);
+
+failed:
+       androidjni_exception_occurred(env);
+       androidjni_detach_thread();
+       return success;
+}
+
 /**
  * Bypass a single socket
  */
@@ -491,6 +522,7 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
                .public = {
                        .update_status = _update_status,
                        .update_imc_state = _update_imc_state,
+                       .add_remediation_instr = _add_remediation_instr,
                        .bypass_socket = _bypass_socket,
                        .get_trusted_certificates = _get_trusted_certificates,
                        .get_user_certificate = _get_user_certificate,
index 90f5bc9..0c71d87 100644 (file)
@@ -91,6 +91,14 @@ struct charonservice_t {
        bool (*update_imc_state)(charonservice_t *this, android_imc_state_t state);
 
        /**
+        * Add a remediation instruction via JNI
+        *
+        * @param instr                 remediation instruction
+        * @return                              TRUE on success
+        */
+       bool (*add_remediation_instr)(charonservice_t *this, char *instr);
+
+       /**
         * Install a bypass policy for the given socket using the protect() Method
         * of the Android VpnService interface.
         *
index 9f920a9..bc90386 100644 (file)
@@ -28,6 +28,7 @@ import org.strongswan.android.data.VpnProfileDataSource;
 import org.strongswan.android.logic.VpnStateService.ErrorState;
 import org.strongswan.android.logic.VpnStateService.State;
 import org.strongswan.android.logic.imc.ImcState;
+import org.strongswan.android.logic.imc.RemediationInstruction;
 import org.strongswan.android.ui.MainActivity;
 
 import android.app.PendingIntent;
@@ -390,6 +391,26 @@ public class CharonVpnService extends VpnService implements Runnable
        }
 
        /**
+        * Add a remediation instruction to the VPN state service.
+        * Called via JNI by different threads (but not concurrently).
+        *
+        * @param xml XML text
+        */
+       public void addRemediationInstruction(String xml)
+       {
+               for (RemediationInstruction instruction : RemediationInstruction.fromXml(xml))
+               {
+                       synchronized (mServiceLock)
+                       {
+                               if (mService != null)
+                               {
+                                       mService.addRemediationInstruction(instruction);
+                               }
+                       }
+               }
+       }
+
+       /**
         * Function called via JNI to generate a list of DER encoded CA certificates
         * as byte array.
         *
index 62ca31f..2c530ba 100644 (file)
 package org.strongswan.android.logic;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.concurrent.Callable;
 
 import org.strongswan.android.data.VpnProfile;
 import org.strongswan.android.logic.imc.ImcState;
+import org.strongswan.android.logic.imc.RemediationInstruction;
 
 import android.app.Service;
 import android.content.Context;
@@ -38,6 +41,7 @@ public class VpnStateService extends Service
        private State mState = State.DISABLED;
        private ErrorState mError = ErrorState.NO_ERROR;
        private ImcState mImcState = ImcState.UNKNOWN;
+       private final LinkedList<RemediationInstruction> mRemediationInstructions = new LinkedList<RemediationInstruction>();
 
        public enum State
        {
@@ -159,6 +163,16 @@ public class VpnStateService extends Service
        }
 
        /**
+        * Get the remediation instructions, if any.
+        *
+        * @return read-only list of instructions
+        */
+       public List<RemediationInstruction> getRemediationInstructions()
+       {       /* only updated from the main thread so no synchronization needed */
+               return Collections.unmodifiableList(mRemediationInstructions);
+       }
+
+       /**
         * Disconnect any existing connection and shutdown the daemon, the
         * VpnService is not stopped but it is reset so new connections can be
         * started.
@@ -277,6 +291,8 @@ public class VpnStateService extends Service
        /**
         * Set the current IMC state and notify all listeners, if changed.
         *
+        * Setting the state to UNKNOWN clears all remediation instructions.
+        *
         * May be called from threads other than the main thread.
         *
         * @param error error state
@@ -287,6 +303,10 @@ public class VpnStateService extends Service
                        @Override
                        public Boolean call() throws Exception
                        {
+                               if (state == ImcState.UNKNOWN)
+                               {
+                                       VpnStateService.this.mRemediationInstructions.clear();
+                               }
                                if (VpnStateService.this.mImcState != state)
                                {
                                        VpnStateService.this.mImcState = state;
@@ -296,4 +316,25 @@ public class VpnStateService extends Service
                        }
                });
        }
+
+       /**
+        * Add the given remediation instruction to the internal list.  Listeners
+        * are not notified.
+        *
+        * Instructions are cleared if the IMC state is set to UNKNOWN.
+        *
+        * May be called from threads other than the main thread.
+        *
+        * @param instruction remediation instruction
+        */
+       public void addRemediationInstruction(final RemediationInstruction instruction)
+       {
+               mHandler.post(new Runnable() {
+                       @Override
+                       public void run()
+                       {
+                               VpnStateService.this.mRemediationInstructions.add(instruction);
+                       }
+               });
+       }
 }