Merge branch 'android-byod'

Adds support for EAP-TNC with a custom Android-specific IMC that
collects data such as installed packages, file hashes or system
settings.

Some parts of the implementation are based on the bachelor semester
project 'strongSwan Android 4 Client with Endpoint Assessment' by
Christoph Bühler and Patrick Lötscher.
This commit is contained in:
Tobias Brunner
2013-07-08 18:50:09 +02:00
86 changed files with 4227 additions and 117 deletions
+5 -1
View File
@@ -37,4 +37,8 @@ apidoc/
coverage/ coverage/
*.gcno *.gcno
*.gcda *.gcda
*.gcov *.gcov
.cproject
.project
.metadata/
.settings/
+11
View File
@@ -13,6 +13,17 @@ add_plugin = $(if $(call plugin_enabled,$(1)), \
) \ ) \
) \ ) \
) )
add_plugin_subdirs = $(if $(call plugin_enabled,$(1)), \
$(patsubst $(LOCAL_PATH)/%,%, \
$(wildcard \
$(subst %,$(subst -,_,$(strip $(1))), \
$(addprefix $(LOCAL_PATH)/plugins/%/,$(addsuffix /*.c, \
$(strip $(2)) \
)) \
) \
) \
) \
)
# strongSwan version, replaced by top Makefile # strongSwan version, replaced by top Makefile
strongswan_VERSION := "@PACKAGE_VERSION@" strongswan_VERSION := "@PACKAGE_VERSION@"
+2 -1
View File
@@ -100,7 +100,8 @@ strongswan_BUILD := \
libhydra \ libhydra \
libstrongswan \ libstrongswan \
libtncif \ libtncif \
libtnccs libtnccs \
libimcv
ifneq ($(strongswan_BUILD_STARTER),) ifneq ($(strongswan_BUILD_STARTER),)
strongswan_BUILD += \ strongswan_BUILD += \
@@ -54,6 +54,10 @@
android:name=".ui.LogActivity" android:name=".ui.LogActivity"
android:label="@string/log_title" > android:label="@string/log_title" >
</activity> </activity>
<activity
android:name=".ui.RemediationInstructionsActivity"
android:label="@string/remediation_instructions_title" >
</activity>
<activity <activity
android:name=".ui.VpnProfileSelectActivity" android:name=".ui.VpnProfileSelectActivity"
android:label="@string/strongswan_shortcut" > android:label="@string/strongswan_shortcut" >
+32 -9
View File
@@ -1,11 +1,20 @@
LOCAL_PATH := $(call my-dir) LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS) include $(CLEAR_VARS)
# use "bring your own device" (BYOD) features (also see USE_BYOD in
# MainActivity.java)
strongswan_USE_BYOD := true
strongswan_CHARON_PLUGINS := android-log openssl fips-prf random nonce pubkey \ strongswan_CHARON_PLUGINS := android-log openssl fips-prf random nonce pubkey \
pkcs1 pkcs8 pem xcbc hmac socket-default kernel-netlink \ pkcs1 pkcs8 pem xcbc hmac socket-default kernel-netlink \
eap-identity eap-mschapv2 eap-md5 eap-gtc eap-identity eap-mschapv2 eap-md5 eap-gtc
strongswan_PLUGINS := $(strongswan_CHARON_PLUGINS) ifneq ($(strongswan_USE_BYOD),)
strongswan_BYOD_PLUGINS := eap-ttls eap-tnc tnc-imc tnc-tnccs tnccs-20
endif
strongswan_PLUGINS := $(strongswan_CHARON_PLUGINS) \
$(strongswan_BYOD_PLUGINS)
include $(LOCAL_PATH)/strongswan/Android.common.mk include $(LOCAL_PATH)/strongswan/Android.common.mk
@@ -52,12 +61,26 @@ strongswan_CFLAGS := \
-DDEV_RANDOM=\"/dev/random\" \ -DDEV_RANDOM=\"/dev/random\" \
-DDEV_URANDOM=\"/dev/urandom\" -DDEV_URANDOM=\"/dev/urandom\"
ifneq ($(strongswan_USE_BYOD),)
strongswan_CFLAGS += -DUSE_BYOD
endif
strongswan_BUILD := \
vstr \
openssl \
libandroidbridge \
strongswan/src/libipsec \
strongswan/src/libcharon \
strongswan/src/libhydra \
strongswan/src/libstrongswan
ifneq ($(strongswan_USE_BYOD),)
strongswan_BUILD += \
strongswan/src/libtnccs \
strongswan/src/libtncif \
strongswan/src/libimcv \
strongswan/src/libpts
endif
include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \ include $(addprefix $(LOCAL_PATH)/,$(addsuffix /Android.mk, \
vstr \ $(strongswan_BUILD)))
openssl \
libandroidbridge \
strongswan/src/libipsec \
strongswan/src/libcharon \
strongswan/src/libhydra \
strongswan/src/libstrongswan \
))
@@ -14,6 +14,12 @@ kernel/android_net.c \
kernel/network_manager.c \ kernel/network_manager.c \
vpnservice_builder.c vpnservice_builder.c
ifneq ($(strongswan_USE_BYOD),)
LOCAL_SRC_FILES += \
byod/imc_android_state.c \
byod/imc_android.c
endif
# build libandroidbridge ------------------------------------------------------- # build libandroidbridge -------------------------------------------------------
LOCAL_C_INCLUDES += \ LOCAL_C_INCLUDES += \
@@ -23,9 +29,22 @@ LOCAL_C_INCLUDES += \
$(strongswan_PATH)/src/libcharon \ $(strongswan_PATH)/src/libcharon \
$(strongswan_PATH)/src/libstrongswan $(strongswan_PATH)/src/libstrongswan
ifneq ($(strongswan_USE_BYOD),)
LOCAL_C_INCLUDES += \
$(strongswan_PATH)/src/libimcv \
$(strongswan_PATH)/src/libtncif \
$(strongswan_PATH)/src/libtnccs \
$(strongswan_PATH)/src/libpts \
$(strongswan_PATH)/src/libtls
endif
LOCAL_CFLAGS := $(strongswan_CFLAGS) \ LOCAL_CFLAGS := $(strongswan_CFLAGS) \
-DPLUGINS='"$(strongswan_CHARON_PLUGINS)"' -DPLUGINS='"$(strongswan_CHARON_PLUGINS)"'
ifneq ($(strongswan_USE_BYOD),)
LOCAL_CFLAGS += -DPLUGINS_BYOD='"$(strongswan_BYOD_PLUGINS)"'
endif
LOCAL_MODULE := libandroidbridge LOCAL_MODULE := libandroidbridge
LOCAL_MODULE_TAGS := optional LOCAL_MODULE_TAGS := optional
@@ -38,6 +57,8 @@ LOCAL_LDLIBS := -llog
LOCAL_SHARED_LIBRARIES := libstrongswan libhydra libipsec libcharon LOCAL_SHARED_LIBRARIES := libstrongswan libhydra libipsec libcharon
ifneq ($(strongswan_USE_BYOD),)
LOCAL_SHARED_LIBRARIES += libimcv libtncif libtnccs libpts
endif
include $(BUILD_SHARED_LIBRARY) include $(BUILD_SHARED_LIBRARY)
@@ -464,13 +464,18 @@ METHOD(listener_t, ike_reestablish, bool,
} }
static void add_auth_cfg_eap(private_android_service_t *this, static void add_auth_cfg_eap(private_android_service_t *this,
peer_cfg_t *peer_cfg) peer_cfg_t *peer_cfg, bool byod)
{ {
identification_t *user; identification_t *user;
auth_cfg_t *auth; auth_cfg_t *auth;
auth = auth_cfg_create(); auth = auth_cfg_create();
auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP); auth->add(auth, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_EAP);
if (byod)
{ /* use EAP-TTLS if BYOD is enabled */
auth->add(auth, AUTH_RULE_EAP_TYPE, EAP_TTLS);
}
user = identification_create_from_string(this->username); user = identification_create_from_string(this->username);
auth->add(auth, AUTH_RULE_IDENTITY, user); auth->add(auth, AUTH_RULE_IDENTITY, user);
@@ -549,9 +554,10 @@ static job_requeue_t initiate(private_android_service_t *this)
} }
} }
if (streq("ikev2-eap", this->type) || if (streq("ikev2-eap", this->type) ||
streq("ikev2-cert-eap", this->type)) streq("ikev2-cert-eap", this->type) ||
streq("ikev2-byod-eap", this->type))
{ {
add_auth_cfg_eap(this, peer_cfg); add_auth_cfg_eap(this, peer_cfg, strpfx(this->type, "ikev2-byod"));
} }
/* remote auth config */ /* remote auth config */
@@ -0,0 +1,725 @@
/*
* Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Copyright (C) 2011-2012 Andreas Steffen
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_android_state.h"
#include "../android_jni.h"
#include "../charonservice.h"
#include <tnc/tnc.h>
#include <libpts.h>
#include <imcv.h>
#include <imc/imc_agent.h>
#include <imc/imc_msg.h>
#include <pa_tnc/pa_tnc_msg.h>
#include <ietf/ietf_attr.h>
#include <ietf/ietf_attr_attr_request.h>
#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>
#include <tcg/tcg_pts_attr_file_meas.h>
#include <tcg/tcg_pts_attr_meas_algo.h>
#include <tcg/tcg_pts_attr_proto_caps.h>
#include <tcg/tcg_pts_attr_req_file_meas.h>
#include <os_info/os_info.h>
#include <tncif_pa_subtypes.h>
#include <pen/pen.h>
#include <utils/debug.h>
#include <stdio.h>
/* IMC definitions */
static const char imc_name[] = "Android";
static pen_type_t msg_types[] = {
{ PEN_IETF, PA_SUBTYPE_IETF_OPERATING_SYSTEM },
{ PEN_IETF, PA_SUBTYPE_IETF_VPN },
{ PEN_TCG, PA_SUBTYPE_TCG_PTS },
};
static imc_agent_t *imc_android;
/**
* AndroidImc object accessed via JNI
*/
static jobject android_imc;
/**
* AndroidImc class object
*/
static jclass android_imc_cls;
/**
* see section 3.8.1 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_initialize(TNC_IMCID imc_id,
TNC_Version min_version,
TNC_Version max_version,
TNC_Version *actual_version)
{
if (imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has already been initialized", imc_name);
return TNC_RESULT_ALREADY_INITIALIZED;
}
imc_android = imc_agent_create(imc_name, msg_types, countof(msg_types),
imc_id, actual_version);
if (!imc_android)
{
return TNC_RESULT_FATAL;
}
libpts_init();
if (min_version > TNC_IFIMC_VERSION_1 || max_version < TNC_IFIMC_VERSION_1)
{
DBG1(DBG_IMC, "no common IF-IMC version");
return TNC_RESULT_NO_COMMON_VERSION;
}
return TNC_RESULT_SUCCESS;
}
/**
* Update the state in the GUI.
*/
static void update_imc_state(TNC_ConnectionState state)
{
android_imc_state_t imc_state = ANDROID_IMC_STATE_UNKNOWN;
switch (state)
{ /* map connection states to the values used by the GUI */
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
imc_state = ANDROID_IMC_STATE_ALLOW;
break;
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
imc_state = ANDROID_IMC_STATE_ISOLATE;
break;
case TNC_CONNECTION_STATE_ACCESS_NONE:
imc_state = ANDROID_IMC_STATE_BLOCK;
break;
}
charonservice->update_imc_state(charonservice, imc_state);
}
/**
* see section 3.8.2 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_notifyconnectionchange(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_ConnectionState new_state)
{
imc_state_t *state;
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
switch (new_state)
{
case TNC_CONNECTION_STATE_CREATE:
state = imc_android_state_create(connection_id);
return imc_android->create_state(imc_android, state);
case TNC_CONNECTION_STATE_HANDSHAKE:
if (imc_android->change_state(imc_android, connection_id, new_state,
&state) != TNC_RESULT_SUCCESS)
{
return TNC_RESULT_FATAL;
}
state->set_result(state, imc_id,
TNC_IMV_EVALUATION_RESULT_DONT_KNOW);
return TNC_RESULT_SUCCESS;
case TNC_CONNECTION_STATE_DELETE:
return imc_android->delete_state(imc_android, connection_id);
case TNC_CONNECTION_STATE_ACCESS_ALLOWED:
case TNC_CONNECTION_STATE_ACCESS_ISOLATED:
case TNC_CONNECTION_STATE_ACCESS_NONE:
update_imc_state(new_state);
/* fall-through */
default:
return imc_android->change_state(imc_android, connection_id,
new_state, NULL);
}
}
/**
* Convert the native C strings in the enumerator to a Java String array.
* The given enumerator gets destroyed.
*/
static jobjectArray string_array_create(JNIEnv *env, enumerator_t *enumerator)
{
linked_list_t *list;
jobjectArray jarray;
jstring jstring;
char *native;
jclass cls;
int i = 0;
cls = (*env)->FindClass(env, "java/lang/String");
list = linked_list_create_from_enumerator(enumerator);
jarray = (*env)->NewObjectArray(env, list->get_count(list), cls, NULL);
if (!jarray)
{
goto failed;
}
enumerator = list->create_enumerator(list);
while (enumerator->enumerate(enumerator, (void**)&native))
{
jstring = (*env)->NewStringUTF(env, native);
if (!jstring)
{
enumerator->destroy(enumerator);
goto failed;
}
(*env)->SetObjectArrayElement(env, jarray, i++, jstring);
}
enumerator->destroy(enumerator);
list->destroy(list);
return jarray;
failed:
androidjni_exception_occurred(env);
list->destroy(list);
return NULL;
}
/**
* Get a measurement for the given attribute type from the Android IMC.
* NULL is returned if no measurement is available or an error occurred.
*
* The optional args is an enumerator over char* (gets destroyed).
*/
static pa_tnc_attr_t *get_measurement(pen_type_t attr_type, enumerator_t *args)
{
JNIEnv *env;
pa_tnc_attr_t *attr;
jmethodID method_id;
jbyteArray jmeasurement;
jobjectArray jargs = NULL;
chunk_t data;
androidjni_attach_thread(&env);
if (args)
{
jargs = string_array_create(env, args);
if (!jargs)
{
goto failed;
}
method_id = (*env)->GetMethodID(env, android_imc_cls, "getMeasurement",
"(II[Ljava/lang/String;)[B");
}
else
{
method_id = (*env)->GetMethodID(env, android_imc_cls, "getMeasurement",
"(II)[B");
}
if (!method_id)
{
goto failed;
}
jmeasurement = (*env)->CallObjectMethod(env, android_imc, method_id,
attr_type.vendor_id, attr_type.type,
jargs);
if (!jmeasurement || androidjni_exception_occurred(env))
{
goto failed;
}
data = chunk_create((*env)->GetByteArrayElements(env, jmeasurement, NULL),
(*env)->GetArrayLength(env, jmeasurement));
if (!data.ptr)
{
goto failed;
}
attr = imcv_pa_tnc_attributes->create(imcv_pa_tnc_attributes,
attr_type.vendor_id, attr_type.type,
data);
(*env)->ReleaseByteArrayElements(env, jmeasurement, data.ptr, JNI_ABORT);
androidjni_detach_thread();
return attr;
failed:
androidjni_exception_occurred(env);
androidjni_detach_thread();
return NULL;
}
/**
* Add the measurement for the requested attribute type with optional
* arguments (enumerator over char*, gets destroyed).
*/
static void add_measurement(pen_type_t attr_type, imc_msg_t *msg,
enumerator_t *args)
{
pa_tnc_attr_t *attr;
enum_name_t *pa_attr_names;
attr = get_measurement(attr_type, args);
if (attr)
{
msg->add_attribute(msg, attr);
return;
}
pa_attr_names = imcv_pa_tnc_attributes->get_names(imcv_pa_tnc_attributes,
attr_type.vendor_id);
if (pa_attr_names)
{
DBG1(DBG_IMC, "no measurement available for PA-TNC attribute type "
"'%N/%N' 0x%06x/0x%08x", pen_names, attr_type.vendor_id,
pa_attr_names, attr_type.type, attr_type.vendor_id, attr_type.type);
}
else
{
DBG1(DBG_IMC, "no measurement available for PA-TNC attribute type '%N' "
"0x%06x/0x%08x", pen_names, attr_type.vendor_id,
attr_type.vendor_id, attr_type.type);
}
}
/**
* Handle an IETF attribute
*/
static void handle_ietf_attribute(pen_type_t attr_type, pa_tnc_attr_t *attr,
imc_msg_t *out_msg)
{
if (attr_type.type == IETF_ATTR_ATTRIBUTE_REQUEST)
{
ietf_attr_attr_request_t *attr_cast;
pen_type_t *entry;
enumerator_t *enumerator;
attr_cast = (ietf_attr_attr_request_t*)attr;
enumerator = attr_cast->create_enumerator(attr_cast);
while (enumerator->enumerate(enumerator, &entry))
{
add_measurement(*entry, out_msg, NULL);
}
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);
}
}
}
/**
* Handle an ITA attribute
*/
static void handle_ita_attribute(pen_type_t attr_type, pa_tnc_attr_t *attr,
imc_msg_t *out_msg)
{
if (attr_type.type == ITA_ATTR_GET_SETTINGS)
{
ita_attr_get_settings_t *attr_cast;
attr_cast = (ita_attr_get_settings_t*)attr;
add_measurement((pen_type_t){ PEN_ITA, ITA_ATTR_SETTINGS },
out_msg, attr_cast->create_enumerator(attr_cast));
}
}
/**
* Handle a TCG attribute
*/
static void handle_tcg_attribute(imc_android_state_t *state,
pen_type_t attr_type, pa_tnc_attr_t *attr,
imc_msg_t *out_msg)
{
pts_t *pts;
pts = state->get_pts(state);
switch (attr_type.type)
{
case TCG_PTS_REQ_PROTO_CAPS:
{
tcg_pts_attr_proto_caps_t *attr_cast;
pts_proto_caps_flag_t caps;
attr_cast = (tcg_pts_attr_proto_caps_t*)attr;
caps = attr_cast->get_flags(attr_cast) & pts->get_proto_caps(pts);
pts->set_proto_caps(pts, caps);
attr = tcg_pts_attr_proto_caps_create(caps, FALSE);
out_msg->add_attribute(out_msg, attr);
break;
}
case TCG_PTS_MEAS_ALGO:
{
tcg_pts_attr_meas_algo_t *attr_cast;
pts_meas_algorithms_t supported, algo;
if (!pts_meas_algo_probe(&supported))
{
attr = pts_hash_alg_error_create(PTS_MEAS_ALGO_NONE);
out_msg->add_attribute(out_msg, attr);
break;
}
attr_cast = (tcg_pts_attr_meas_algo_t*)attr;
algo = pts_meas_algo_select(supported,
attr_cast->get_algorithms(attr_cast));
if (algo == PTS_MEAS_ALGO_NONE)
{
attr = pts_hash_alg_error_create(supported);
out_msg->add_attribute(out_msg, attr);
break;
}
pts->set_meas_algorithm(pts, algo);
attr = tcg_pts_attr_meas_algo_create(algo, TRUE);
out_msg->add_attribute(out_msg, attr);
break;
}
case TCG_PTS_REQ_FILE_MEAS:
{
tcg_pts_attr_req_file_meas_t *attr_cast;
pts_file_meas_t *measurements;
pts_error_code_t pts_error;
u_int32_t delim;
u_int16_t req_id;
bool is_dir;
char *path;
attr_cast = (tcg_pts_attr_req_file_meas_t*)attr;
path = attr_cast->get_pathname(attr_cast);
if (!pts->is_path_valid(pts, path, &pts_error))
{ /* silently ignore internal errors */
break;
}
else if (pts_error)
{
attr = ietf_attr_pa_tnc_error_create(pen_type_create(PEN_TCG,
pts_error), attr->get_value(attr));
out_msg->add_attribute(out_msg, attr);
break;
}
delim = attr_cast->get_delimiter(attr_cast);
if (delim != SOLIDUS_UTF && delim != REVERSE_SOLIDUS_UTF)
{
attr = ietf_attr_pa_tnc_error_create(pen_type_create(PEN_TCG,
TCG_PTS_INVALID_DELIMITER), attr->get_value(attr));
out_msg->add_attribute(out_msg, attr);
break;
}
req_id = attr_cast->get_request_id(attr_cast);
is_dir = attr_cast->get_directory_flag(attr_cast);
DBG1(DBG_IMC, "measurement request %d for %s '%s'", req_id,
is_dir ? "directory" : "file", path);
measurements = pts_file_meas_create_from_path(req_id, path, is_dir,
TRUE, pts->get_meas_algorithm(pts));
if (!measurements)
{
attr = ietf_attr_pa_tnc_error_create(pen_type_create(PEN_TCG,
TCG_PTS_FILE_NOT_FOUND), attr->get_value(attr));
out_msg->add_attribute(out_msg, attr);
break;
}
attr = tcg_pts_attr_file_meas_create(measurements);
attr->set_noskip_flag(attr, TRUE);
out_msg->add_attribute(out_msg, attr);
break;
}
default:
DBG1(DBG_IMC, "received unsupported TCG attribute '%N'",
tcg_attr_names, attr_type.type);
break;
}
}
/**
* see section 3.8.3 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_beginhandshake(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
imc_state_t *state;
imc_msg_t *out_msg;
TNC_Result result = TNC_RESULT_SUCCESS;
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_android->get_state(imc_android, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
if (lib->settings->get_bool(lib->settings,
"android.imc.send_os_info", TRUE))
{
out_msg = imc_msg_create(imc_android, state, connection_id, imc_id,
TNC_IMVID_ANY, msg_types[0]);
add_measurement((pen_type_t){ PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION },
out_msg, NULL);
add_measurement((pen_type_t){ PEN_IETF, IETF_ATTR_STRING_VERSION },
out_msg, NULL);
add_measurement((pen_type_t){ PEN_ITA, ITA_ATTR_DEVICE_ID },
out_msg, NULL);
/* send PA-TNC message with the excl flag not set */
result = out_msg->send(out_msg, FALSE);
out_msg->destroy(out_msg);
}
return result;
}
static TNC_Result receive_message(imc_android_state_t *state, imc_msg_t *in_msg)
{
imc_msg_t *out_msg;
enumerator_t *enumerator;
pa_tnc_attr_t *attr;
pen_type_t attr_type;
TNC_Result result;
bool fatal_error = FALSE;
/* parse received PA-TNC message and handle local and remote errors */
result = in_msg->receive(in_msg, &fatal_error);
if (result != TNC_RESULT_SUCCESS)
{
return result;
}
out_msg = imc_msg_create_as_reply(in_msg);
/* analyze PA-TNC attributes */
enumerator = in_msg->create_attribute_enumerator(in_msg);
while (enumerator->enumerate(enumerator, &attr))
{
attr_type = attr->get_type(attr);
switch (attr_type.vendor_id)
{
case PEN_IETF:
handle_ietf_attribute(attr_type, attr, out_msg);
continue;
case PEN_ITA:
handle_ita_attribute(attr_type, attr, out_msg);
continue;
case PEN_TCG:
handle_tcg_attribute(state, attr_type, attr, out_msg);
continue;
default:
continue;
}
}
enumerator->destroy(enumerator);
if (fatal_error)
{
result = TNC_RESULT_FATAL;
}
else
{
result = out_msg->send(out_msg, TRUE);
}
out_msg->destroy(out_msg);
return result;
}
/**
* see section 3.8.4 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_receivemessage(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_MessageType msg_type)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_android->get_state(imc_android, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_data(imc_android, state, connection_id,
msg_type, chunk_create(msg, msg_len));
result = receive_message((imc_android_state_t*)state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.6 of TCG TNC IF-IMV Specification 1.3
*/
static TNC_Result tnc_imc_receivemessagelong(TNC_IMCID imc_id,
TNC_ConnectionID connection_id,
TNC_UInt32 msg_flags,
TNC_BufferReference msg,
TNC_UInt32 msg_len,
TNC_VendorID msg_vid,
TNC_MessageSubtype msg_subtype,
TNC_UInt32 src_imv_id,
TNC_UInt32 dst_imc_id)
{
imc_state_t *state;
imc_msg_t *in_msg;
TNC_Result result;
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
if (!imc_android->get_state(imc_android, connection_id, &state))
{
return TNC_RESULT_FATAL;
}
in_msg = imc_msg_create_from_long_data(imc_android, state, connection_id,
src_imv_id, dst_imc_id,msg_vid, msg_subtype,
chunk_create(msg, msg_len));
result = receive_message((imc_android_state_t*)state, in_msg);
in_msg->destroy(in_msg);
return result;
}
/**
* see section 3.8.7 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_batchending(TNC_IMCID imc_id,
TNC_ConnectionID connection_id)
{
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return TNC_RESULT_SUCCESS;
}
/**
* see section 3.8.8 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_terminate(TNC_IMCID imc_id)
{
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
imc_android->destroy(imc_android);
imc_android = NULL;
libpts_deinit();
return TNC_RESULT_SUCCESS;
}
/**
* see section 4.2.8.1 of TCG TNC IF-IMC Specification 1.3
*/
static TNC_Result tnc_imc_providebindfunction(TNC_IMCID imc_id,
TNC_TNCC_BindFunctionPointer bind_function)
{
if (!imc_android)
{
DBG1(DBG_IMC, "IMC \"%s\" has not been initialized", imc_name);
return TNC_RESULT_NOT_INITIALIZED;
}
return imc_android->bind_functions(imc_android, bind_function);
}
/*
* Described in header
*/
bool imc_android_register(plugin_t *plugin, plugin_feature_t *feature,
bool reg, void *data)
{
JNIEnv *env;
jmethodID method_id;
jobject obj, context = (jobject)data;
jclass cls;
bool success = TRUE;
androidjni_attach_thread(&env);
if (reg)
{
cls = (*env)->FindClass(env, JNI_PACKAGE_STRING "/imc/AndroidImc");
if (!cls)
{
goto failed;
}
android_imc_cls = (*env)->NewGlobalRef(env, cls);
method_id = (*env)->GetMethodID(env, cls, "<init>",
"(Landroid/content/Context;)V");
if (!method_id)
{
goto failed;
}
obj = (*env)->NewObject(env, cls, method_id, context);
if (!obj)
{
goto failed;
}
android_imc = (*env)->NewGlobalRef(env, obj);
androidjni_detach_thread();
if (tnc->imcs->load_from_functions(tnc->imcs, "Android",
tnc_imc_initialize, tnc_imc_notifyconnectionchange,
tnc_imc_beginhandshake, tnc_imc_receivemessage,
tnc_imc_receivemessagelong, tnc_imc_batchending,
tnc_imc_terminate, tnc_imc_providebindfunction))
{
return TRUE;
}
failed:
DBG1(DBG_IMC, "initialization of Android IMC failed");
androidjni_exception_occurred(env);
success = FALSE;
}
if (android_imc)
{
(*env)->DeleteGlobalRef(env, android_imc);
android_imc = NULL;
}
if (android_imc_cls)
{
(*env)->DeleteGlobalRef(env, android_imc_cls);
android_imc_cls = NULL;
}
androidjni_detach_thread();
return success;
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup android_imc android_imc
* @{ @ingroup android_byod
*/
#ifndef ANDROID_IMC_H_
#define ANDROID_IMC_H_
/**
* Callback for the Android IMC plugin
*/
bool imc_android_register(plugin_t *plugin, plugin_feature_t *feature,
bool reg, void *data);
#endif /** ANDROID_IMC_H_ @}*/
@@ -0,0 +1,173 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Copyright (C) 2012 Andreas Steffen
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
#include "imc_android_state.h"
#include <tncif_names.h>
#include <utils/debug.h>
typedef struct private_imc_android_state_t private_imc_android_state_t;
/**
* Private data of an imc_state_t object.
*/
struct private_imc_android_state_t {
/**
* Public interface
*/
imc_android_state_t public;
/**
* TNCCS connection ID
*/
TNC_ConnectionID connection_id;
/**
* TNCCS connection state
*/
TNC_ConnectionState state;
/**
* Assessment/Evaluation Result
*/
TNC_IMV_Evaluation_Result result;
/**
* Does the TNCCS connection support long message types?
*/
bool has_long;
/**
* Does the TNCCS connection support exclusive delivery?
*/
bool has_excl;
/**
* Maximum PA-TNC message size for this TNCCS connection
*/
u_int32_t max_msg_len;
/**
* TCG Platform Trust Service (PTS)
*/
pts_t *pts;
};
METHOD(imc_state_t, get_connection_id, TNC_ConnectionID,
private_imc_android_state_t *this)
{
return this->connection_id;
}
METHOD(imc_state_t, has_long, bool,
private_imc_android_state_t *this)
{
return this->has_long;
}
METHOD(imc_state_t, has_excl, bool,
private_imc_android_state_t *this)
{
return this->has_excl;
}
METHOD(imc_state_t, set_flags, void,
private_imc_android_state_t *this, bool has_long, bool has_excl)
{
this->has_long = has_long;
this->has_excl = has_excl;
}
METHOD(imc_state_t, set_max_msg_len, void,
private_imc_android_state_t *this, u_int32_t max_msg_len)
{
this->max_msg_len = max_msg_len;
}
METHOD(imc_state_t, get_max_msg_len, u_int32_t,
private_imc_android_state_t *this)
{
return this->max_msg_len;
}
METHOD(imc_state_t, change_state, void,
private_imc_android_state_t *this, TNC_ConnectionState new_state)
{
this->state = new_state;
}
METHOD(imc_state_t, set_result, void,
private_imc_android_state_t *this, TNC_IMCID id, TNC_IMV_Evaluation_Result result)
{
this->result = result;
}
METHOD(imc_state_t, get_result, bool,
private_imc_android_state_t *this, TNC_IMCID id, TNC_IMV_Evaluation_Result *result)
{
if (result)
{
*result = this->result;
}
return this->result != TNC_IMV_EVALUATION_RESULT_DONT_KNOW;
}
METHOD(imc_state_t, destroy, void,
private_imc_android_state_t *this)
{
this->pts->destroy(this->pts);
free(this);
}
METHOD(imc_android_state_t, get_pts, pts_t*,
private_imc_android_state_t *this)
{
return this->pts;
}
/**
* Described in header.
*/
imc_state_t *imc_android_state_create(TNC_ConnectionID connection_id)
{
private_imc_android_state_t *this;
INIT(this,
.public = {
.interface = {
.get_connection_id = _get_connection_id,
.has_long = _has_long,
.has_excl = _has_excl,
.set_flags = _set_flags,
.set_max_msg_len = _set_max_msg_len,
.get_max_msg_len = _get_max_msg_len,
.change_state = _change_state,
.set_result = _set_result,
.get_result = _get_result,
.destroy = _destroy,
},
.get_pts = _get_pts,
},
.state = TNC_CONNECTION_STATE_CREATE,
.result = TNC_IMV_EVALUATION_RESULT_DONT_KNOW,
.connection_id = connection_id,
.pts = pts_create(TRUE),
);
return &this->public.interface;
}
@@ -0,0 +1,52 @@
/*
* Copyright (C) 2012 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
/**
* @defgroup imc_android_state imc_android_state
* @{ @ingroup android_byod
*/
#ifndef IMC_ANDROID_STATE_H_
#define IMC_ANDROID_STATE_H_
#include <imc/imc_state.h>
#include <pts/pts.h>
typedef struct imc_android_state_t imc_android_state_t;
/**
* Internal state of an imc_android_t connection instance
*/
struct imc_android_state_t {
/**
* imc_state_t interface
*/
imc_state_t interface;
/**
* Get TCG Platform Trust Service (PTS) object
*/
pts_t *(*get_pts)(imc_android_state_t *this);
};
/**
* Create an imc_android_state_t instance
*
* @param id connection ID
*/
imc_state_t* imc_android_state_create(TNC_ConnectionID id);
#endif /** IMC_ANDROID_STATE_H_ @}*/
@@ -30,6 +30,10 @@
#include "kernel/android_ipsec.h" #include "kernel/android_ipsec.h"
#include "kernel/android_net.h" #include "kernel/android_net.h"
#ifdef USE_BYOD
#include "byod/imc_android.h"
#endif
#include <daemon.h> #include <daemon.h>
#include <hydra.h> #include <hydra.h>
#include <ipsec.h> #include <ipsec.h>
@@ -158,6 +162,61 @@ failed:
return success; return success;
} }
METHOD(charonservice_t, update_imc_state, bool,
private_charonservice_t *this, android_imc_state_t state)
{
JNIEnv *env;
jmethodID method_id;
bool success = FALSE;
androidjni_attach_thread(&env);
method_id = (*env)->GetMethodID(env, android_charonvpnservice_class,
"updateImcState", "(I)V");
if (!method_id)
{
goto failed;
}
(*env)->CallVoidMethod(env, this->vpn_service, method_id, (jint)state);
success = !androidjni_exception_occurred(env);
failed:
androidjni_exception_occurred(env);
androidjni_detach_thread();
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 * Bypass a single socket
*/ */
@@ -357,7 +416,7 @@ static void initiate(char *type, char *gateway, char *username, char *password)
/** /**
* Initialize/deinitialize Android backend * Initialize/deinitialize Android backend
*/ */
static bool charonservice_register(void *plugin, plugin_feature_t *feature, static bool charonservice_register(plugin_t *plugin, plugin_feature_t *feature,
bool reg, void *data) bool reg, void *data)
{ {
private_charonservice_t *this = (private_charonservice_t*)charonservice; private_charonservice_t *this = (private_charonservice_t*)charonservice;
@@ -434,25 +493,37 @@ static void set_options(char *logfile)
lib->settings->set_str(lib->settings, lib->settings->set_str(lib->settings,
"charon.interfaces_ignore", "lo, tun0, tun1, tun2, tun3, " "charon.interfaces_ignore", "lo, tun0, tun1, tun2, tun3, "
"tun4"); "tun4");
#ifdef USE_BYOD
lib->settings->set_str(lib->settings,
"charon.plugins.eap-tnc.protocol", "tnccs-2.0");
lib->settings->set_bool(lib->settings,
"android.imc.send_os_info", TRUE);
lib->settings->set_str(lib->settings,
"libtnccs.tnc_config", "");
#endif
} }
/** /**
* Initialize the charonservice object * Initialize the charonservice object
*/ */
static void charonservice_init(JNIEnv *env, jobject service, jobject builder) static void charonservice_init(JNIEnv *env, jobject service, jobject builder,
jboolean byod)
{ {
private_charonservice_t *this; private_charonservice_t *this;
static plugin_feature_t features[] = { static plugin_feature_t features[] = {
PLUGIN_CALLBACK(kernel_ipsec_register, kernel_android_ipsec_create), PLUGIN_CALLBACK(kernel_ipsec_register, kernel_android_ipsec_create),
PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"), PLUGIN_PROVIDE(CUSTOM, "kernel-ipsec"),
PLUGIN_CALLBACK((plugin_feature_callback_t)charonservice_register, NULL), PLUGIN_CALLBACK(charonservice_register, NULL),
PLUGIN_PROVIDE(CUSTOM, "Android backend"), PLUGIN_PROVIDE(CUSTOM, "android-backend"),
PLUGIN_DEPENDS(CUSTOM, "libcharon"), PLUGIN_DEPENDS(CUSTOM, "libcharon"),
}; };
INIT(this, INIT(this,
.public = { .public = {
.update_status = _update_status, .update_status = _update_status,
.update_imc_state = _update_imc_state,
.add_remediation_instr = _add_remediation_instr,
.bypass_socket = _bypass_socket, .bypass_socket = _bypass_socket,
.get_trusted_certificates = _get_trusted_certificates, .get_trusted_certificates = _get_trusted_certificates,
.get_user_certificate = _get_user_certificate, .get_user_certificate = _get_user_certificate,
@@ -471,6 +542,21 @@ static void charonservice_init(JNIEnv *env, jobject service, jobject builder)
lib->plugins->add_static_features(lib->plugins, "androidbridge", features, lib->plugins->add_static_features(lib->plugins, "androidbridge", features,
countof(features), TRUE); countof(features), TRUE);
#ifdef USE_BYOD
if (byod)
{
plugin_feature_t byod_features[] = {
PLUGIN_CALLBACK(imc_android_register, this->vpn_service),
PLUGIN_PROVIDE(CUSTOM, "android-imc"),
PLUGIN_DEPENDS(CUSTOM, "android-backend"),
PLUGIN_DEPENDS(CUSTOM, "imc-manager"),
};
lib->plugins->add_static_features(lib->plugins, "android-byod",
byod_features, countof(byod_features), TRUE);
}
#endif
} }
/** /**
@@ -504,11 +590,11 @@ static void segv_handler(int signal)
* Initialize charon and the libraries via JNI * Initialize charon and the libraries via JNI
*/ */
JNI_METHOD(CharonVpnService, initializeCharon, void, JNI_METHOD(CharonVpnService, initializeCharon, void,
jobject builder, jstring jlogfile) jobject builder, jstring jlogfile, jboolean byod)
{ {
struct sigaction action; struct sigaction action;
struct utsname utsname; struct utsname utsname;
char *logfile; char *logfile, *plugins;
/* logging for library during initialization, as we have no bus yet */ /* logging for library during initialization, as we have no bus yet */
dbg = dbg_android; dbg = dbg_android;
@@ -551,7 +637,7 @@ JNI_METHOD(CharonVpnService, initializeCharon, void,
charon->load_loggers(charon, NULL, FALSE); charon->load_loggers(charon, NULL, FALSE);
charonservice_init(env, this, builder); charonservice_init(env, this, builder, byod);
if (uname(&utsname) != 0) if (uname(&utsname) != 0)
{ {
@@ -560,7 +646,18 @@ JNI_METHOD(CharonVpnService, initializeCharon, void,
DBG1(DBG_DMN, "Starting IKE charon daemon (strongSwan "VERSION", %s %s, %s)", DBG1(DBG_DMN, "Starting IKE charon daemon (strongSwan "VERSION", %s %s, %s)",
utsname.sysname, utsname.release, utsname.machine); utsname.sysname, utsname.release, utsname.machine);
if (!charon->initialize(charon, PLUGINS)) #ifdef PLUGINS_BYOD
if (byod)
{
plugins = PLUGINS " " PLUGINS_BYOD;
}
else
#endif
{
plugins = PLUGINS;
}
if (!charon->initialize(charon, plugins))
{ {
libcharon_deinit(); libcharon_deinit();
charonservice_deinit(env); charonservice_deinit(env);
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012 Tobias Brunner * Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager * Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
@@ -21,6 +21,9 @@
* @defgroup android_backend backend * @defgroup android_backend backend
* @ingroup libandroidbridge * @ingroup libandroidbridge
* *
* @defgroup android_byod byod
* @ingroup libandroidbridge
*
* @defgroup android_kernel kernel * @defgroup android_kernel kernel
* @ingroup libandroidbridge * @ingroup libandroidbridge
* *
@@ -38,6 +41,7 @@
#include <collections/linked_list.h> #include <collections/linked_list.h>
typedef enum android_vpn_state_t android_vpn_state_t; typedef enum android_vpn_state_t android_vpn_state_t;
typedef enum android_imc_state_t android_imc_state_t;
typedef struct charonservice_t charonservice_t; typedef struct charonservice_t charonservice_t;
/** /**
@@ -53,6 +57,16 @@ enum android_vpn_state_t {
CHARONSERVICE_GENERIC_ERROR, CHARONSERVICE_GENERIC_ERROR,
}; };
/**
* Final IMC state as defined in ImcState.java
*/
enum android_imc_state_t {
ANDROID_IMC_STATE_UNKNOWN = 0,
ANDROID_IMC_STATE_ALLOW = 1,
ANDROID_IMC_STATE_BLOCK = 2,
ANDROID_IMC_STATE_ISOLATE = 3,
};
/** /**
* Public interface of charonservice. * Public interface of charonservice.
* *
@@ -68,6 +82,22 @@ struct charonservice_t {
*/ */
bool (*update_status)(charonservice_t *this, android_vpn_state_t code); bool (*update_status)(charonservice_t *this, android_vpn_state_t code);
/**
* Update final IMC state in the Java domain (UI)
*
* @param state IMC state
* @return TRUE on success
*/
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 * Install a bypass policy for the given socket using the protect() Method
* of the Android VpnService interface. * of the Android VpnService interface.
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid
android:color="@color/panel_separator" />
</shape>
</item>
<item android:left="2dp">
<shape>
<solid
android:color="@color/panel_background" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2012-2013 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
-->
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape>
<solid
android:color="@color/panel_separator" />
</shape>
</item>
<item android:bottom="2dp">
<shape>
<solid
android:color="@color/panel_background" />
</shape>
</item>
</layer-list>
@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:baselineAligned="false" >
<fragment
class="org.strongswan.android.ui.RemediationInstructionsFragment"
android:id="@+id/remediation_instructions_fragment"
android:layout_height="match_parent"
android:layout_weight="1"
android:layout_width="0dp" />
<FrameLayout
android:layout_height="match_parent"
android:layout_weight="2"
android:layout_width="0dp"
android:background="@drawable/remediation_instruction_background_large"
android:padding="5dp" >
<fragment
class="org.strongswan.android.ui.RemediationInstructionFragment"
android:id="@+id/remediation_instruction_fragment"
android:layout_height="match_parent"
android:layout_width="match_parent" />
</FrameLayout>
</LinearLayout>
@@ -0,0 +1,69 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="2dp"
android:background="@drawable/state_background"
android:orientation="vertical" >
<LinearLayout
android:id="@+id/imc_state_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:orientation="vertical" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:layout_marginTop="10dp"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:text="@string/imc_state_label"
android:textColor="?android:textColorPrimary"
android:textSize="20sp" />
<TextView
android:id="@+id/imc_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text=""
android:textColor="?android:textColorSecondary"
android:textSize="20sp" />
</LinearLayout>
<TextView
android:id="@+id/action"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:layout_marginLeft="20dp"
android:layout_marginRight="20dp"
android:text="@string/show_remediation_instructions"
android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?android:attr/textColorSecondary" />
</LinearLayout>
</LinearLayout>
+7 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Tobias Brunner Copyright (C) 2012-2013 Tobias Brunner
Hochschule fuer Technik Rapperswil Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it This program is free software; you can redistribute it and/or modify it
@@ -24,6 +24,12 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" /> android:layout_height="wrap_content" />
<fragment
class="org.strongswan.android.ui.ImcStateFragment"
android:id="@+id/imc_state_frag"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<fragment <fragment
class="org.strongswan.android.ui.VpnProfileListFragment" class="org.strongswan.android.ui.VpnProfileListFragment"
android:id="@+id/profile_list_frag" android:id="@+id/profile_list_frag"
@@ -65,6 +65,11 @@
android:spinnerMode="dropdown" android:spinnerMode="dropdown"
android:entries="@array/vpn_types" /> android:entries="@array/vpn_types" />
<include
android:id="@+id/tnc_notice"
layout="@layout/two_line_button"
android:visibility="gone" />
<LinearLayout <LinearLayout
android:id="@+id/username_password_group" android:id="@+id/username_password_group"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -114,7 +119,7 @@
<include <include
android:id="@+id/select_user_certificate" android:id="@+id/select_user_certificate"
layout="@layout/certificate_selector" /> layout="@layout/two_line_button" />
</LinearLayout> </LinearLayout>
@@ -132,7 +137,7 @@
<include <include
android:id="@+id/select_certificate" android:id="@+id/select_certificate"
layout="@layout/certificate_selector" /> layout="@layout/two_line_button" />
</LinearLayout> </LinearLayout>
@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="5dp" >
<TextView
android:id="@+id/title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textIsSelectable="true"
android:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
android:id="@+id/description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:textIsSelectable="true"
android:textColor="?android:textColorSecondary"
android:textAppearance="?android:attr/textAppearanceMedium" />
<TextView
android:id="@+id/list_header"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="20dp"
android:textIsSelectable="true"
android:textAppearance="?android:attr/textAppearanceMedium" />
<include
layout="@android:layout/list_content"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="5dp" />
</LinearLayout>
@@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (C) 2013 Tobias Brunner
Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the
Free Software Foundation; either version 2 of the License, or (at your
option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details.
-->
<TwoLineListItem xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="8dip"
android:paddingTop="8dip"
android:background="?android:attr/activatedBackgroundIndicator"
android:minHeight="?android:attr/listPreferredItemHeight"
android:mode="twoLine" >
<TextView
android:id="@android:id/text1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginRight="15dp"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textIsSelectable="false" />
<TextView
android:id="@android:id/text2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@android:id/text1"
android:layout_alignLeft="@android:id/text1"
android:layout_alignRight="@android:id/text1"
android:textColor="?android:textColorSecondary"
android:textAppearance="?android:attr/textAppearanceSmall"
android:singleLine="true"
android:ellipsize="end"
android:textIsSelectable="false" />
</TwoLineListItem>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Tobias Brunner Copyright (C) 2013 Tobias Brunner
Hochschule fuer Technik Rapperswil Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it This program is free software; you can redistribute it and/or modify it
@@ -13,9 +13,9 @@
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
for more details. for more details.
--> -->
<shape xmlns:android="http://schemas.android.com/apk/res/android"> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/fragment_container">
<solid </FrameLayout>
android:color="#333" />
</shape>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Tobias Brunner Copyright (C) 2012-2013 Tobias Brunner
Copyright (C) 2012 Giuliano Grassi Copyright (C) 2012 Giuliano Grassi
Copyright (C) 2012 Ralf Sager Copyright (C) 2012 Ralf Sager
Hochschule fuer Technik Rapperswil Hochschule fuer Technik Rapperswil
@@ -18,8 +18,8 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout_margin="5dp" android:paddingBottom="2dp"
android:background="@drawable/vpn_state_background" android:background="@drawable/state_background"
android:orientation="vertical" > android:orientation="vertical" >
<GridLayout <GridLayout
@@ -83,9 +83,4 @@
style="?android:attr/borderlessButtonStyle" > style="?android:attr/borderlessButtonStyle" >
</Button> </Button>
<View
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="?android:attr/listDivider" />
</LinearLayout> </LinearLayout>
@@ -19,5 +19,6 @@
<item>IKEv2 EAP (Benutzername/Passwort)</item> <item>IKEv2 EAP (Benutzername/Passwort)</item>
<item>IKEv2 Zertifikat</item> <item>IKEv2 Zertifikat</item>
<item>IKEv2 Zertifikat + EAP (Benutzername/Passwort)</item> <item>IKEv2 Zertifikat + EAP (Benutzername/Passwort)</item>
<item>IKEv2 EAP-TNC (Benutzername/Passwort)</item>
</string-array> </string-array>
</resources> </resources>
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Tobias Brunner Copyright (C) 2012-2013 Tobias Brunner
Copyright (C) 2012 Giuliano Grassi Copyright (C) 2012 Giuliano Grassi
Copyright (C) 2012 Ralf Sager Copyright (C) 2012 Ralf Sager
Hochschule fuer Technik Rapperswil Hochschule fuer Technik Rapperswil
@@ -69,6 +69,9 @@
<string name="alert_text_no_input_username">Bitte geben Sie hier Ihren Benutzernamen ein</string> <string name="alert_text_no_input_username">Bitte geben Sie hier Ihren Benutzernamen ein</string>
<string name="alert_text_nocertfound_title">Kein CA-Zertifikat ausgewählt</string> <string name="alert_text_nocertfound_title">Kein CA-Zertifikat ausgewählt</string>
<string name="alert_text_nocertfound">Bitte wählen Sie eines aus oder aktivieren Sie <i>Automatisch wählen</i></string> <string name="alert_text_nocertfound">Bitte wählen Sie eines aus oder aktivieren Sie <i>Automatisch wählen</i></string>
<string name="tnc_notice_title">EAP-TNC kann Ihre Privatsphäre beeinträchtigen</string>
<string name="tnc_notice_subtitle">Gerätedaten werden an den Gateway-Betreiber gesendet</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) erlaubt Gateway-Betreibern den Gesundheitszustand von Endgeräten zu prüfen.&lt;/p>&lt;p>Dazu kann der Betreiber Daten verlangen, wie etwa eine eindeutige Identifikationsnummer, eine Liste der installierten Pakete, Systemeinstellungen oder kryptografische Prüfsummen von Dateien.&lt;/p>&lt;b>Solche Daten werden nur übermittelt nachdem die Identität des Gateways geprüft wurde.&lt;/b></string>
<!-- Trusted certificate selection --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">CA-Zertifikate</string> <string name="trusted_certs_title">CA-Zertifikate</string>
@@ -86,6 +89,15 @@
<string name="state_disabled">Kein aktives Profil</string> <string name="state_disabled">Kein aktives Profil</string>
<string name="state_error">Fehler</string> <string name="state_error">Fehler</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Eingeschränkt</string>
<string name="imc_state_block">Fehlgeschlagen</string>
<string name="show_remediation_instructions">Korrekturanweisungen anzeigen</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Korrekturanweisungen</string>
<!-- Dialogs --> <!-- Dialogs -->
<string name="login_title">Passwort eingeben um zu verbinden</string> <string name="login_title">Passwort eingeben um zu verbinden</string>
<string name="login_confirm">Verbinden</string> <string name="login_confirm">Verbinden</string>
@@ -94,6 +106,7 @@
<string name="error_unreachable">Gateway ist nicht erreichbar.</string> <string name="error_unreachable">Gateway ist nicht erreichbar.</string>
<string name="error_peer_auth_failed">Authentifizierung des Gateway ist fehlgeschlagen.</string> <string name="error_peer_auth_failed">Authentifizierung des Gateway ist fehlgeschlagen.</string>
<string name="error_auth_failed">Benutzerauthentifizierung ist fehlgeschlagen.</string> <string name="error_auth_failed">Benutzerauthentifizierung ist fehlgeschlagen.</string>
<string name="error_assessment_failed">Sicherheitsassessment ist fehlgeschlagen.</string>
<string name="error_generic">Unbekannter Fehler während des Verbindens.</string> <string name="error_generic">Unbekannter Fehler während des Verbindens.</string>
<string name="connecting_title">Verbinden: %1$s</string> <string name="connecting_title">Verbinden: %1$s</string>
<string name="connecting_message">Verbinde mit \""%1$s\".</string> <string name="connecting_message">Verbinde mit \""%1$s\".</string>
@@ -19,5 +19,6 @@
<item>IKEv2 EAP (użytkownik/hasło)</item> <item>IKEv2 EAP (użytkownik/hasło)</item>
<item>IKEv2 certyfikat</item> <item>IKEv2 certyfikat</item>
<item>IKEv2 certyfikat + EAP (użytkownik/hasło)</item> <item>IKEv2 certyfikat + EAP (użytkownik/hasło)</item>
<item>IKEv2 EAP-TNC (użytkownik/hasło)</item>
</string-array> </string-array>
</resources> </resources>
@@ -1,7 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Giuliano Grassi
Copyright (C) 2012 Ralf Sager
Copyright (C) 2012 Andreas Steffen Copyright (C) 2012 Andreas Steffen
HSR Hochschule fuer Technik Rapperswil HSR Hochschule fuer Technik Rapperswil
@@ -71,6 +69,9 @@
<string name="alert_text_no_input_username">Wprowadź swoją nazwę użytkownika</string> <string name="alert_text_no_input_username">Wprowadź swoją nazwę użytkownika</string>
<string name="alert_text_nocertfound_title">Nie wybrano żadnego certyfikatu CA</string> <string name="alert_text_nocertfound_title">Nie wybrano żadnego certyfikatu CA</string>
<string name="alert_text_nocertfound">Wybierz lub uaktywnij jeden <i>Wybierz automatycznie</i></string> <string name="alert_text_nocertfound">Wybierz lub uaktywnij jeden <i>Wybierz automatycznie</i></string>
<string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
<string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
<!-- Trusted certificate selection --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">Certyfikaty CA</string> <string name="trusted_certs_title">Certyfikaty CA</string>
@@ -88,6 +89,15 @@
<string name="state_disabled">Brak aktywnego VPN</string> <string name="state_disabled">Brak aktywnego VPN</string>
<string name="state_error">Błąd</string> <string name="state_error">Błąd</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Restricted</string>
<string name="imc_state_block">Failed</string>
<string name="show_remediation_instructions">View remediation instructions</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Remediation instructions</string>
<!-- Dialogs --> <!-- Dialogs -->
<string name="login_title">Wprowadż hasło</string> <string name="login_title">Wprowadż hasło</string>
<string name="login_confirm">Połącz</string> <string name="login_confirm">Połącz</string>
@@ -96,6 +106,7 @@
<string name="error_unreachable">Bramka jest nieosiągalna</string> <string name="error_unreachable">Bramka jest nieosiągalna</string>
<string name="error_peer_auth_failed">Błąd przy weryfikacji bramki</string> <string name="error_peer_auth_failed">Błąd przy weryfikacji bramki</string>
<string name="error_auth_failed">Błąd przy autoryzacji użytkownika</string> <string name="error_auth_failed">Błąd przy autoryzacji użytkownika</string>
<string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Nieznany błąd w czasie połączenia</string> <string name="error_generic">Nieznany błąd w czasie połączenia</string>
<string name="connecting_title">Łączenie: %1$s</string> <string name="connecting_title">Łączenie: %1$s</string>
<string name="connecting_message">Tworzenie tunelu VPN z \""%1$s\".</string> <string name="connecting_message">Tworzenie tunelu VPN z \""%1$s\".</string>
@@ -18,5 +18,6 @@
<item>IKEv2 EAP (Логин/Пароль)</item> <item>IKEv2 EAP (Логин/Пароль)</item>
<item>IKEv2 Сертификат</item> <item>IKEv2 Сертификат</item>
<item>IKEv2 Сертификат + EAP (Логин/Пароль)</item> <item>IKEv2 Сертификат + EAP (Логин/Пароль)</item>
<item>IKEv2 EAP-TNC (Логин/Пароль)</item>
</string-array> </string-array>
</resources> </resources>
@@ -66,6 +66,9 @@
<string name="alert_text_no_input_username">Пожалуйста введите имя пользователя</string> <string name="alert_text_no_input_username">Пожалуйста введите имя пользователя</string>
<string name="alert_text_nocertfound_title">Не выбран сертификат CA</string> <string name="alert_text_nocertfound_title">Не выбран сертификат CA</string>
<string name="alert_text_nocertfound">Пожалуйста выберите один <i>Выбрать автоматически</i></string> <string name="alert_text_nocertfound">Пожалуйста выберите один <i>Выбрать автоматически</i></string>
<string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
<string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
<!-- Trusted certificate selection --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">Сертификаты CA</string> <string name="trusted_certs_title">Сертификаты CA</string>
@@ -83,6 +86,15 @@
<string name="state_disabled">Нет активных VPN</string> <string name="state_disabled">Нет активных VPN</string>
<string name="state_error">Ошибка</string> <string name="state_error">Ошибка</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Restricted</string>
<string name="imc_state_block">Failed</string>
<string name="show_remediation_instructions">View remediation instructions</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Remediation instructions</string>
<!-- Dialogs --> <!-- Dialogs -->
<string name="login_title">Введите пароль для соединения</string> <string name="login_title">Введите пароль для соединения</string>
<string name="login_confirm">Соединить</string> <string name="login_confirm">Соединить</string>
@@ -91,6 +103,7 @@
<string name="error_unreachable">Шлюз недоступен.</string> <string name="error_unreachable">Шлюз недоступен.</string>
<string name="error_peer_auth_failed">Ошибка авторизаци при подключении к шлюзу.</string> <string name="error_peer_auth_failed">Ошибка авторизаци при подключении к шлюзу.</string>
<string name="error_auth_failed">Ошибка авторизации пользователя.</string> <string name="error_auth_failed">Ошибка авторизации пользователя.</string>
<string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Неизвестная ошибка.</string> <string name="error_generic">Неизвестная ошибка.</string>
<string name="connecting_title">Подключение: %1$s</string> <string name="connecting_title">Подключение: %1$s</string>
<string name="connecting_message">Подключение к VPN с \""%1$s\".</string> <string name="connecting_message">Подключение к VPN с \""%1$s\".</string>
@@ -18,5 +18,6 @@
<item>IKEv2 EAP (Логін/Пароль)</item> <item>IKEv2 EAP (Логін/Пароль)</item>
<item>IKEv2 Сертифікати</item> <item>IKEv2 Сертифікати</item>
<item>IKEv2 Сертифікати + EAP (Логін/Пароль)</item> <item>IKEv2 Сертифікати + EAP (Логін/Пароль)</item>
<item>IKEv2 EAP-TNC (Логін/Пароль)</item>
</string-array> </string-array>
</resources> </resources>
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Dmitry Korzhevin
Copyright (C) 2013 Pavel Kopchyk Copyright (C) 2013 Pavel Kopchyk
Copyright (C) 2012 Dmitry Korzhevin
This program is free software; you can redistribute it and/or modify it This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the under the terms of the GNU General Public License as published by the
@@ -67,6 +67,9 @@
<string name="alert_text_no_input_username">Введіть ім\'я користувача тут</string> <string name="alert_text_no_input_username">Введіть ім\'я користувача тут</string>
<string name="alert_text_nocertfound_title">Не вибрано сертифікат CA</string> <string name="alert_text_nocertfound_title">Не вибрано сертифікат CA</string>
<string name="alert_text_nocertfound">Будь ласка виберіть один <i>Вибрати автоматично</i></string> <string name="alert_text_nocertfound">Будь ласка виберіть один <i>Вибрати автоматично</i></string>
<string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
<string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
<!-- Trusted certificate selection --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">Сертифікати CA</string> <string name="trusted_certs_title">Сертифікати CA</string>
@@ -84,6 +87,15 @@
<string name="state_disabled">Немає активних VPN</string> <string name="state_disabled">Немає активних VPN</string>
<string name="state_error">Помилка</string> <string name="state_error">Помилка</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Restricted</string>
<string name="imc_state_block">Failed</string>
<string name="show_remediation_instructions">View remediation instructions</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Remediation instructions</string>
<!-- Dialogs --> <!-- Dialogs -->
<string name="login_title">Введіть пароль для з\'єднання</string> <string name="login_title">Введіть пароль для з\'єднання</string>
<string name="login_confirm">Підключити</string> <string name="login_confirm">Підключити</string>
@@ -92,6 +104,7 @@
<string name="error_unreachable">Немає зв\'язку зі шлюзом.</string> <string name="error_unreachable">Немає зв\'язку зі шлюзом.</string>
<string name="error_peer_auth_failed">Помилка перевірки данних аутентифікації шлюза.</string> <string name="error_peer_auth_failed">Помилка перевірки данних аутентифікації шлюза.</string>
<string name="error_auth_failed">Помилка аутентифікації користувача.</string> <string name="error_auth_failed">Помилка аутентифікації користувача.</string>
<string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Невідома помилка під час підключення.</string> <string name="error_generic">Невідома помилка під час підключення.</string>
<string name="connecting_title">Підключення: %1$s</string> <string name="connecting_title">Підключення: %1$s</string>
<string name="connecting_message">Підключення VPN з \""%1$s\".</string> <string name="connecting_message">Підключення VPN з \""%1$s\".</string>
@@ -19,5 +19,6 @@
<item>IKEv2 EAP (Username/Password)</item> <item>IKEv2 EAP (Username/Password)</item>
<item>IKEv2 Certificate</item> <item>IKEv2 Certificate</item>
<item>IKEv2 Certificate + EAP (Username/Password)</item> <item>IKEv2 Certificate + EAP (Username/Password)</item>
<item>IKEv2 EAP-TNC (Username/Password)</item>
</string-array> </string-array>
</resources> </resources>
+10 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Tobias Brunner Copyright (C) 2012-2013 Tobias Brunner
Hochschule fuer Technik Rapperswil Hochschule fuer Technik Rapperswil
This program is free software; you can redistribute it and/or modify it This program is free software; you can redistribute it and/or modify it
@@ -18,7 +18,16 @@
<color <color
name="error_text">#D9192C</color> name="error_text">#D9192C</color>
<color
name="warning_text">#FF9909</color>
<color <color
name="success_text">#99CC00</color> name="success_text">#99CC00</color>
<color
name="panel_background">#333333</color>
<color
name="panel_separator">#5a5a5a</color>
</resources> </resources>
+14 -1
View File
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<!-- <!--
Copyright (C) 2012 Tobias Brunner Copyright (C) 2012-2013 Tobias Brunner
Copyright (C) 2012 Giuliano Grassi Copyright (C) 2012 Giuliano Grassi
Copyright (C) 2012 Ralf Sager Copyright (C) 2012 Ralf Sager
Hochschule fuer Technik Rapperswil Hochschule fuer Technik Rapperswil
@@ -69,6 +69,9 @@
<string name="alert_text_no_input_username">Please enter your username here</string> <string name="alert_text_no_input_username">Please enter your username here</string>
<string name="alert_text_nocertfound_title">No CA certificate selected</string> <string name="alert_text_nocertfound_title">No CA certificate selected</string>
<string name="alert_text_nocertfound">Please select one or activate <i>Select automatically</i></string> <string name="alert_text_nocertfound">Please select one or activate <i>Select automatically</i></string>
<string name="tnc_notice_title">EAP-TNC may affect your privacy</string>
<string name="tnc_notice_subtitle">Device data is sent to the gateway operator</string>
<string name="tnc_notice_details">&lt;p>Trusted Network Connect (TNC) allows gateway operators to assess the health of a client device.&lt;/p>&lt;p>For that purpose the gateway operator may request data such as a unique identifier, a list of installed packages, system settings, or cryptographic checksums of files.&lt;/p>&lt;b>Any data will be sent only after verifying the gateway\'s identity.&lt;/b></string>
<!-- Trusted certificate selection --> <!-- Trusted certificate selection -->
<string name="trusted_certs_title">CA certificates</string> <string name="trusted_certs_title">CA certificates</string>
@@ -86,6 +89,15 @@
<string name="state_disabled">No active VPN</string> <string name="state_disabled">No active VPN</string>
<string name="state_error">Error</string> <string name="state_error">Error</string>
<!-- IMC state fragment -->
<string name="imc_state_label">Assessment:</string>
<string name="imc_state_isolate">Restricted</string>
<string name="imc_state_block">Failed</string>
<string name="show_remediation_instructions">View remediation instructions</string>
<!-- Remediation instructions -->
<string name="remediation_instructions_title">Remediation instructions</string>
<!-- Dialogs --> <!-- Dialogs -->
<string name="login_title">Enter password to connect</string> <string name="login_title">Enter password to connect</string>
<string name="login_confirm">Connect</string> <string name="login_confirm">Connect</string>
@@ -94,6 +106,7 @@
<string name="error_unreachable">Gateway is unreachable.</string> <string name="error_unreachable">Gateway is unreachable.</string>
<string name="error_peer_auth_failed">Verifying gateway authentication failed.</string> <string name="error_peer_auth_failed">Verifying gateway authentication failed.</string>
<string name="error_auth_failed">User authentication failed.</string> <string name="error_auth_failed">User authentication failed.</string>
<string name="error_assessment_failed">Security assessment failed.</string>
<string name="error_generic">Unspecified failure while connecting.</string> <string name="error_generic">Unspecified failure while connecting.</string>
<string name="connecting_title">Connecting: %1$s</string> <string name="connecting_title">Connecting: %1$s</string>
<string name="connecting_message">Establishing VPN with \""%1$s\".</string> <string name="connecting_message">Establishing VPN with \""%1$s\".</string>
@@ -20,11 +20,13 @@ public enum VpnType
/* the order here must match the items in R.array.vpn_types */ /* the order here must match the items in R.array.vpn_types */
IKEV2_EAP("ikev2-eap", true, false), IKEV2_EAP("ikev2-eap", true, false),
IKEV2_CERT("ikev2-cert", false, true), IKEV2_CERT("ikev2-cert", false, true),
IKEV2_CERT_EAP("ikev2-cert-eap", true, true); IKEV2_CERT_EAP("ikev2-cert-eap", true, true),
IKEV2_BYOD_EAP("ikev2-byod-eap", true, false, true);
private String mIdentifier; private String mIdentifier;
private boolean mCertificate; private boolean mCertificate;
private boolean mUsernamePassword; private boolean mUsernamePassword;
private boolean mBYOD;
/** /**
* Enum which provides additional information about the supported VPN types. * Enum which provides additional information about the supported VPN types.
@@ -34,10 +36,24 @@ public enum VpnType
* @param certificate true if a client certificate is required * @param certificate true if a client certificate is required
*/ */
VpnType(String id, boolean userpass, boolean certificate) VpnType(String id, boolean userpass, boolean certificate)
{
this(id, userpass, certificate, false);
}
/**
* Enum which provides additional information about the supported VPN types.
*
* @param id identifier used to store and transmit this specific type
* @param userpass true if username and password are required
* @param certificate true if a client certificate is required
* @param byod true to enable BYOD features
*/
VpnType(String id, boolean userpass, boolean certificate, boolean byod)
{ {
mIdentifier = id; mIdentifier = id;
mUsernamePassword = userpass; mUsernamePassword = userpass;
mCertificate = certificate; mCertificate = certificate;
mBYOD = byod;
} }
/** /**
@@ -69,6 +85,16 @@ public enum VpnType
return mCertificate; return mCertificate;
} }
/**
* Whether BYOD features should be enabled.
*
* @return true if BYOD features are to be enabled
*/
public boolean getEnableBYOD()
{
return mBYOD;
}
/** /**
* Get the enum entry with the given identifier. * Get the enum entry with the given identifier.
* *
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012 Tobias Brunner * Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager * Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
@@ -27,6 +27,8 @@ import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.data.VpnProfileDataSource; import org.strongswan.android.data.VpnProfileDataSource;
import org.strongswan.android.logic.VpnStateService.ErrorState; import org.strongswan.android.logic.VpnStateService.ErrorState;
import org.strongswan.android.logic.VpnStateService.State; 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 org.strongswan.android.ui.MainActivity;
import android.app.PendingIntent; import android.app.PendingIntent;
@@ -208,10 +210,11 @@ public class CharonVpnService extends VpnService implements Runnable
setProfile(mCurrentProfile); setProfile(mCurrentProfile);
setError(ErrorState.NO_ERROR); setError(ErrorState.NO_ERROR);
setState(State.CONNECTING); setState(State.CONNECTING);
setImcState(ImcState.UNKNOWN);
mIsDisconnecting = false; mIsDisconnecting = false;
BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName()); BuilderAdapter builder = new BuilderAdapter(mCurrentProfile.getName());
initializeCharon(builder, mLogFile); initializeCharon(builder, mLogFile, mCurrentProfile.getVpnType().getEnableBYOD());
Log.i(TAG, "charon started"); Log.i(TAG, "charon started");
initiate(mCurrentProfile.getVpnType().getIdentifier(), initiate(mCurrentProfile.getVpnType().getIdentifier(),
@@ -296,6 +299,23 @@ public class CharonVpnService extends VpnService implements Runnable
} }
} }
/**
* Set the IMC state on the state service. Called by the handler thread and
* any of charon's threads.
*
* @param state IMC state
*/
private void setImcState(ImcState state)
{
synchronized (mServiceLock)
{
if (mService != null)
{
mService.setImcState(state);
}
}
}
/** /**
* Set an error on the state service and disconnect the current connection. * Set an error on the state service and disconnect the current connection.
* This is not done by calling stopCurrentConnection() above, but instead * This is not done by calling stopCurrentConnection() above, but instead
@@ -355,6 +375,41 @@ public class CharonVpnService extends VpnService implements Runnable
} }
} }
/**
* Updates the IMC state of the current connection.
* Called via JNI by different threads (but not concurrently).
*
* @param value new state
*/
public void updateImcState(int value)
{
ImcState state = ImcState.fromValue(value);
if (state != null)
{
setImcState(state);
}
}
/**
* 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 * Function called via JNI to generate a list of DER encoded CA certificates
* as byte array. * as byte array.
@@ -461,8 +516,9 @@ public class CharonVpnService extends VpnService implements Runnable
* *
* @param builder BuilderAdapter for this connection * @param builder BuilderAdapter for this connection
* @param logfile absolute path to the logfile * @param logfile absolute path to the logfile
* @param boyd enable BYOD features
*/ */
public native void initializeCharon(BuilderAdapter builder, String logfile); public native void initializeCharon(BuilderAdapter builder, String logfile, boolean byod);
/** /**
* Deinitialize charon, provided by libandroidbridge.so * Deinitialize charon, provided by libandroidbridge.so
@@ -600,6 +656,15 @@ public class CharonVpnService extends VpnService implements Runnable
{ {
System.loadLibrary("crypto"); System.loadLibrary("crypto");
System.loadLibrary("strongswan"); System.loadLibrary("strongswan");
if (MainActivity.USE_BYOD)
{
System.loadLibrary("tncif");
System.loadLibrary("tnccs");
System.loadLibrary("imcv");
System.loadLibrary("pts");
}
System.loadLibrary("hydra"); System.loadLibrary("hydra");
System.loadLibrary("charon"); System.loadLibrary("charon");
System.loadLibrary("ipsec"); System.loadLibrary("ipsec");
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012 Tobias Brunner * Copyright (C) 2012-2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -16,10 +16,14 @@
package org.strongswan.android.logic; package org.strongswan.android.logic;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import org.strongswan.android.data.VpnProfile; 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.app.Service;
import android.content.Context; import android.content.Context;
@@ -36,6 +40,8 @@ public class VpnStateService extends Service
private VpnProfile mProfile; private VpnProfile mProfile;
private State mState = State.DISABLED; private State mState = State.DISABLED;
private ErrorState mError = ErrorState.NO_ERROR; private ErrorState mError = ErrorState.NO_ERROR;
private ImcState mImcState = ImcState.UNKNOWN;
private final LinkedList<RemediationInstruction> mRemediationInstructions = new LinkedList<RemediationInstruction>();
public enum State public enum State
{ {
@@ -146,6 +152,26 @@ public class VpnStateService extends Service
return mError; return mError;
} }
/**
* Get the current IMC state, if any.
*
* @return imc state
*/
public ImcState getImcState()
{ /* only updated from the main thread so no synchronization needed */
return mImcState;
}
/**
* 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 * Disconnect any existing connection and shutdown the daemon, the
* VpnService is not stopped but it is reset so new connections can be * VpnService is not stopped but it is reset so new connections can be
@@ -261,4 +287,54 @@ 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
*/
public void setImcState(final ImcState state)
{
notifyListeners(new Callable<Boolean>() {
@Override
public Boolean call() throws Exception
{
if (state == ImcState.UNKNOWN)
{
VpnStateService.this.mRemediationInstructions.clear();
}
if (VpnStateService.this.mImcState != state)
{
VpnStateService.this.mImcState = state;
return true;
}
return false;
}
});
}
/**
* 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);
}
});
}
} }
@@ -0,0 +1,99 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.AttributeType;
import org.strongswan.android.logic.imc.collectors.Collector;
import org.strongswan.android.logic.imc.collectors.DeviceIdCollector;
import org.strongswan.android.logic.imc.collectors.InstalledPackagesCollector;
import org.strongswan.android.logic.imc.collectors.PortFilterCollector;
import org.strongswan.android.logic.imc.collectors.ProductInformationCollector;
import org.strongswan.android.logic.imc.collectors.SettingsCollector;
import org.strongswan.android.logic.imc.collectors.StringVersionCollector;
import android.content.Context;
public class AndroidImc
{
private final Context mContext;
public AndroidImc(Context context)
{
mContext = context;
}
/**
* Get a measurement (the binary encoding of the requested attribute) for
* the given vendor specific attribute type.
*
* @param vendor vendor ID
* @param type vendor specific attribute type
* @return encoded attribute, or null if not available or failed
*/
public byte[] getMeasurement(int vendor, int type)
{
return getMeasurement(vendor, type, null);
}
/**
* Get a measurement (the binary encoding of the requested attribute) for
* the given vendor specific attribute type.
*
* @param vendor vendor ID
* @param type vendor specific attribute type
* @param args optional arguments for a measurement
* @return encoded attribute, or null if not available or failed
*/
public byte[] getMeasurement(int vendor, int type, String[] args)
{
AttributeType attributeType = AttributeType.fromValues(vendor, type);
Collector collector = null;
switch (attributeType)
{
case IETF_PRODUCT_INFORMATION:
collector = new ProductInformationCollector();
break;
case IETF_STRING_VERSION:
collector = new StringVersionCollector();
break;
case IETF_PORT_FILTER:
collector = new PortFilterCollector();
break;
case IETF_INSTALLED_PACKAGES:
collector = new InstalledPackagesCollector(mContext);
break;
case ITA_SETTINGS:
collector = new SettingsCollector(mContext, args);
break;
case ITA_DEVICE_ID:
collector = new DeviceIdCollector(mContext);
break;
default:
break;
}
if (collector != null)
{
Attribute attribute = collector.getMeasurement();
if (attribute != null)
{
return attribute.getEncoding();
}
}
return null;
}
}
@@ -0,0 +1,58 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc;
public enum ImcState
{
UNKNOWN(0),
ALLOW(1),
BLOCK(2),
ISOLATE(3);
private final int mValue;
private ImcState(int value)
{
mValue = value;
}
/**
* Get the numeric value of the IMC state.
* @return numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Get the enum entry from a numeric value, if defined
*
* @param value numeric value
* @return the enum entry or null
*/
public static ImcState fromValue(int value)
{
for (ImcState state : ImcState.values())
{
if (state.mValue == value)
{
return state;
}
}
return null;
}
}
@@ -0,0 +1,273 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Xml;
public class RemediationInstruction implements Parcelable
{
private String mTitle;
private String mDescription;
private String mHeader;
private final List<String> mItems = new LinkedList<String>();
@Override
public int describeContents()
{
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags)
{
dest.writeString(mTitle);
dest.writeString(mDescription);
dest.writeString(mHeader);
dest.writeStringList(mItems);
}
public static final Parcelable.Creator<RemediationInstruction> CREATOR = new Creator<RemediationInstruction>() {
@Override
public RemediationInstruction[] newArray(int size)
{
return new RemediationInstruction[size];
}
@Override
public RemediationInstruction createFromParcel(Parcel source)
{
return new RemediationInstruction(source);
}
};
private RemediationInstruction()
{
}
private RemediationInstruction(Parcel source)
{
mTitle = source.readString();
mDescription = source.readString();
mHeader = source.readString();
source.readStringList(mItems);
}
public String getTitle()
{
return mTitle;
}
private void setTitle(String title)
{
mTitle = title;
}
public String getDescription()
{
return mDescription;
}
private void setDescription(String description)
{
mDescription = description;
}
public String getHeader()
{
return mHeader;
}
private void setHeader(String header)
{
mHeader = header;
}
public List<String> getItems()
{
return Collections.unmodifiableList(mItems);
}
private void addItem(String item)
{
mItems.add(item);
}
/**
* Create a list of RemediationInstruction objects from the given XML data.
*
* @param xml XML data
* @return list of RemediationInstruction objects
*/
public static List<RemediationInstruction> fromXml(String xml)
{
List<RemediationInstruction> instructions = new LinkedList<RemediationInstruction>();
XmlPullParser parser = Xml.newPullParser();
try
{
parser.setInput(new StringReader(xml));
parser.nextTag();
readInstructions(parser, instructions);
}
catch (XmlPullParserException e)
{
e.printStackTrace();
}
catch (IOException e)
{
e.printStackTrace();
}
return instructions;
}
/**
* Read a &lt;remediationinstructions&gt; element and store the extracted
* RemediationInstruction objects in the given list.
*
* @param parser
* @param instructions
* @throws XmlPullParserException
* @throws IOException
*/
private static void readInstructions(XmlPullParser parser, List<RemediationInstruction> instructions) throws XmlPullParserException, IOException
{
parser.require(XmlPullParser.START_TAG, null, "remediationinstructions");
while (parser.next() != XmlPullParser.END_TAG)
{
if (parser.getEventType() != XmlPullParser.START_TAG)
{
continue;
}
if (parser.getName().equals("instruction"))
{
RemediationInstruction instruction = new RemediationInstruction();
readInstruction(parser, instruction);
instructions.add(instruction);
}
else
{
skipTag(parser);
}
}
}
/**
* Read an &lt;instruction&gt; element and store the information in the
* given RemediationInstruction object.
*
* @param parser
* @param instruction
* @throws XmlPullParserException
* @throws IOException
*/
private static void readInstruction(XmlPullParser parser, RemediationInstruction instruction) throws XmlPullParserException, IOException
{
parser.require(XmlPullParser.START_TAG, null, "instruction");
while (parser.next() != XmlPullParser.END_TAG)
{
if (parser.getEventType() != XmlPullParser.START_TAG)
{
continue;
}
String name = parser.getName();
if (name.equals("title"))
{
instruction.setTitle(parser.nextText());
}
else if (name.equals("description"))
{
instruction.setDescription(parser.nextText());
}
else if (name.equals("itemsheader"))
{
instruction.setHeader(parser.nextText());
}
else if (name.equals("items"))
{
readItems(parser, instruction);
}
else
{
skipTag(parser);
}
}
}
/**
* Read all items of an &lt;items&gt; node and add them to the given
* RemediationInstruction object.
*
* @param parser
* @param instruction
* @throws XmlPullParserException
* @throws IOException
*/
private static void readItems(XmlPullParser parser, RemediationInstruction instruction) throws XmlPullParserException, IOException
{
while (parser.next() != XmlPullParser.END_TAG)
{
if (parser.getEventType() != XmlPullParser.START_TAG)
{
continue;
}
if (parser.getName().equals("item"))
{
instruction.addItem(parser.nextText());
}
else
{
skipTag(parser);
}
}
}
/**
* Skip the current tag and all child elements.
*
* @param parser
* @throws XmlPullParserException
* @throws IOException
*/
private static void skipTag(XmlPullParser parser) throws XmlPullParserException, IOException
{
int depth = 1;
parser.require(XmlPullParser.START_TAG, null, null);
while (depth != 0)
{
switch (parser.next())
{
case XmlPullParser.END_TAG:
depth--;
break;
case XmlPullParser.START_TAG:
depth++;
break;
}
}
}
}
@@ -0,0 +1,28 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.attributes;
/**
* Interface to be implemented by attribute classes
*/
public interface Attribute
{
/**
* Returns the binary encoding of the attribute
* @return binary encoding
*/
public byte[] getEncoding();
}
@@ -0,0 +1,100 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.attributes;
public enum AttributeType
{
/* IETF standard PA-TNC attribute types defined by RFC 5792 */
IETF_TESTING(PrivateEnterpriseNumber.IETF, 0),
IETF_ATTRIBUTE_REQUEST(PrivateEnterpriseNumber.IETF, 1),
IETF_PRODUCT_INFORMATION(PrivateEnterpriseNumber.IETF, 2),
IETF_NUMERIC_VERSION(PrivateEnterpriseNumber.IETF, 3),
IETF_STRING_VERSION(PrivateEnterpriseNumber.IETF, 4),
IETF_OPERATIONAL_STATUS(PrivateEnterpriseNumber.IETF, 5),
IETF_PORT_FILTER(PrivateEnterpriseNumber.IETF, 6),
IETF_INSTALLED_PACKAGES(PrivateEnterpriseNumber.IETF, 7),
IETF_PA_TNC_ERROR(PrivateEnterpriseNumber.IETF, 8),
IETF_ASSESSMENT_RESULT(PrivateEnterpriseNumber.IETF, 9),
IETF_REMEDIATION_INSTRUCTIONS(PrivateEnterpriseNumber.IETF, 10),
IETF_FORWARDING_ENABLED(PrivateEnterpriseNumber.IETF, 11),
IETF_FACTORY_DEFAULT_PWD_ENABLED(PrivateEnterpriseNumber.IETF, 12),
IETF_RESERVED(PrivateEnterpriseNumber.IETF, 0xffffffff),
/* ITA attributes */
ITA_SETTINGS(PrivateEnterpriseNumber.ITA, 4),
ITA_DEVICE_ID(PrivateEnterpriseNumber.ITA, 8);
private PrivateEnterpriseNumber mVendor;
private int mType;
/**
* Enum type for vendor specific attributes (defined in their namespace)
*
* @param vendor private enterprise number of vendor
* @param type vendor specific attribute type
*/
private AttributeType(PrivateEnterpriseNumber vendor, int type)
{
mVendor = vendor;
mType = type;
}
/**
* Get private enterprise number of vendor
*
* @return PEN
*/
public PrivateEnterpriseNumber getVendor()
{
return mVendor;
}
/**
* Get vendor specific type
*
* @return type
*/
public int getType()
{
return mType;
}
/**
* Get the enum entry from the given numeric values, if defined
*
* @param vendor vendor id
* @param type vendor specific type
* @return enum entry or null
*/
public static AttributeType fromValues(int vendor, int type)
{
PrivateEnterpriseNumber pen = PrivateEnterpriseNumber.fromValue(vendor);
if (pen == null)
{
return null;
}
for (AttributeType attr : AttributeType.values())
{
if (attr.mVendor == pen && attr.mType == type)
{
return attr;
}
}
return null;
}
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.attributes;
/**
* ITA Device ID attribute
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Device ID (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class DeviceIdAttribute implements Attribute
{
private String mDeviceId;
/**
* Set the device ID
* @param version version number
*/
public void setDeviceId(String deviceId)
{
this.mDeviceId = deviceId;
}
@Override
public byte[] getEncoding()
{
return mDeviceId.getBytes();
}
}
@@ -0,0 +1,67 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.attributes;
import java.util.LinkedList;
import org.strongswan.android.utils.BufferedByteWriter;
import android.util.Pair;
/**
* PA-TNC Installed Packages attribute (see section 4.2.7 of RFC 5792)
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved | Package Count |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Pkg Name Len | Package Name (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Version Len | Package Version Number (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class InstalledPackagesAttribute implements Attribute
{
private final short RESERVED = 0;
private final LinkedList<Pair<String, String>> mPackages = new LinkedList<Pair<String, String>>();
/**
* Add an installed package to this attribute.
* @param name name of the package
* @param version version number of the package
*/
public void addPackage(String name, String version)
{
mPackages.add(new Pair<String, String>(name, version));
}
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
writer.put16(RESERVED);
writer.put16((short)mPackages.size());
for (Pair<String, String> pair : mPackages)
{
writer.putLen8(pair.first.getBytes());
writer.putLen8(pair.second.getBytes());
}
return writer.toByteArray();
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.attributes;
import java.util.LinkedList;
import org.strongswan.android.logic.imc.collectors.Protocol;
import org.strongswan.android.utils.BufferedByteWriter;
import android.util.Pair;
/**
* PA-TNC Port Filter attribute (see section 4.2.6 of RFC 5792)
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved |B| Protocol | Port Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Reserved |B| Protocol | Port Number |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class PortFilterAttribute implements Attribute
{
private final LinkedList<Pair<Protocol, Short>> mPorts = new LinkedList<Pair<Protocol, Short>>();
/**
* Add an open port with the given protocol and port number
* @param protocol transport protocol
* @param port port number
*/
public void addPort(Protocol protocol, short port)
{
mPorts.add(new Pair<Protocol, Short>(protocol, port));
}
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
for (Pair<Protocol, Short> port : mPorts)
{
/* we report open ports, so the BLOCKED flag is not set */
writer.put((byte)0);
writer.put(port.first.getValue());
writer.put16(port.second);
}
return writer.toByteArray();
}
}
@@ -0,0 +1,65 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.attributes;
public enum PrivateEnterpriseNumber
{
IETF(0x000000),
GOOGLE(0x002B79),
ITA(0x00902a),
UNASSIGNED(0xfffffe),
RESERVED(0xffffff);
private int mValue;
/**
* Enum for private enterprise numbers (PEN) as allocated by IANA
*
* @param value numeric value
*/
private PrivateEnterpriseNumber(int value)
{
mValue = value;
}
/**
* Get the numeric value of a PEN
*
* @return numeric value
*/
public int getValue()
{
return mValue;
}
/**
* Get the enum entry from a numeric value, if defined
*
* @param value numeric value
* @return the enum entry or null
*/
public static PrivateEnterpriseNumber fromValue(int value)
{
for (PrivateEnterpriseNumber pen : PrivateEnterpriseNumber.values())
{
if (pen.mValue == value)
{
return pen;
}
}
return null;
}
}
@@ -0,0 +1,47 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.attributes;
import org.strongswan.android.utils.BufferedByteWriter;
/**
* PA-TNC Product Information attribute (see section 4.2.2 of RFC 5792)
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Product Vendor ID | Product ID |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Product ID | Product Name (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class ProductInformationAttribute implements Attribute
{
private final String PRODUCT_NAME = "Android";
private final short PRODUCT_ID = 0;
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
writer.put24(PrivateEnterpriseNumber.GOOGLE.getValue());
writer.put16(PRODUCT_ID);
writer.put(PRODUCT_NAME.getBytes());
return writer.toByteArray();
}
}
@@ -0,0 +1,78 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.attributes;
import java.util.LinkedList;
import org.strongswan.android.utils.BufferedByteWriter;
import android.util.Pair;
/**
* ITA Settings attribute
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Settings Count |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Name Length | Name (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Name (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Value Length | Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Name Length | Name (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Name (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Value Length | Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ~ Value (Variable Length) ~
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* ...........................
*/
public class SettingsAttribute implements Attribute
{
private final LinkedList<Pair<String, String>> mSettings = new LinkedList<Pair<String, String>>();
/**
* Add a setting to this attribute.
* @param name name of the setting
* @param value value of the setting
*/
public void addSetting(String name, String value)
{
mSettings.add(new Pair<String, String>(name, value));
}
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
writer.put32(mSettings.size());
for (Pair<String, String> pair : mSettings)
{
writer.putLen16(pair.first.getBytes());
writer.putLen16(pair.second.getBytes());
}
return writer.toByteArray();
}
}
@@ -0,0 +1,68 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.attributes;
import org.strongswan.android.utils.BufferedByteWriter;
/**
* PA-TNC String Version attribute (see section 4.2.4 of RFC 5792)
*
* 1 2 3
* 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Version Len | Product Version Number (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Build Num Len | Internal Build Number (Variable Length) |
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
* | Config. Len | Configuration Version Number (Variable Length)|
* +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
*/
public class StringVersionAttribute implements Attribute
{
private String mVersionNumber;
private String mBuildNumber;
/**
* Set the product version number
* @param version version number
*/
public void setProductVersionNumber(String version)
{
this.mVersionNumber = version;
}
/**
* Set the internal build number
* @param build build number
*/
public void setInternalBuildNumber(String build)
{
this.mBuildNumber = build;
}
@Override
public byte[] getEncoding()
{
BufferedByteWriter writer = new BufferedByteWriter();
writer.putLen8(mVersionNumber.getBytes());
writer.putLen8(mBuildNumber.getBytes());
/* we don't provide a configuration number */
writer.put((byte)0);
return writer.toByteArray();
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.collectors;
import org.strongswan.android.logic.imc.attributes.Attribute;
/**
* Interface for measurement collectors
*/
public interface Collector
{
/**
* This method shall return the result of a measurement, if available
* @return attribute or null
*/
public abstract Attribute getMeasurement();
}
@@ -0,0 +1,45 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.collectors;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.DeviceIdAttribute;
import android.content.ContentResolver;
import android.content.Context;
public class DeviceIdCollector implements Collector
{
private final ContentResolver mContentResolver;
public DeviceIdCollector(Context context)
{
mContentResolver = context.getContentResolver();
}
@Override
public Attribute getMeasurement()
{
String id = android.provider.Settings.Secure.getString(mContentResolver, "android_id");
if (id != null)
{
DeviceIdAttribute attribute = new DeviceIdAttribute();
attribute.setDeviceId(id);
return attribute;
}
return null;
}
}
@@ -0,0 +1,55 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.collectors;
import java.util.List;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.InstalledPackagesAttribute;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
public class InstalledPackagesCollector implements Collector
{
private final PackageManager mPackageManager;
public InstalledPackagesCollector(Context context)
{
mPackageManager = context.getPackageManager();
}
@Override
public Attribute getMeasurement()
{
InstalledPackagesAttribute attribute = new InstalledPackagesAttribute();
List<PackageInfo> packages = mPackageManager.getInstalledPackages(0);
for (PackageInfo info : packages)
{
if ((info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0 ||
info.packageName == null || info.versionName == null)
{ /* ignore packages installed in the system image */
continue;
}
attribute.addPackage(info.packageName, info.versionName);
}
return attribute;
}
}
@@ -0,0 +1,79 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.collectors;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.PortFilterAttribute;
public class PortFilterCollector implements Collector
{
private static Pattern LISTEN = Pattern.compile("\\bLISTEN\\b");
private static Pattern PROTOCOL = Pattern.compile("\\b(tcp|udp)6?\\b");
private static Pattern PORT = Pattern.compile("[:]{1,3}(\\d{1,5})\\b(?!\\.)");
@Override
public Attribute getMeasurement()
{
PortFilterAttribute attribute = null;
try
{
Process netstat = Runtime.getRuntime().exec("netstat -n");
try
{
BufferedReader reader = new BufferedReader(new InputStreamReader(netstat.getInputStream()));
String line;
attribute = new PortFilterAttribute();
while ((line = reader.readLine()) != null)
{
if (!LISTEN.matcher(line).find())
{
continue;
}
Matcher protocolMatcher = PROTOCOL.matcher(line);
Matcher portMatcher = PORT.matcher(line);
if (protocolMatcher.find() && portMatcher.find())
{
Protocol protocol = Protocol.fromName(protocolMatcher.group());
if (protocol == null)
{
continue;
}
int port = Integer.parseInt(portMatcher.group(1));
attribute.addPort(protocol, (short)port);
}
}
}
finally
{
netstat.destroy();
}
}
catch (IOException e)
{
e.printStackTrace();
}
return attribute;
}
}
@@ -0,0 +1,30 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.collectors;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.ProductInformationAttribute;
public class ProductInformationCollector implements Collector
{
@Override
public Attribute getMeasurement()
{ /* this is currently hardcoded in the attribute */
return new ProductInformationAttribute();
}
}
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.collectors;
public enum Protocol
{
TCP((byte)6, "tcp", "tcp6"),
UDP((byte)17, "udp", "udp6");
private final byte mValue;
private String[] mNames;
private Protocol(byte value, String... names)
{
mValue = value;
mNames = names;
}
/**
* Get the numeric value of the protocol.
* @return numeric value
*/
public byte getValue()
{
return mValue;
}
/**
* Get the protocol from the given protocol name, if found.
* @param name protocol name (e.g. "udp" or "tcp")
* @return enum entry or null
*/
public static Protocol fromName(String name)
{
for (Protocol protocol : Protocol.values())
{
for (String keyword : protocol.mNames)
{
if (keyword.equalsIgnoreCase(name))
{
return protocol;
}
}
}
return null;
}
}
@@ -0,0 +1,61 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.collectors;
import java.util.Locale;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.SettingsAttribute;
import android.content.ContentResolver;
import android.content.Context;
public class SettingsCollector implements Collector
{
private final ContentResolver mContentResolver;
private final String[] mSettings;
public SettingsCollector(Context context, String[] args)
{
mContentResolver = context.getContentResolver();
mSettings = args;
}
@Override
public Attribute getMeasurement()
{
if (mSettings == null || mSettings.length == 0)
{
return null;
}
SettingsAttribute attribute = new SettingsAttribute();
for (String name : mSettings)
{
String value = android.provider.Settings.Secure.getString(mContentResolver, name.toLowerCase(Locale.US));
if (value == null)
{
value = android.provider.Settings.System.getString(mContentResolver, name.toLowerCase(Locale.US));
}
if (value != null)
{
attribute.addSetting(name, value);
}
}
return attribute;
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Copyright (C) 2012 Christoph Buehler
* Copyright (C) 2012 Patrick Loetscher
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.logic.imc.collectors;
import org.strongswan.android.logic.imc.attributes.Attribute;
import org.strongswan.android.logic.imc.attributes.StringVersionAttribute;
public class StringVersionCollector implements Collector
{
@Override
public Attribute getMeasurement()
{
StringVersionAttribute attribute = new StringVersionAttribute();
attribute.setProductVersionNumber(android.os.Build.VERSION.RELEASE);
attribute.setInternalBuildNumber(android.os.Build.DISPLAY);
return attribute;
}
}
@@ -0,0 +1,181 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.ui;
import java.util.ArrayList;
import org.strongswan.android.R;
import org.strongswan.android.logic.VpnStateService;
import org.strongswan.android.logic.VpnStateService.VpnStateListener;
import org.strongswan.android.logic.imc.ImcState;
import org.strongswan.android.logic.imc.RemediationInstruction;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.app.Service;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.GestureDetector;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnTouchListener;
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
public class ImcStateFragment extends Fragment implements VpnStateListener
{
private TextView mStateView;
private TextView mAction;
private LinearLayout mButton;
private VpnStateService mService;
private final ServiceConnection mServiceConnection = new ServiceConnection() {
@Override
public void onServiceDisconnected(ComponentName name)
{
mService = null;
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
mService = ((VpnStateService.LocalBinder)service).getService();
mService.registerListener(ImcStateFragment.this);
updateView();
}
};
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
/* bind to the service only seems to work from the ApplicationContext */
Context context = getActivity().getApplicationContext();
context.bindService(new Intent(context, VpnStateService.class),
mServiceConnection, Service.BIND_AUTO_CREATE);
/* hide it initially */
getFragmentManager().beginTransaction().hide(this).commit();
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View view = inflater.inflate(R.layout.imc_state_fragment, null);
mButton = (LinearLayout)view.findViewById(R.id.imc_state_button);
mButton.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
Intent intent;
if (mService != null && !mService.getRemediationInstructions().isEmpty())
{
intent = new Intent(getActivity(), RemediationInstructionsActivity.class);
intent.putParcelableArrayListExtra(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS,
new ArrayList<RemediationInstruction>(mService.getRemediationInstructions()));
}
else
{
intent = new Intent(getActivity(), LogActivity.class);
}
startActivity(intent);
}
});
final GestureDetector gestures = new GestureDetector(getActivity(), new GestureDetector.SimpleOnGestureListener() {
/* a better value would be getScaledTouchExplorationTapSlop() but that is hidden */
private final int mMinDistance = ViewConfiguration.get(getActivity()).getScaledTouchSlop() * 4;
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY)
{
if (Math.abs(e1.getX() - e2.getX()) >= mMinDistance)
{ /* only if the user swiped a minimum horizontal distance */
if (mService != null)
{
mService.setImcState(ImcState.UNKNOWN);
}
return true;
}
return false;
}
});
mButton.setOnTouchListener(new OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event)
{
return gestures.onTouchEvent(event);
}
});
mStateView = (TextView)view.findViewById(R.id.imc_state);
mAction = (TextView)view.findViewById(R.id.action);
return view;
}
@Override
public void onDestroy()
{
super.onDestroy();
if (mService != null)
{
mService.unregisterListener(this);
getActivity().getApplicationContext().unbindService(mServiceConnection);
}
}
@Override
public void stateChanged()
{
updateView();
}
public void updateView()
{
FragmentTransaction ft = getFragmentManager().beginTransaction();
switch (mService.getImcState())
{
case UNKNOWN:
case ALLOW:
ft.hide(this);
break;
case ISOLATE:
mStateView.setText(R.string.imc_state_isolate);
mStateView.setTextColor(getResources().getColor(R.color.warning_text));
ft.show(this);
break;
case BLOCK:
mStateView.setText(R.string.imc_state_block);
mStateView.setTextColor(getResources().getColor(R.color.error_text));
ft.show(this);
break;
}
ft.commit();
mAction.setText(mService.getRemediationInstructions().isEmpty() ? R.string.show_log
: R.string.show_remediation_instructions);
}
}
@@ -58,6 +58,8 @@ public class MainActivity extends Activity implements OnVpnProfileSelectedListen
public static final String CONTACT_EMAIL = "[email protected]"; public static final String CONTACT_EMAIL = "[email protected]";
public static final String START_PROFILE = "org.strongswan.android.action.START_PROFILE"; public static final String START_PROFILE = "org.strongswan.android.action.START_PROFILE";
public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID"; public static final String EXTRA_VPN_PROFILE_ID = "org.strongswan.android.VPN_PROFILE_ID";
/** Use "bring your own device" (BYOD) features */
public static final boolean USE_BYOD = true;
private static final int PREPARE_VPN_SERVICE = 0; private static final int PREPARE_VPN_SERVICE = 0;
private static final String PROFILE_NAME = "org.strongswan.android.MainActivity.PROFILE_NAME"; private static final String PROFILE_NAME = "org.strongswan.android.MainActivity.PROFILE_NAME";
private static final String PROFILE_REQUIRES_PASSWORD = "org.strongswan.android.MainActivity.REQUIRES_PASSWORD"; private static final String PROFILE_REQUIRES_PASSWORD = "org.strongswan.android.MainActivity.REQUIRES_PASSWORD";
@@ -0,0 +1,109 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.ui;
import org.strongswan.android.R;
import org.strongswan.android.logic.imc.RemediationInstruction;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class RemediationInstructionFragment extends ListFragment
{
public static final String ARG_REMEDIATION_INSTRUCTION = "instruction";
private RemediationInstruction mInstruction = null;
private TextView mTitle;
private TextView mDescription;
private TextView mHeader;
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
return inflater.inflate(R.layout.remediation_instruction, container, false);
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null)
{
mInstruction = savedInstanceState.getParcelable(ARG_REMEDIATION_INSTRUCTION);
}
/* show dividers only between list items */
getListView().setHeaderDividersEnabled(false);
getListView().setFooterDividersEnabled(false);
/* don't show loader while adapter is not set */
setListShown(true);
mTitle = (TextView)getView().findViewById(R.id.title);
mDescription = (TextView)getView().findViewById(R.id.description);
mHeader = (TextView)getView().findViewById(R.id.list_header);
}
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putParcelable(ARG_REMEDIATION_INSTRUCTION, mInstruction);
}
@Override
public void onStart()
{
super.onStart();
Bundle args = getArguments();
if (args != null)
{
mInstruction = args.getParcelable(ARG_REMEDIATION_INSTRUCTION);
}
updateView(mInstruction);
}
public void updateView(RemediationInstruction instruction)
{
mInstruction = instruction;
if (mInstruction != null)
{
mTitle.setText(mInstruction.getTitle());
mDescription.setText(mInstruction.getDescription());
if (mInstruction.getHeader() != null)
{
mHeader.setText(mInstruction.getHeader());
setListAdapter(new ArrayAdapter<String>(getActivity(),
android.R.layout.simple_list_item_1, mInstruction.getItems()));
}
else
{
mHeader.setText("");
setListAdapter(null);
}
}
else
{
mTitle.setText("");
mDescription.setText("");
mHeader.setText("");
setListAdapter(null);
}
}
}
@@ -0,0 +1,94 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.ui;
import java.util.ArrayList;
import org.strongswan.android.R;
import org.strongswan.android.logic.imc.RemediationInstruction;
import org.strongswan.android.ui.RemediationInstructionsFragment.OnRemediationInstructionSelectedListener;
import android.app.Activity;
import android.os.Bundle;
import android.view.MenuItem;
public class RemediationInstructionsActivity extends Activity implements OnRemediationInstructionSelectedListener
{
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.remediation_instructions);
getActionBar().setDisplayHomeAsUpEnabled(true);
if (savedInstanceState != null)
{ /* only update if we're not restoring */
return;
}
RemediationInstructionsFragment frag = (RemediationInstructionsFragment)getFragmentManager().findFragmentById(R.id.remediation_instructions_fragment);
if (frag != null)
{ /* two-pane layout, update fragment */
Bundle extras = getIntent().getExtras();
ArrayList<RemediationInstruction> list = extras.getParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS);
frag.updateView(list);
}
else
{ /* one-pane layout, create fragment */
frag = new RemediationInstructionsFragment();
frag.setArguments(getIntent().getExtras());
getFragmentManager().beginTransaction().add(R.id.fragment_container, frag).commit();
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item)
{
switch (item.getItemId())
{
case android.R.id.home:
/* one-pane layout, pop possible fragment from stack, finish otherwise */
if (!getFragmentManager().popBackStackImmediate())
{
finish();
}
getActionBar().setTitle(getTitle());
return true;
default:
return super.onOptionsItemSelected(item);
}
}
@Override
public void onRemediationInstructionSelected(RemediationInstruction instruction)
{
RemediationInstructionFragment frag = (RemediationInstructionFragment)getFragmentManager().findFragmentById(R.id.remediation_instruction_fragment);
if (frag != null)
{ /* two-pane layout, update directly */
frag.updateView(instruction);
}
else
{ /* one-pane layout, replace fragment */
frag = new RemediationInstructionFragment();
Bundle args = new Bundle();
args.putParcelable(RemediationInstructionFragment.ARG_REMEDIATION_INSTRUCTION, instruction);
frag.setArguments(args);
getFragmentManager().beginTransaction().replace(R.id.fragment_container, frag).addToBackStack(null).commit();
getActionBar().setTitle(instruction.getTitle());
}
}
}
@@ -0,0 +1,122 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.ui;
import java.util.ArrayList;
import org.strongswan.android.R;
import org.strongswan.android.logic.imc.RemediationInstruction;
import org.strongswan.android.ui.adapter.RemediationInstructionAdapter;
import android.app.Activity;
import android.app.ListFragment;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
public class RemediationInstructionsFragment extends ListFragment
{
public static final String EXTRA_REMEDIATION_INSTRUCTIONS = "instructions";
private static final String KEY_POSITION = "position";
private ArrayList<RemediationInstruction> mInstructions = null;
private OnRemediationInstructionSelectedListener mListener;
private RemediationInstructionAdapter mAdapter;
private int mCurrentPosition = -1;
/**
* The activity containing this fragment should implement this interface
*/
public interface OnRemediationInstructionSelectedListener
{
public void onRemediationInstructionSelected(RemediationInstruction instruction);
}
@Override
public void onActivityCreated(Bundle savedInstanceState)
{
super.onActivityCreated(savedInstanceState);
if (savedInstanceState != null)
{
mInstructions = savedInstanceState.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS);
mCurrentPosition = savedInstanceState.getInt(KEY_POSITION);
}
}
@Override
public void onSaveInstanceState(Bundle outState)
{
super.onSaveInstanceState(outState);
outState.putParcelableArrayList(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS, mInstructions);
outState.putInt(KEY_POSITION, mCurrentPosition);
}
@Override
public void onAttach(Activity activity)
{
super.onAttach(activity);
if (activity instanceof OnRemediationInstructionSelectedListener)
{
mListener = (OnRemediationInstructionSelectedListener)activity;
}
}
@Override
public void onStart()
{
super.onStart();
boolean two_pane = getFragmentManager().findFragmentById(R.id.remediation_instruction_fragment) != null;
if (two_pane)
{ /* two-pane layout, make list items selectable */
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
}
Bundle args = getArguments();
if (mInstructions == null && args != null)
{
mInstructions = args.getParcelableArrayList(EXTRA_REMEDIATION_INSTRUCTIONS);
}
updateView(mInstructions);
if (two_pane && mCurrentPosition == -1 && mInstructions.size() > 0)
{ /* two-pane layout, select first instruction */
mCurrentPosition = 0;
mListener.onRemediationInstructionSelected(mInstructions.get(0));
}
getListView().setItemChecked(mCurrentPosition, true);
}
@Override
public void onListItemClick(ListView l, View v, int position, long id)
{
mCurrentPosition = position;
mListener.onRemediationInstructionSelected(mInstructions.get(position));
getListView().setItemChecked(position, true);
}
public void updateView(ArrayList<RemediationInstruction> instructions)
{
if (mAdapter == null)
{
mAdapter = new RemediationInstructionAdapter(getActivity());
setListAdapter(mAdapter);
}
mInstructions = instructions;
mAdapter.setData(mInstructions);
}
}
@@ -28,6 +28,8 @@ import org.strongswan.android.logic.TrustedCertificateManager;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Dialog;
import android.app.DialogFragment;
import android.content.Context; import android.content.Context;
import android.content.DialogInterface; import android.content.DialogInterface;
import android.content.Intent; import android.content.Intent;
@@ -36,6 +38,7 @@ import android.os.Bundle;
import android.security.KeyChain; import android.security.KeyChain;
import android.security.KeyChainAliasCallback; import android.security.KeyChainAliasCallback;
import android.security.KeyChainException; import android.security.KeyChainException;
import android.text.Html;
import android.util.Log; import android.util.Log;
import android.view.Menu; import android.view.Menu;
import android.view.MenuInflater; import android.view.MenuInflater;
@@ -73,6 +76,7 @@ public class VpnProfileDetailActivity extends Activity
private TwoLineListItem mSelectUserCert; private TwoLineListItem mSelectUserCert;
private CheckBox mCheckAuto; private CheckBox mCheckAuto;
private TwoLineListItem mSelectCert; private TwoLineListItem mSelectCert;
private TwoLineListItem mTncNotice;
@Override @Override
public void onCreate(Bundle savedInstanceState) public void onCreate(Bundle savedInstanceState)
@@ -90,6 +94,7 @@ public class VpnProfileDetailActivity extends Activity
mName = (EditText)findViewById(R.id.name); mName = (EditText)findViewById(R.id.name);
mGateway = (EditText)findViewById(R.id.gateway); mGateway = (EditText)findViewById(R.id.gateway);
mSelectVpnType = (Spinner)findViewById(R.id.vpn_type); mSelectVpnType = (Spinner)findViewById(R.id.vpn_type);
mTncNotice = (TwoLineListItem)findViewById(R.id.tnc_notice);
mUsernamePassword = (ViewGroup)findViewById(R.id.username_password_group); mUsernamePassword = (ViewGroup)findViewById(R.id.username_password_group);
mUsername = (EditText)findViewById(R.id.username); mUsername = (EditText)findViewById(R.id.username);
@@ -117,6 +122,16 @@ public class VpnProfileDetailActivity extends Activity
} }
}); });
mTncNotice.getText1().setText(R.string.tnc_notice_title);
mTncNotice.getText2().setText(R.string.tnc_notice_subtitle);
mTncNotice.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v)
{
new TncNoticeDialog().show(VpnProfileDetailActivity.this.getFragmentManager(), "TncNotice");
}
});
mSelectUserCert.setOnClickListener(new SelectUserCertOnClickListener()); mSelectUserCert.setOnClickListener(new SelectUserCertOnClickListener());
mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() { mCheckAuto.setOnCheckedChangeListener(new OnCheckedChangeListener() {
@@ -225,6 +240,7 @@ public class VpnProfileDetailActivity extends Activity
{ {
mUsernamePassword.setVisibility(mVpnType.getRequiresUsernamePassword() ? View.VISIBLE : View.GONE); mUsernamePassword.setVisibility(mVpnType.getRequiresUsernamePassword() ? View.VISIBLE : View.GONE);
mUserCertificate.setVisibility(mVpnType.getRequiresCertificate() ? View.VISIBLE : View.GONE); mUserCertificate.setVisibility(mVpnType.getRequiresCertificate() ? View.VISIBLE : View.GONE);
mTncNotice.setVisibility(mVpnType.getEnableBYOD() ? View.VISIBLE : View.GONE);
if (mVpnType.getRequiresCertificate()) if (mVpnType.getRequiresCertificate())
{ {
@@ -536,4 +552,25 @@ public class VpnProfileDetailActivity extends Activity
updateCredentialView(); updateCredentialView();
} }
} }
/**
* Dialog with notification message if EAP-TNC is used.
*/
public static class TncNoticeDialog extends DialogFragment
{
@Override
public Dialog onCreateDialog(Bundle savedInstanceState)
{
return new AlertDialog.Builder(getActivity())
.setTitle(R.string.tnc_notice_title)
.setMessage(Html.fromHtml(getString(R.string.tnc_notice_details)))
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int id)
{
dialog.dismiss();
}
}).create();
}
}
} }
@@ -1,5 +1,5 @@
/* /*
* Copyright (C) 2012 Tobias Brunner * Copyright (C) 2012-2013 Tobias Brunner
* Copyright (C) 2012 Giuliano Grassi * Copyright (C) 2012 Giuliano Grassi
* Copyright (C) 2012 Ralf Sager * Copyright (C) 2012 Ralf Sager
* Hochschule fuer Technik Rapperswil * Hochschule fuer Technik Rapperswil
@@ -17,12 +17,17 @@
package org.strongswan.android.ui; package org.strongswan.android.ui;
import java.util.ArrayList;
import java.util.List;
import org.strongswan.android.R; import org.strongswan.android.R;
import org.strongswan.android.data.VpnProfile; import org.strongswan.android.data.VpnProfile;
import org.strongswan.android.logic.VpnStateService; import org.strongswan.android.logic.VpnStateService;
import org.strongswan.android.logic.VpnStateService.ErrorState; import org.strongswan.android.logic.VpnStateService.ErrorState;
import org.strongswan.android.logic.VpnStateService.State; import org.strongswan.android.logic.VpnStateService.State;
import org.strongswan.android.logic.VpnStateService.VpnStateListener; import org.strongswan.android.logic.VpnStateService.VpnStateListener;
import org.strongswan.android.logic.imc.ImcState;
import org.strongswan.android.logic.imc.RemediationInstruction;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.app.Fragment; import android.app.Fragment;
@@ -45,6 +50,7 @@ import android.widget.TextView;
public class VpnStateFragment extends Fragment implements VpnStateListener public class VpnStateFragment extends Fragment implements VpnStateListener
{ {
private static final String KEY_ERROR = "error"; private static final String KEY_ERROR = "error";
private static final String KEY_IMC_STATE = "imc_state";
private static final String KEY_NAME = "name"; private static final String KEY_NAME = "name";
private TextView mProfileNameView; private TextView mProfileNameView;
@@ -56,6 +62,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
private State mState; private State mState;
private AlertDialog mErrorDialog; private AlertDialog mErrorDialog;
private ErrorState mError; private ErrorState mError;
private ImcState mImcState;
private String mErrorProfileName; private String mErrorProfileName;
private VpnStateService mService; private VpnStateService mService;
private final ServiceConnection mServiceConnection = new ServiceConnection() { private final ServiceConnection mServiceConnection = new ServiceConnection() {
@@ -85,9 +92,11 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
mServiceConnection, Service.BIND_AUTO_CREATE); mServiceConnection, Service.BIND_AUTO_CREATE);
mError = ErrorState.NO_ERROR; mError = ErrorState.NO_ERROR;
mImcState = ImcState.UNKNOWN;
if (savedInstanceState != null && savedInstanceState.containsKey(KEY_ERROR)) if (savedInstanceState != null && savedInstanceState.containsKey(KEY_ERROR))
{ {
mError = (ErrorState)savedInstanceState.getSerializable(KEY_ERROR); mError = (ErrorState)savedInstanceState.getSerializable(KEY_ERROR);
mImcState = (ImcState)savedInstanceState.getSerializable(KEY_IMC_STATE);
mErrorProfileName = savedInstanceState.getString(KEY_NAME); mErrorProfileName = savedInstanceState.getString(KEY_NAME);
} }
} }
@@ -98,6 +107,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
super.onSaveInstanceState(outState); super.onSaveInstanceState(outState);
outState.putSerializable(KEY_ERROR, mError); outState.putSerializable(KEY_ERROR, mError);
outState.putSerializable(KEY_IMC_STATE, mImcState);
outState.putString(KEY_NAME, mErrorProfileName); outState.putString(KEY_NAME, mErrorProfileName);
} }
@@ -167,6 +177,7 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
{ {
State state = mService.getState(); State state = mService.getState();
ErrorState error = ErrorState.NO_ERROR; ErrorState error = ErrorState.NO_ERROR;
ImcState imcState = ImcState.UNKNOWN;
String name = "", gateway = ""; String name = "", gateway = "";
if (state != State.DISABLED) if (state != State.DISABLED)
@@ -178,9 +189,10 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
gateway = profile.getGateway(); gateway = profile.getGateway();
} }
error = mService.getErrorState(); error = mService.getErrorState();
imcState = mService.getImcState();
} }
if (reportError(name, state, error)) if (reportError(name, state, error, imcState))
{ {
return; return;
} }
@@ -223,16 +235,18 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
} }
} }
private boolean reportError(String name, State state, ErrorState error) private boolean reportError(String name, State state, ErrorState error, ImcState imcState)
{ {
if (mError != ErrorState.NO_ERROR) if (mError != ErrorState.NO_ERROR)
{ /* we are currently reporting an error which was not yet dismissed */ { /* we are currently reporting an error which was not yet dismissed */
error = mError; error = mError;
imcState = mImcState;
name = mErrorProfileName; name = mErrorProfileName;
} }
else if (error != ErrorState.NO_ERROR && (state == State.CONNECTING || state == State.CONNECTED)) else if (error != ErrorState.NO_ERROR && (state == State.CONNECTING || state == State.CONNECTED))
{ /* while initiating we report errors */ { /* while initiating we report errors */
mError = error; mError = error;
mImcState = imcState;
mErrorProfileName = name; mErrorProfileName = name;
} }
else else
@@ -257,7 +271,14 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
switch (error) switch (error)
{ {
case AUTH_FAILED: case AUTH_FAILED:
showErrorDialog(R.string.error_auth_failed); if (imcState == ImcState.BLOCK)
{
showErrorDialog(R.string.error_assessment_failed);
}
else
{
showErrorDialog(R.string.error_auth_failed);
}
break; break;
case PEER_AUTH_FAILED: case PEER_AUTH_FAILED:
showErrorDialog(R.string.error_peer_auth_failed); showErrorDialog(R.string.error_peer_auth_failed);
@@ -305,6 +326,13 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
} }
} }
private void clearError()
{
mError = ErrorState.NO_ERROR;
mImcState = ImcState.UNKNOWN;
updateView();
}
private void showConnectDialog(String profile, String gateway) private void showConnectDialog(String profile, String gateway)
{ {
mProgressDialog = new ProgressDialog(getActivity()); mProgressDialog = new ProgressDialog(getActivity());
@@ -338,32 +366,46 @@ public class VpnStateFragment extends Fragment implements VpnStateListener
private void showErrorDialog(int textid) private void showErrorDialog(int textid)
{ {
final List<RemediationInstruction> instructions = mService.getRemediationInstructions();
final boolean show_instructions = mImcState == ImcState.BLOCK && !instructions.isEmpty();
int text = show_instructions ? R.string.show_remediation_instructions : R.string.show_log;
mErrorDialog = new AlertDialog.Builder(getActivity()) mErrorDialog = new AlertDialog.Builder(getActivity())
.setMessage(getString(R.string.error_introduction) + " " + getString(textid)) .setMessage(getString(R.string.error_introduction) + " " + getString(textid))
.setCancelable(false) .setCancelable(false)
.setNeutralButton(R.string.show_log, new DialogInterface.OnClickListener() { .setNeutralButton(text, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int which) public void onClick(DialogInterface dialog, int which)
{ {
clearError();
dialog.dismiss(); dialog.dismiss();
Intent logIntent = new Intent(getActivity(), LogActivity.class); Intent intent;
startActivity(logIntent); if (show_instructions)
{
intent = new Intent(getActivity(), RemediationInstructionsActivity.class);
intent.putParcelableArrayListExtra(RemediationInstructionsFragment.EXTRA_REMEDIATION_INSTRUCTIONS,
new ArrayList<RemediationInstruction>(instructions));
}
else
{
intent = new Intent(getActivity(), LogActivity.class);
}
startActivity(intent);
} }
}) })
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() { .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override @Override
public void onClick(DialogInterface dialog, int id) public void onClick(DialogInterface dialog, int id)
{ {
clearError();
dialog.dismiss(); dialog.dismiss();
} }
}).create(); }).create();
mErrorDialog.setOnDismissListener(new DialogInterface.OnDismissListener() { mErrorDialog.setOnDismissListener(new DialogInterface.OnDismissListener() {
@Override @Override
public void onDismiss(DialogInterface dialog) public void onDismiss(DialogInterface dialog)
{ /* clear the error */ {
mError = ErrorState.NO_ERROR;
mErrorDialog = null; mErrorDialog = null;
updateView();
} }
}); });
mErrorDialog.show(); mErrorDialog.show();
@@ -0,0 +1,71 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.ui.adapter;
import java.util.List;
import org.strongswan.android.R;
import org.strongswan.android.logic.imc.RemediationInstruction;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class RemediationInstructionAdapter extends ArrayAdapter<RemediationInstruction>
{
public RemediationInstructionAdapter(Context context)
{
super(context, 0);
}
/**
* Set new data for this adapter.
*
* @param data the new data (null to clear)
*/
public void setData(List<RemediationInstruction> data)
{
clear();
if (data != null)
{
addAll(data);
}
}
@Override
public View getView(int position, View convertView, ViewGroup parent)
{
View view;
if (convertView != null)
{
view = convertView;
}
else
{
LayoutInflater inflater = LayoutInflater.from(getContext());
view = inflater.inflate(R.layout.remediation_instruction_item, parent, false);
}
RemediationInstruction item = getItem(position);
TextView text = (TextView)view.findViewById(android.R.id.text1);
text.setText(item.getTitle());
text = (TextView)view.findViewById(android.R.id.text2);
text.setText(item.getDescription());
return view;
}
}
@@ -0,0 +1,185 @@
/*
* Copyright (C) 2013 Tobias Brunner
* Hochschule fuer Technik Rapperswil
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*/
package org.strongswan.android.utils;
import java.nio.ByteBuffer;
/**
* Very similar to ByteBuffer (although with a stripped interface) but it
* automatically resizes the underlying buffer.
*/
public class BufferedByteWriter
{
/**
* The underlying byte buffer
*/
private byte[] mBuffer;
/**
* ByteBuffer used as wrapper around the buffer to easily convert values
*/
private ByteBuffer mWriter;
/**
* Create a writer with a default initial capacity
*/
public BufferedByteWriter()
{
this(0);
}
/**
* Create a writer with the given initial capacity (helps avoid expensive
* resizing if known).
* @param capacity initial capacity
*/
public BufferedByteWriter(int capacity)
{
capacity = capacity > 4 ? capacity : 32;
mBuffer = new byte[capacity];
mWriter = ByteBuffer.wrap(mBuffer);
}
/**
* Ensure that there is enough space available to write the requested
* number of bytes. If necessary the internal buffer is resized.
* @param required required number of bytes
*/
private void ensureCapacity(int required)
{
if (mWriter.remaining() >= required)
{
return;
}
byte[] buffer = new byte[(mBuffer.length + required) * 2];
System.arraycopy(mBuffer, 0, buffer, 0, mWriter.position());
mBuffer = buffer;
ByteBuffer writer = ByteBuffer.wrap(buffer);
writer.position(mWriter.position());
mWriter = writer;
}
/**
* Write the given byte array to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put(byte[] value)
{
ensureCapacity(value.length);
mWriter.put(value);
return this;
}
/**
* Write the given byte to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put(byte value)
{
ensureCapacity(1);
mWriter.put(value);
return this;
}
/**
* Write the 8-bit length of the given data followed by the data itself
* @param value
* @return the writer
*/
public BufferedByteWriter putLen8(byte[] value)
{
ensureCapacity(1 + value.length);
mWriter.put((byte)value.length);
mWriter.put(value);
return this;
}
/**
* Write the 16-bit length of the given data followed by the data itself
* @param value
* @return the writer
*/
public BufferedByteWriter putLen16(byte[] value)
{
ensureCapacity(2 + value.length);
mWriter.putShort((short)value.length);
mWriter.put(value);
return this;
}
/**
* Write the given short value (16-bit) in big-endian order to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put16(short value)
{
ensureCapacity(2);
mWriter.putShort(value);
return this;
}
/**
* Write 24-bit of the given value in big-endian order to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put24(int value)
{
ensureCapacity(3);
mWriter.put((byte)(value >> 16));
mWriter.putShort((short)value);
return this;
}
/**
* Write the given int value (32-bit) in big-endian order to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put32(int value)
{
ensureCapacity(4);
mWriter.putInt(value);
return this;
}
/**
* Write the given long value (64-bit) in big-endian order to the buffer
* @param value
* @return the writer
*/
public BufferedByteWriter put64(long value)
{
ensureCapacity(8);
mWriter.putLong(value);
return this;
}
/**
* Convert the internal buffer to a new byte array.
* @return byte array
*/
public byte[] toByteArray()
{
int length = mWriter.position();
byte[] bytes = new byte[length];
System.arraycopy(mBuffer, 0, bytes, 0, length);
return bytes;
}
}
+31 -2
View File
@@ -186,8 +186,11 @@ endif
LOCAL_SRC_FILES += $(call add_plugin, eap-peap) LOCAL_SRC_FILES += $(call add_plugin, eap-peap)
# adding libtls if any of the three plugins above is enabled LOCAL_SRC_FILES += $(call add_plugin, eap-tnc)
ifneq ($(or $(call plugin_enabled, eap-tls), $(call plugin_enabled, eap-ttls), $(call plugin_enabled, eap-peap)),)
# adding libtls if any of the four plugins above is enabled
ifneq ($(or $(call plugin_enabled, eap-tls), $(call plugin_enabled, eap-ttls), \
$(call plugin_enabled, eap-peap), $(call plugin_enabled, eap-tnc)),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtls/ LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtls/
LOCAL_SRC_FILES += $(addprefix ../libtls/, \ LOCAL_SRC_FILES += $(addprefix ../libtls/, \
tls_protection.c tls_compression.c tls_fragmentation.c tls_alert.c \ tls_protection.c tls_compression.c tls_fragmentation.c tls_alert.c \
@@ -207,6 +210,32 @@ ifneq ($(call plugin_enabled, stroke),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../stroke/ LOCAL_C_INCLUDES += $(LOCAL_PATH)/../stroke/
endif endif
LOCAL_SRC_FILES += $(call add_plugin, tnc-imc)
ifneq ($(call plugin_enabled, tnc-imc),)
LOCAL_SHARED_LIBRARIES += libdl
endif
LOCAL_SRC_FILES += $(call add_plugin, tnc-tnccs)
LOCAL_SRC_FILES += $(call add_plugin, tnccs-20)
LOCAL_SRC_FILES += $(call add_plugin_subdirs, tnccs-20, batch messages state_machine)
ifneq ($(call plugin_enabled, tnccs-20),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/plugins/tnccs_20/
# for tls.h
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtls/
endif
ifneq ($(or $(call plugin_enabled, eap-tnc), $(call plugin_enabled, tnc-imc), \
$(call plugin_enabled, tnc-tnccs), $(call plugin_enabled, tnccs-20)),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtnccs/
LOCAL_SHARED_LIBRARIES += libtnccs
endif
ifneq ($(or $(call plugin_enabled, tnc-imc), $(call plugin_enabled, tnc-tnccs), \
$(call plugin_enabled, tnccs-20)),)
LOCAL_C_INCLUDES += $(LOCAL_PATH)/../libtncif/
LOCAL_SHARED_LIBRARIES += libtncif
endif
# build libcharon -------------------------------------------------------------- # build libcharon --------------------------------------------------------------
@@ -782,7 +782,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
enumerator = enumerator_create_token(message, " ", " "); enumerator = enumerator_create_token(message, " ", " ");
while (enumerator->enumerate(enumerator, &token)) while (enumerator->enumerate(enumerator, &token))
{ {
if (strneq(token, "S=", 2)) if (strpfx(token, "S="))
{ {
chunk_t hex; chunk_t hex;
token += 2; token += 2;
@@ -795,7 +795,7 @@ static status_t process_peer_success(private_eap_mschapv2_t *this,
hex = chunk_create(token, AUTH_RESPONSE_LEN - 2); hex = chunk_create(token, AUTH_RESPONSE_LEN - 2);
auth_string = chunk_from_hex(hex, NULL); auth_string = chunk_from_hex(hex, NULL);
} }
else if (strneq(token, "M=", 2)) else if (strpfx(token, "M="))
{ {
token += 2; token += 2;
msg = strdup(token); msg = strdup(token);
@@ -864,16 +864,16 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
enumerator = enumerator_create_token(message, " ", " "); enumerator = enumerator_create_token(message, " ", " ");
while (enumerator->enumerate(enumerator, &token)) while (enumerator->enumerate(enumerator, &token))
{ {
if (strneq(token, "E=", 2)) if (strpfx(token, "E="))
{ {
token += 2; token += 2;
error = atoi(token); error = atoi(token);
} }
else if (strneq(token, "R=", 2)) else if (strpfx(token, "R="))
{ {
/* ignore retriable */ /* ignore retriable */
} }
else if (strneq(token, "C=", 2)) else if (strpfx(token, "C="))
{ {
chunk_t hex; chunk_t hex;
token += 2; token += 2;
@@ -886,11 +886,11 @@ static status_t process_peer_failure(private_eap_mschapv2_t *this,
hex = chunk_create(token, 2 * CHALLENGE_LEN); hex = chunk_create(token, 2 * CHALLENGE_LEN);
challenge = chunk_from_hex(hex, NULL); challenge = chunk_from_hex(hex, NULL);
} }
else if (strneq(token, "V=", 2)) else if (strpfx(token, "V="))
{ {
/* ignore version */ /* ignore version */
} }
else if (strneq(token, "M=", 2)) else if (strpfx(token, "M="))
{ {
token += 2; token += 2;
msg = strdup(token); msg = strdup(token);
@@ -355,7 +355,7 @@ static void generate_auth_cfg(private_load_tester_config_t *this, char *str,
} }
} }
} }
else if (strneq(str, "eap", strlen("eap"))) else if (strpfx(str, "eap"))
{ /* EAP authentication, use a NAI */ { /* EAP authentication, use a NAI */
class = AUTH_CLASS_EAP; class = AUTH_CLASS_EAP;
if (*(str + strlen("eap")) == '-') if (*(str + strlen("eap")) == '-')
+5 -5
View File
@@ -559,9 +559,9 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
} }
/* authentication metod (class, actually) */ /* authentication metod (class, actually) */
if (strneq(auth, "pubkey", strlen("pubkey")) || if (strpfx(auth, "pubkey") ||
strneq(auth, "rsa", strlen("rsa")) || strpfx(auth, "rsa") ||
strneq(auth, "ecdsa", strlen("ecdsa"))) strpfx(auth, "ecdsa"))
{ {
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY); cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PUBKEY);
build_crl_policy(cfg, local, msg->add_conn.crl_policy); build_crl_policy(cfg, local, msg->add_conn.crl_policy);
@@ -572,7 +572,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
{ {
cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK); cfg->add(cfg, AUTH_RULE_AUTH_CLASS, AUTH_CLASS_PSK);
} }
else if (strneq(auth, "xauth", 5)) else if (strpfx(auth, "xauth"))
{ {
char *pos; char *pos;
@@ -588,7 +588,7 @@ static auth_cfg_t *build_auth_cfg(private_stroke_config_t *this,
identification_create_from_string(msg->add_conn.xauth_identity)); identification_create_from_string(msg->add_conn.xauth_identity));
} }
} }
else if (strneq(auth, "eap", 3)) else if (strpfx(auth, "eap"))
{ {
eap_vendor_type_t *type; eap_vendor_type_t *type;
+6 -7
View File
@@ -175,7 +175,7 @@ METHOD(stroke_cred_t, load_ca, certificate_t*,
certificate_t *cert = NULL; certificate_t *cert = NULL;
char path[PATH_MAX]; char path[PATH_MAX];
if (strneq(filename, "%smartcard", strlen("%smartcard"))) if (strpfx(filename, "%smartcard"))
{ {
smartcard_format_t format; smartcard_format_t format;
char module[SC_PART_LEN], keyid[SC_PART_LEN]; char module[SC_PART_LEN], keyid[SC_PART_LEN];
@@ -239,7 +239,7 @@ METHOD(stroke_cred_t, load_peer, certificate_t*,
certificate_t *cert = NULL; certificate_t *cert = NULL;
char path[PATH_MAX]; char path[PATH_MAX];
if (strneq(filename, "%smartcard", strlen("%smartcard"))) if (strpfx(filename, "%smartcard"))
{ {
smartcard_format_t format; smartcard_format_t format;
char module[SC_PART_LEN], keyid[SC_PART_LEN]; char module[SC_PART_LEN], keyid[SC_PART_LEN];
@@ -787,7 +787,7 @@ static bool load_pin(mem_cred_t *secrets, chunk_t line, int line_nr,
} }
chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL); chunk = chunk_from_hex(chunk_create(keyid, strlen(keyid)), NULL);
if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7)) if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
{ {
free(secret.ptr); free(secret.ptr);
if (!prompt) if (!prompt)
@@ -880,7 +880,7 @@ static bool load_from_file(chunk_t line, int line_nr, FILE *prompt,
return FALSE; return FALSE;
} }
} }
if (secret.len == 7 && strneq(secret.ptr, "%prompt", 7)) if (secret.len == 7 && strpfx(secret.ptr, "%prompt"))
{ {
callback_cred_t *cb; callback_cred_t *cb;
passphrase_cb_data_t pp_data = { passphrase_cb_data_t pp_data = {
@@ -1142,8 +1142,7 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
{ {
continue; continue;
} }
if (line.len > strlen("include ") && if (line.len > strlen("include ") && strpfx(line.ptr, "include "))
strneq(line.ptr, "include ", strlen("include ")))
{ {
char **expanded, *dir, pattern[PATH_MAX]; char **expanded, *dir, pattern[PATH_MAX];
u_char *pos; u_char *pos;
@@ -1211,7 +1210,7 @@ static void load_secrets(private_stroke_cred_t *this, mem_cred_t *secrets,
continue; continue;
} }
if (line.len > 2 && strneq(": ", line.ptr, 2)) if (line.len > 2 && strpfx(line.ptr, ": "))
{ {
/* no ids, skip the ':' */ /* no ids, skip the ':' */
ids = chunk_empty; ids = chunk_empty;
@@ -78,7 +78,7 @@
/** this is the default number of ipsec devices */ /** this is the default number of ipsec devices */
#define DEFAULT_IPSEC_DEV_COUNT 4 #define DEFAULT_IPSEC_DEV_COUNT 4
/** TRUE if the given name matches an ipsec device */ /** TRUE if the given name matches an ipsec device */
#define IS_IPSEC_DEV(name) (strneq((name), IPSEC_DEV_PREFIX, sizeof(IPSEC_DEV_PREFIX) - 1)) #define IS_IPSEC_DEV(name) (strpfx((name), IPSEC_DEV_PREFIX))
/** the following stuff is from ipsec_tunnel.h */ /** the following stuff is from ipsec_tunnel.h */
struct ipsectunnelconf struct ipsectunnelconf
@@ -2332,7 +2332,7 @@ METHOD(kernel_ipsec_t, query_policy, status_t,
while (fgets(line, sizeof(line), file)) while (fgets(line, sizeof(line), file))
{ {
if (strneq(line, said, strlen(said))) if (strpfx(line, said))
{ {
/* fine we found the correct line, now find the idle time */ /* fine we found the correct line, now find the idle time */
u_int32_t idle_time; u_int32_t idle_time;
@@ -126,7 +126,7 @@ static void remove_nameserver(private_resolve_handler_t *this,
/* copy all, but matching line */ /* copy all, but matching line */
while (fgets(line, sizeof(line), in)) while (fgets(line, sizeof(line), in))
{ {
if (strneq(line, matcher, strlen(matcher))) if (strpfx(line, matcher))
{ {
DBG1(DBG_IKE, "removing DNS server %H from %s", DBG1(DBG_IKE, "removing DNS server %H from %s",
addr, this->file); addr, this->file);
+65
View File
@@ -0,0 +1,65 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# copy-n-paste from Makefile.am
libimcv_la_SOURCES := \
imcv.h imcv.c \
imc/imc_agent.h imc/imc_agent.c imc/imc_state.h \
imc/imc_msg.h imc/imc_msg.c \
imv/imv_agent.h imv/imv_agent.c imv/imv_state.h \
imv/imv_agent_if.h imv/imv_if.h \
imv/imv_database.h imv/imv_database.c \
imv/imv_msg.h imv/imv_msg.c \
imv/imv_lang_string.h imv/imv_lang_string.c \
imv/imv_reason_string.h imv/imv_reason_string.c \
imv/imv_remediation_string.h imv/imv_remediation_string.c \
imv/imv_session.h imv/imv_session.c \
imv/imv_workitem.h imv/imv_workitem.c \
imv/tables.sql imv/data.sql \
ietf/ietf_attr.h ietf/ietf_attr.c \
ietf/ietf_attr_assess_result.h ietf/ietf_attr_assess_result.c \
ietf/ietf_attr_attr_request.h ietf/ietf_attr_attr_request.c \
ietf/ietf_attr_fwd_enabled.h ietf/ietf_attr_fwd_enabled.c \
ietf/ietf_attr_default_pwd_enabled.h ietf/ietf_attr_default_pwd_enabled.c \
ietf/ietf_attr_installed_packages.h ietf/ietf_attr_installed_packages.c \
ietf/ietf_attr_numeric_version.h ietf/ietf_attr_numeric_version.c \
ietf/ietf_attr_op_status.h ietf/ietf_attr_op_status.c \
ietf/ietf_attr_pa_tnc_error.h ietf/ietf_attr_pa_tnc_error.c \
ietf/ietf_attr_port_filter.h ietf/ietf_attr_port_filter.c \
ietf/ietf_attr_product_info.h ietf/ietf_attr_product_info.c \
ietf/ietf_attr_remediation_instr.h ietf/ietf_attr_remediation_instr.c \
ietf/ietf_attr_string_version.h ietf/ietf_attr_string_version.c \
ita/ita_attr.h ita/ita_attr.c \
ita/ita_attr_command.h ita/ita_attr_command.c \
ita/ita_attr_dummy.h ita/ita_attr_dummy.c \
ita/ita_attr_get_settings.h ita/ita_attr_get_settings.c \
ita/ita_attr_settings.h ita/ita_attr_settings.c \
ita/ita_attr_angel.h ita/ita_attr_angel.c \
ita/ita_attr_device_id.h ita/ita_attr_device_id.c \
os_info/os_info.h os_info/os_info.c \
pa_tnc/pa_tnc_attr.h \
pa_tnc/pa_tnc_msg.h pa_tnc/pa_tnc_msg.c \
pa_tnc/pa_tnc_attr_manager.h pa_tnc/pa_tnc_attr_manager.c
LOCAL_SRC_FILES := $(filter %.c,$(libimcv_la_SOURCES))
# build libimcv ----------------------------------------------------------------
LOCAL_C_INCLUDES += \
$(libvstr_PATH) \
$(strongswan_PATH)/src/libtncif \
$(strongswan_PATH)/src/libstrongswan
LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := libimcv
LOCAL_MODULE_TAGS := optional
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES += libstrongswan libtncif
include $(BUILD_SHARED_LIBRARY)
+1
View File
@@ -174,6 +174,7 @@ void libimcv_deinit(void)
imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_IETF); imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_IETF);
imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_ITA); imcv_pa_tnc_attributes->remove_vendor(imcv_pa_tnc_attributes, PEN_ITA);
DESTROY_IF(imcv_pa_tnc_attributes); DESTROY_IF(imcv_pa_tnc_attributes);
imcv_pa_tnc_attributes = NULL;
DESTROY_IF(imcv_db); DESTROY_IF(imcv_db);
DBG1(DBG_LIB, "libimcv terminated"); DBG1(DBG_LIB, "libimcv terminated");
} }
+2 -2
View File
@@ -182,8 +182,8 @@ METHOD(os_info_t, get_setting, chunk_t,
size_t i = 0; size_t i = 0;
chunk_t value; chunk_t value;
if (!strneq(name, "/etc/", 5) && !strneq(name, "/proc/", 6) && if (!strpfx(name, "/etc/") && !strpfx(name, "/proc/") &&
!strneq(name, "/sys/", 5) && !strneq(name, "/var/", 5)) !strpfx(name, "/sys/") && !strpfx(name, "/var/"))
{ {
/** /**
* In order to guarantee privacy, only settings from the * In order to guarantee privacy, only settings from the
@@ -282,7 +282,10 @@ METHOD(imv_state_t, get_reason_string, bool,
/* Instantiate a TNC Reason String object */ /* Instantiate a TNC Reason String object */
DESTROY_IF(this->reason_string); DESTROY_IF(this->reason_string);
this->reason_string = imv_reason_string_create(*reason_language); this->reason_string = imv_reason_string_create(*reason_language);
this->reason_string->add_reason(this->reason_string, reasons); if (this->rec != TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION)
{
this->reason_string->add_reason(this->reason_string, reasons);
}
*reason_string = this->reason_string->get_encoding(this->reason_string); *reason_string = this->reason_string->get_encoding(this->reason_string);
return TRUE; return TRUE;
+70
View File
@@ -0,0 +1,70 @@
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
# copy-n-paste from Makefile.am
libpts_la_SOURCES := \
libpts.h libpts.c \
pts/pts.h pts/pts.c \
pts/pts_error.h pts/pts_error.c \
pts/pts_pcr.h pts/pts_pcr.c \
pts/pts_proto_caps.h \
pts/pts_req_func_comp_evid.h \
pts/pts_simple_evid_final.h \
pts/pts_creds.h pts/pts_creds.c \
pts/pts_database.h pts/pts_database.c \
pts/pts_dh_group.h pts/pts_dh_group.c \
pts/pts_file_meas.h pts/pts_file_meas.c \
pts/pts_file_meta.h pts/pts_file_meta.c \
pts/pts_file_type.h pts/pts_file_type.c \
pts/pts_meas_algo.h pts/pts_meas_algo.c \
pts/components/pts_component.h \
pts/components/pts_component_manager.h pts/components/pts_component_manager.c \
pts/components/pts_comp_evidence.h pts/components/pts_comp_evidence.c \
pts/components/pts_comp_func_name.h pts/components/pts_comp_func_name.c \
pts/components/ita/ita_comp_func_name.h pts/components/ita/ita_comp_func_name.c \
pts/components/ita/ita_comp_ima.h pts/components/ita/ita_comp_ima.c \
pts/components/ita/ita_comp_tboot.h pts/components/ita/ita_comp_tboot.c \
pts/components/ita/ita_comp_tgrub.h pts/components/ita/ita_comp_tgrub.c \
pts/components/tcg/tcg_comp_func_name.h pts/components/tcg/tcg_comp_func_name.c \
tcg/tcg_attr.h tcg/tcg_attr.c \
tcg/tcg_pts_attr_proto_caps.h tcg/tcg_pts_attr_proto_caps.c \
tcg/tcg_pts_attr_dh_nonce_params_req.h tcg/tcg_pts_attr_dh_nonce_params_req.c \
tcg/tcg_pts_attr_dh_nonce_params_resp.h tcg/tcg_pts_attr_dh_nonce_params_resp.c \
tcg/tcg_pts_attr_dh_nonce_finish.h tcg/tcg_pts_attr_dh_nonce_finish.c \
tcg/tcg_pts_attr_meas_algo.h tcg/tcg_pts_attr_meas_algo.c \
tcg/tcg_pts_attr_get_tpm_version_info.h tcg/tcg_pts_attr_get_tpm_version_info.c \
tcg/tcg_pts_attr_tpm_version_info.h tcg/tcg_pts_attr_tpm_version_info.c \
tcg/tcg_pts_attr_get_aik.h tcg/tcg_pts_attr_get_aik.c \
tcg/tcg_pts_attr_aik.h tcg/tcg_pts_attr_aik.c \
tcg/tcg_pts_attr_req_func_comp_evid.h tcg/tcg_pts_attr_req_func_comp_evid.c \
tcg/tcg_pts_attr_gen_attest_evid.h tcg/tcg_pts_attr_gen_attest_evid.c \
tcg/tcg_pts_attr_simple_comp_evid.h tcg/tcg_pts_attr_simple_comp_evid.c \
tcg/tcg_pts_attr_simple_evid_final.h tcg/tcg_pts_attr_simple_evid_final.c \
tcg/tcg_pts_attr_req_file_meas.h tcg/tcg_pts_attr_req_file_meas.c \
tcg/tcg_pts_attr_file_meas.h tcg/tcg_pts_attr_file_meas.c \
tcg/tcg_pts_attr_req_file_meta.h tcg/tcg_pts_attr_req_file_meta.c \
tcg/tcg_pts_attr_unix_file_meta.h tcg/tcg_pts_attr_unix_file_meta.c
LOCAL_SRC_FILES := $(filter %.c,$(libpts_la_SOURCES))
# build libpts -----------------------------------------------------------------
LOCAL_C_INCLUDES += \
$(libvstr_PATH) \
$(strongswan_PATH)/src/libtncif \
$(strongswan_PATH)/src/libimcv \
$(strongswan_PATH)/src/libstrongswan
LOCAL_CFLAGS := $(strongswan_CFLAGS)
LOCAL_MODULE := libpts
LOCAL_MODULE_TAGS := optional
LOCAL_ARM_MODE := arm
LOCAL_PRELINK_MODULE := false
LOCAL_SHARED_LIBRARIES += libstrongswan libimcv
include $(BUILD_SHARED_LIBRARY)
+2 -16
View File
@@ -302,20 +302,7 @@ pts_file_meas_t *pts_file_meas_create_from_path(u_int16_t request_id,
return NULL; return NULL;
} }
measurement = chunk_create(hash, hasher->get_hash_size(hasher)); measurement = chunk_create(hash, hasher->get_hash_size(hasher));
this = (private_pts_file_meas_t*)pts_file_meas_create(request_id);
INIT(this,
.public = {
.get_request_id = _get_request_id,
.get_file_count = _get_file_count,
.add = _add,
.create_enumerator = _create_enumerator,
.check = _check,
.verify = _verify,
.destroy = _destroy,
},
.request_id = request_id,
.list = linked_list_create(),
);
if (is_dir) if (is_dir)
{ {
@@ -338,8 +325,7 @@ pts_file_meas_t *pts_file_meas_create_from_path(u_int16_t request_id,
{ {
if (!hash_file(hasher, abs_name, hash)) if (!hash_file(hasher, abs_name, hash))
{ {
success = FALSE; continue;
break;
} }
filename = use_rel_name ? rel_name : abs_name; filename = use_rel_name ? rel_name : abs_name;
DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename); DBG2(DBG_PTS, " %#B for '%s'", &measurement, filename);
@@ -112,7 +112,7 @@ METHOD(fetcher_t, fetch, status_t,
status_t status = FAILED; status_t status = FAILED;
chunk_t *result = userdata; chunk_t *result = userdata;
if (!strneq(url, "ldap", 4)) if (!strpfx(url, "ldap"))
{ {
return NOT_SUPPORTED; return NOT_SUPPORTED;
} }
@@ -666,7 +666,7 @@ mysql_database_t *mysql_database_create(char *uri)
conn_t *conn; conn_t *conn;
private_mysql_database_t *this; private_mysql_database_t *this;
if (!strneq(uri, "mysql://", 8)) if (!strpfx(uri, "mysql://"))
{ {
return NULL; return NULL;
} }
@@ -319,7 +319,7 @@ sqlite_database_t *sqlite_database_create(char *uri)
/** /**
* parse sqlite:///path/to/file.db uri * parse sqlite:///path/to/file.db uri
*/ */
if (!strneq(uri, "sqlite://", 9)) if (!strpfx(uri, "sqlite://"))
{ {
return NULL; return NULL;
} }
@@ -85,7 +85,7 @@ static sshkey_public_key_t *parse_public_key(chunk_t blob)
BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END); BUILD_RSA_MODULUS, n, BUILD_RSA_PUB_EXP, e, BUILD_END);
} }
else if (format.len > strlen(ECDSA_PREFIX) && else if (format.len > strlen(ECDSA_PREFIX) &&
strneq(format.ptr, ECDSA_PREFIX, strlen(ECDSA_PREFIX))) strpfx(format.ptr, ECDSA_PREFIX))
{ {
chunk_t ec_blob, identifier, q, oid, encoded; chunk_t ec_blob, identifier, q, oid, encoded;
sshkey_public_key_t *key; sshkey_public_key_t *key;
+23 -6
View File
@@ -81,9 +81,20 @@ static inline bool streq(const char *x, const char *y)
} }
/** /**
* Macro compares two strings for equality, length limited * Helper function that compares two strings for equality, length limited
*/ */
#define strneq(x,y,len) (strncmp(x, y, len) == 0) static inline bool strneq(const char *x, const char *y, size_t len)
{
return strncmp(x, y, len) == 0;
}
/**
* Helper function that checks if a string starts with a given prefix
*/
static inline bool strpfx(const char *x, const char *prefix)
{
return strneq(x, prefix, strlen(prefix));
}
/** /**
* Helper function that compares two strings for equality ignoring case * Helper function that compares two strings for equality ignoring case
@@ -94,9 +105,12 @@ static inline bool strcaseeq(const char *x, const char *y)
} }
/** /**
* Macro compares two strings for equality ignoring case, length limited * Helper function that compares two strings for equality ignoring case, length limited
*/ */
#define strncaseeq(x,y,len) (strncasecmp(x, y, len) == 0) static inline bool strncaseeq(const char *x, const char *y, size_t len)
{
return strncasecmp(x, y, len) == 0;
}
/** /**
* NULL-safe strdup variant * NULL-safe strdup variant
@@ -107,9 +121,12 @@ static inline char *strdupnull(const char *s)
} }
/** /**
* Macro compares two binary blobs for equality * Helper function that compares two binary blobs for equality
*/ */
#define memeq(x,y,len) (memcmp(x, y, len) == 0) static inline bool memeq(const void *x, const void *y, size_t len)
{
return memcmp(x, y, len) == 0;
}
/** /**
* Macro gives back larger of two values. * Macro gives back larger of two values.
+5
View File
@@ -100,6 +100,11 @@ static bool load_imcvs_from_config(char *filename, bool is_imc)
void *addr; void *addr;
char *label; char *label;
if (!filename || !*filename)
{
return TRUE;
}
label = is_imc ? "IMC" : "IMV"; label = is_imc ? "IMC" : "IMV";
DBG1(DBG_TNC, "loading %ss from '%s'", label, filename); DBG1(DBG_TNC, "loading %ss from '%s'", label, filename);