ITA-HSR/Device ID attribute & IMV OS state machine
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 4 May 2013 19:06:36 +0000 (21:06 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Fri, 21 Jun 2013 21:25:22 +0000 (23:25 +0200)
src/libimcv/Makefile.am
src/libimcv/ietf/ietf_attr_attr_request.c
src/libimcv/ita/ita_attr.c
src/libimcv/ita/ita_attr.h
src/libimcv/ita/ita_attr_device_id.c [new file with mode: 0644]
src/libimcv/ita/ita_attr_device_id.h [new file with mode: 0644]
src/libimcv/plugins/imc_os/imc_os.c
src/libimcv/plugins/imv_os/imv_os.c
src/libimcv/plugins/imv_os/imv_os_state.c
src/libimcv/plugins/imv_os/imv_os_state.h

index 50cfbf9..268fff0 100644 (file)
@@ -34,6 +34,7 @@ libimcv_la_SOURCES = \
        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 \
index 5dc4870..3b4fd26 100644 (file)
@@ -234,7 +234,11 @@ pa_tnc_attr_t *ietf_attr_attr_request_create(pen_t vendor_id, u_int32_t type)
                .list = linked_list_create(),
                .ref = 1,
        );
-       add(this, vendor_id, type);
+
+       if (vendor_id != PEN_RESERVED)
+       {
+               add(this, vendor_id, type);
+       }
 
        return &this->public.pa_tnc_attribute;
 }
index 590bc9b..f395671 100644 (file)
 #include "ita/ita_attr_get_settings.h"
 #include "ita/ita_attr_settings.h"
 #include "ita/ita_attr_angel.h"
+#include "ita/ita_attr_device_id.h"
 
-ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_ECHO,
+ENUM(ita_attr_names, ITA_ATTR_COMMAND, ITA_ATTR_DEVICE_ID,
        "Command",
        "Dummy",
        "Get Settings",
        "Settings",
        "Start Angel",
        "Stop Angel",
-       "Echo"
+       "Echo",
+       "Device ID"
 );
 
 /**
@@ -49,6 +51,8 @@ pa_tnc_attr_t* ita_attr_create_from_data(u_int32_t type, chunk_t value)
                        return ita_attr_angel_create_from_data(TRUE, value);
                case ITA_ATTR_STOP_ANGEL:
                        return ita_attr_angel_create_from_data(FALSE, value);
+               case ITA_ATTR_DEVICE_ID:
+                       return ita_attr_device_id_create_from_data(value);
                default:
                        return NULL;
        }
index 446fa03..ac5d8ab 100644 (file)
@@ -37,7 +37,8 @@ enum ita_attr_t {
        ITA_ATTR_SETTINGS = 4,
        ITA_ATTR_START_ANGEL = 5,
        ITA_ATTR_STOP_ANGEL = 6,
-       ITA_ATTR_ECHO = 7
+       ITA_ATTR_ECHO = 7,
+       ITA_ATTR_DEVICE_ID = 8
 };
 
 /**
diff --git a/src/libimcv/ita/ita_attr_device_id.c b/src/libimcv/ita/ita_attr_device_id.c
new file mode 100644 (file)
index 0000000..36907eb
--- /dev/null
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 2013 Andreas Steffen
+ * HSR 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 "ita_attr.h"
+#include "ita_attr_device_id.h"
+
+#include <pen/pen.h>
+
+#include <utils/debug.h>
+
+typedef struct private_ita_attr_device_id_t private_ita_attr_device_id_t;
+
+/**
+ * Private data of an ita_attr_device_id_t object.
+ */
+struct private_ita_attr_device_id_t {
+
+       /**
+        * Public members of ita_attr_device_id_t
+        */
+       ita_attr_device_id_t public;
+
+       /**
+        * Vendor-specific attribute type
+        */
+       pen_type_t type;
+
+       /**
+        * Attribute value
+        */
+       chunk_t value;
+
+       /**
+        * Noskip flag
+        */
+       bool noskip_flag;
+
+       /**
+        * Reference count
+        */
+       refcount_t ref;
+};
+
+METHOD(pa_tnc_attr_t, get_type, pen_type_t,
+       private_ita_attr_device_id_t *this)
+{
+       return this->type;
+}
+
+METHOD(pa_tnc_attr_t, get_value, chunk_t,
+       private_ita_attr_device_id_t *this)
+{
+       return this->value;
+}
+
+METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
+       private_ita_attr_device_id_t *this)
+{
+       return this->noskip_flag;
+}
+
+METHOD(pa_tnc_attr_t, set_noskip_flag,void,
+       private_ita_attr_device_id_t *this, bool noskip)
+{
+       this->noskip_flag = noskip;
+}
+
+METHOD(pa_tnc_attr_t, build, void,
+       private_ita_attr_device_id_t *this)
+{
+       return;
+}
+
+METHOD(pa_tnc_attr_t, process, status_t,
+       private_ita_attr_device_id_t *this, u_int32_t *offset)
+{
+       return SUCCESS;
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+       private_ita_attr_device_id_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public.pa_tnc_attribute;
+}
+
+METHOD(pa_tnc_attr_t, destroy, void,
+       private_ita_attr_device_id_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               free(this->value.ptr);
+               free(this);
+       }
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *ita_attr_device_id_create_from_data(chunk_t value)
+{
+       private_ita_attr_device_id_t *this;
+
+       INIT(this,
+               .public = {
+                       .pa_tnc_attribute = {
+                               .get_type = _get_type,
+                               .get_value = _get_value,
+                               .get_noskip_flag = _get_noskip_flag,
+                               .set_noskip_flag = _set_noskip_flag,
+                               .build = _build,
+                               .process = _process,
+                               .get_ref = _get_ref,
+                               .destroy = _destroy,
+                       },
+               },
+               .type = { PEN_ITA, ITA_ATTR_DEVICE_ID },
+               .value = chunk_clone(value),
+               .ref = 1,
+       );
+
+       return &this->public.pa_tnc_attribute;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *ita_attr_device_id_create(chunk_t value)
+{
+       return ita_attr_device_id_create_from_data(value);
+}
+
diff --git a/src/libimcv/ita/ita_attr_device_id.h b/src/libimcv/ita/ita_attr_device_id.h
new file mode 100644 (file)
index 0000000..558a8e0
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2013 Andreas Steffen
+ * HSR 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 ita_attr_device_id ita_attr_device_id
+ * @{ @ingroup ita_attr
+ */
+
+#ifndef ITA_ATTR_DEVICE_ID_H_
+#define ITA_ATTR_DEVICE_ID_H_
+
+typedef struct ita_attr_device_id_t ita_attr_device_id_t;
+
+#include "pa_tnc/pa_tnc_attr.h"
+
+/**
+ * Class implementing the ITA Device ID PA-TNC attribute.
+ *
+ */
+struct ita_attr_device_id_t {
+
+       /**
+        * Public PA-TNC attribute interface
+        */
+       pa_tnc_attr_t pa_tnc_attribute;
+
+};
+
+/**
+ * Creates an ita_attr_device_id_t object
+ *
+ * @param size                         ITA Device ID attribute value
+ */
+pa_tnc_attr_t* ita_attr_device_id_create(chunk_t value);
+
+/**
+ * Creates an ita_attr_device_id_t object from received data
+ *
+ * @param value                                binary value blob
+ */
+pa_tnc_attr_t* ita_attr_device_id_create_from_data(chunk_t value);
+
+#endif /** ITA_ATTR_DEVICE_ID_H_ @}*/
index f6e205c..98eac24 100644 (file)
@@ -30,6 +30,7 @@
 #include <ita/ita_attr_get_settings.h>
 #include <ita/ita_attr_settings.h>
 #include <ita/ita_attr_angel.h>
+#include <ita/ita_attr_device_id.h>
 #include <os_info/os_info.h>
 
 #include <tncif_pa_subtypes.h>
@@ -213,7 +214,7 @@ static void add_fwd_enabled(imc_msg_t *msg)
        os_fwd_status_t fwd_status;
 
        fwd_status = os->get_fwd_status(os);
-       DBG1(DBG_IMC, "IPv4 forwarding status: %N",
+       DBG1(DBG_IMC, "IPv4 forwarding is %N",
                                   os_fwd_status_names, fwd_status);
        attr = ietf_attr_fwd_enabled_create(fwd_status);
        msg->add_attribute(msg, attr);
@@ -226,12 +227,37 @@ static void add_default_pwd_enabled(imc_msg_t *msg)
 {
        pa_tnc_attr_t *attr;
 
-       DBG1(DBG_IMC, "factory default password: disabled");
+       DBG1(DBG_IMC, "factory default password is disabled");
        attr = ietf_attr_default_pwd_enabled_create(FALSE);
        msg->add_attribute(msg, attr);
 }
 
 /**
+ * Add ITA Device ID attribute to the send queue
+ */
+static void add_device_id(imc_msg_t *msg)
+{
+       pa_tnc_attr_t *attr;
+       chunk_t value;
+       char *name;
+
+       name = os->get_type(os) == OS_TYPE_ANDROID ?
+                                 "android_id" : "/var/lib/dbus/machine-id";
+       value = os->get_setting(os, name);
+
+       /* trim trailing newline character */
+       if (value.ptr[value.len - 1] == '\n')
+       {
+               value.len--;
+       }
+
+       DBG1(DBG_IMC, "device ID is %.*s", value.len, value.ptr);
+       attr = ita_attr_device_id_create(value);
+       msg->add_attribute(msg, attr);
+       free(value.ptr);
+}
+
+/**
  * Add an IETF Installed Packages attribute to the send queue
  */
 static void add_installed_packages(imc_state_t *state, imc_msg_t *msg)
@@ -365,6 +391,7 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
                add_op_status(out_msg);
                add_fwd_enabled(out_msg);
                add_default_pwd_enabled(out_msg);
+               add_device_id(out_msg);
 
                /* send PA-TNC message with the excl flag not set */
                result = out_msg->send(out_msg, FALSE);
@@ -410,35 +437,45 @@ static TNC_Result receive_message(imc_state_t *state, imc_msg_t *in_msg)
                                e = attr_cast->create_enumerator(attr_cast);
                                while (e->enumerate(e, &entry))
                                {
-                                       if (entry->vendor_id != PEN_IETF)
+                                       if (entry->vendor_id == PEN_IETF)
                                        {
-                                               continue;
+                                               switch (entry->type)
+                                               {
+                                                       case IETF_ATTR_PRODUCT_INFORMATION:
+                                                               add_product_info(out_msg);
+                                                               break;
+                                                       case IETF_ATTR_STRING_VERSION:
+                                                               add_string_version(out_msg);
+                                                               break;
+                                                       case IETF_ATTR_NUMERIC_VERSION:
+                                                               add_numeric_version(out_msg);
+                                                               break;
+                                                       case IETF_ATTR_OPERATIONAL_STATUS:
+                                                               add_op_status(out_msg);
+                                                               break;
+                                                       case IETF_ATTR_FORWARDING_ENABLED:
+                                                               add_fwd_enabled(out_msg);
+                                                               break;
+                                                       case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
+                                                               add_default_pwd_enabled(out_msg);
+                                                               break;
+                                                       case IETF_ATTR_INSTALLED_PACKAGES:
+                                                               add_installed_packages(state, out_msg);
+                                                               break;
+                                                       default:
+                                                               break;
+                                               }
                                        }
-                                       switch (entry->type)
+                                       else if (entry->vendor_id == PEN_ITA)
                                        {
-                                               case IETF_ATTR_PRODUCT_INFORMATION:
-                                                       add_product_info(out_msg);
-                                                       break;
-                                               case IETF_ATTR_STRING_VERSION:
-                                                       add_string_version(out_msg);
-                                                       break;
-                                               case IETF_ATTR_NUMERIC_VERSION:
-                                                       add_numeric_version(out_msg);
-                                                       break;
-                                               case IETF_ATTR_OPERATIONAL_STATUS:
-                                                       add_op_status(out_msg);
-                                                       break;
-                                               case IETF_ATTR_FORWARDING_ENABLED:
-                                                       add_fwd_enabled(out_msg);
-                                                       break;
-                                               case IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED:
-                                                       add_default_pwd_enabled(out_msg);
-                                                       break;
-                                               case IETF_ATTR_INSTALLED_PACKAGES:
-                                                       add_installed_packages(state, out_msg);
-                                                       break;
-                                               default:
-                                                       break;
+                                               switch (entry->type)
+                                               {
+                                                       case ITA_ATTR_DEVICE_ID:
+                                                               add_device_id(out_msg);
+                                                               break;
+                                                       default:
+                                                               break;
+                                               }
                                        }
                                }
                                e->destroy(e);
index 560b8bf..44b2907 100644 (file)
@@ -33,6 +33,7 @@
 #include <ita/ita_attr_get_settings.h>
 #include <ita/ita_attr_settings.h>
 #include <ita/ita_attr_angel.h>
+#include <ita/ita_attr_device_id.h>
 
 #include <tncif_names.h>
 #include <tncif_pa_subtypes.h>
@@ -53,6 +54,22 @@ static pen_type_t msg_types[] = {
 static imv_agent_t *imv_os;
 
 /**
+ * Flag set when corresponding attribute has been received
+ */
+typedef enum imv_os_attr_t imv_os_attr_t;
+
+enum imv_os_attr_t {
+       IMV_OS_ATTR_PRODUCT_INFORMATION =         (1<<0),
+       IMV_OS_ATTR_STRING_VERSION =              (1<<1),
+       IMV_OS_ATTR_NUMERIC_VERSION =             (1<<2),
+       IMV_OS_ATTR_OPERATIONAL_STATUS =          (1<<3),
+       IMV_OS_ATTR_FORWARDING_ENABLED =          (1<<4),
+       IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED = (1<<5),
+       IMV_OS_ATTR_DEVICE_ID =                   (1<<6),
+       IMV_OS_ATTR_ALL =                         (1<<7)-1
+};
+
+/**
  * IMV OS database
  */
 static imv_os_database_t *os_db;
@@ -135,8 +152,6 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
        chunk_t os_version = chunk_empty;
        bool fatal_error = FALSE, assessment = FALSE;
        char non_market_apps_str[] = "install_non_market_apps";
-       char android_id_str[] = "android_id";
-       char machine_id_str[] = "/var/lib/dbus/machine-id";
 
        os_state = (imv_os_state_t*)state;
 
@@ -164,6 +179,8 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                        ietf_attr_product_info_t *attr_cast;
                                        pen_t vendor_id;
 
+                                       os_state->set_received(os_state,
+                                                                                  IMV_OS_ATTR_PRODUCT_INFORMATION);
                                        attr_cast = (ietf_attr_product_info_t*)attr;
                                        os_name = attr_cast->get_info(attr_cast, &vendor_id, NULL);
                                        if (vendor_id != PEN_IETF)
@@ -183,6 +200,8 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                {
                                        ietf_attr_string_version_t *attr_cast;
 
+                                       os_state->set_received(os_state,
+                                                                                  IMV_OS_ATTR_STRING_VERSION);
                                        attr_cast = (ietf_attr_string_version_t*)attr;
                                        os_version = attr_cast->get_version(attr_cast, NULL, NULL);
                                        if (os_version.len)
@@ -197,6 +216,8 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                        ietf_attr_numeric_version_t *attr_cast;
                                        u_int32_t major, minor;
 
+                                       os_state->set_received(os_state,
+                                                                                  IMV_OS_ATTR_NUMERIC_VERSION);
                                        attr_cast = (ietf_attr_numeric_version_t*)attr;
                                        attr_cast->get_version(attr_cast, &major, &minor);
                                        DBG1(DBG_IMV, "operating system numeric version is %d.%d",
@@ -210,6 +231,8 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                        op_result_t op_result;
                                        time_t last_boot;
 
+                                       os_state->set_received(os_state,
+                                                                                  IMV_OS_ATTR_OPERATIONAL_STATUS);
                                        attr_cast = (ietf_attr_op_status_t*)attr;
                                        op_status = attr_cast->get_status(attr_cast);
                                        op_result = attr_cast->get_result(attr_cast);
@@ -224,9 +247,11 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                        ietf_attr_fwd_enabled_t *attr_cast;
                                        os_fwd_status_t fwd_status;
 
+                                       os_state->set_received(os_state,
+                                                                                  IMV_OS_ATTR_FORWARDING_ENABLED);
                                        attr_cast = (ietf_attr_fwd_enabled_t*)attr;
                                        fwd_status = attr_cast->get_status(attr_cast);
-                                       DBG1(DBG_IMV, "IPv4 forwarding status: %N",
+                                       DBG1(DBG_IMV, "IPv4 forwarding is %N",
                                                                   os_fwd_status_names, fwd_status);
                                        if (fwd_status == OS_FWD_ENABLED)
                                        {
@@ -240,9 +265,11 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                        ietf_attr_default_pwd_enabled_t *attr_cast;
                                        bool default_pwd_status;
 
+                                       os_state->set_received(os_state,
+                                                                       IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED);
                                        attr_cast = (ietf_attr_default_pwd_enabled_t*)attr;
                                        default_pwd_status = attr_cast->get_status(attr_cast);
-                                       DBG1(DBG_IMV, "factory default password: %sabled",
+                                       DBG1(DBG_IMV, "factory default password is %sabled",
                                                                   default_pwd_status ? "en":"dis");
                                        if (default_pwd_status)
                                        {
@@ -257,9 +284,6 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                        enumerator_t *e;
                                        status_t status;
 
-                                       /* Received at least one Installed Packages attribute */
-                                       os_state->set_package_request(os_state, FALSE);
-
                                        if (!os_db)
                                        {
                                                break;
@@ -290,9 +314,7 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                case ITA_ATTR_SETTINGS:
                                {
                                        ita_attr_settings_t *attr_cast;
-                                       imv_database_t *imv_db;
                                        enumerator_t *e;
-                                       int session_id, device_id;
                                        char *name;
                                        chunk_t value;
 
@@ -306,27 +328,32 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                                                        os_state->set_os_settings(os_state,
                                                                                                OS_SETTINGS_NON_MARKET_APPS);
                                                }
-                                               else if ((streq(name, android_id_str) ||
-                                                                 streq(name, machine_id_str)) && os_db)
-                                               {
-                                                       imv_db = imv_os->get_database(imv_os);
-                                                       if (imv_db)
-                                                       {
-                                                               session_id = state->get_session_id(state);
-                                                               device_id = imv_db->add_device(imv_db,
-                                                                                                               session_id, value);
-                                                               os_state->set_device_id(os_state, device_id);
-
-                                                               /* trigger the policy manager */
-                                                               imv_db->policy_script(imv_db, session_id, TRUE);
-                                                       }
-                                               }
                                                DBG1(DBG_IMV, "setting '%s'\n  %.*s",
                                                         name, value.len, value.ptr);
                                        }
                                        e->destroy(e);
                                        break;
                                }
+                               case ITA_ATTR_DEVICE_ID:
+                               {
+                                       imv_database_t *imv_db;
+                                       int session_id, device_id;
+                                       chunk_t value;
+
+                                       os_state->set_received(os_state,
+                                                                                  IMV_OS_ATTR_DEVICE_ID);
+                                       value = attr->get_value(attr);
+                                       DBG1(DBG_IMV, "device ID is %.*s", value.len, value.ptr);
+
+                                       imv_db = imv_os->get_database(imv_os);
+                                       if (imv_db)
+                                       {
+                                               session_id = state->get_session_id(state);
+                                               device_id = imv_db->add_device(imv_db, session_id, value);
+                                               os_state->set_device_id(os_state, device_id);
+                                       }
+                                       break;
+                               }
                                case ITA_ATTR_START_ANGEL:
                                        os_state->set_angel_count(os_state, TRUE);
                                        break;
@@ -340,10 +367,13 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
        }
        enumerator->destroy(enumerator);
 
+       /**
+        * The IETF Product Information and String Version attributes
+        * are supposed to arrive in the same PA-TNC message
+        */
        if (os_name.len && os_version.len)
        {
                os_type_t os_type;
-               ita_attr_get_settings_t *attr_cast;
                imv_database_t *imv_db;
 
                /* set the OS type, name and version */
@@ -356,33 +386,9 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
                        imv_db->add_product(imv_db, state->get_session_id(state),
                                        os_state->get_info(os_state, NULL, NULL, NULL));
                }
-
-               /* requesting installed packages */
-               os_state->set_package_request(os_state, TRUE);
-               attr = ietf_attr_attr_request_create(PEN_IETF,
-                                                                                        IETF_ATTR_INSTALLED_PACKAGES);
-               out_msg->add_attribute(out_msg, attr);
-
-               /* requesting Android or Linux settings */
-               attr = ita_attr_get_settings_create();
-               attr_cast = (ita_attr_get_settings_t*)attr;
-
-               if (os_type == OS_TYPE_ANDROID)
-               {
-                       attr_cast->add(attr_cast, android_id_str);
-                       attr_cast->add(attr_cast, non_market_apps_str);
-               }
-               else
-               {
-                       attr_cast->add(attr_cast, machine_id_str);
-                       attr_cast->add(attr_cast, "/proc/sys/kernel/tainted");
-               }
-               out_msg->add_attribute(out_msg, attr);
        }
 
-       if (fatal_error ||
-          (os_state->get_attribute_request(os_state) &&
-               os_state->get_info(os_state, NULL, NULL, NULL) == NULL))
+       if (fatal_error)
        {
                state->set_recommendation(state,
                                                                TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
@@ -392,9 +398,8 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg)
 
        /* If all Installed Packages attributes were received, go to assessment */
        if (!assessment &&
-               !os_state->get_package_request(os_state) &&
-               !os_state->get_angel_count(os_state) &&
-                os_state->get_info(os_state, NULL, NULL, NULL))
+                os_state->get_handshake_state(os_state) == IMV_OS_STATE_POLICY_START &&
+               !os_state->get_angel_count(os_state))
        {
                int count, count_update, count_blacklist, count_ok;
                u_int os_settings;
@@ -532,16 +537,61 @@ TNC_Result TNC_IMV_SolicitRecommendation(TNC_IMVID imv_id,
 }
 
 /**
+ * Build an IETF Attribute Request attribute for missing attributes
+ */
+static pa_tnc_attr_t* build_attr_request(u_int received)
+{
+       pa_tnc_attr_t *attr;
+       ietf_attr_attr_request_t *attr_cast;
+
+       attr = ietf_attr_attr_request_create(PEN_RESERVED, 0);
+       attr_cast = (ietf_attr_attr_request_t*)attr;
+
+       if (!(received & IMV_OS_ATTR_PRODUCT_INFORMATION) ||
+               !(received & IMV_OS_ATTR_STRING_VERSION))
+       {
+               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_PRODUCT_INFORMATION);
+               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
+       }
+       if (!(received & IMV_OS_ATTR_NUMERIC_VERSION))
+       {
+               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_NUMERIC_VERSION);
+       }
+       if (!(received & IMV_OS_ATTR_OPERATIONAL_STATUS))
+       {
+               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_OPERATIONAL_STATUS);
+       }
+       if (!(received & IMV_OS_ATTR_FORWARDING_ENABLED))
+       {
+               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_FORWARDING_ENABLED);
+       }
+       if (!(received & IMV_OS_ATTR_FACTORY_DEFAULT_PWD_ENABLED))
+       {
+               attr_cast->add(attr_cast, PEN_IETF,
+                                                                 IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED);
+       }
+       if (!(received & IMV_OS_ATTR_DEVICE_ID))
+       {
+               attr_cast->add(attr_cast, PEN_ITA,  ITA_ATTR_DEVICE_ID);
+       }
+
+       return attr;
+}
+
+/**
  * see section 3.8.8 of TCG TNC IF-IMV Specification 1.3
  */
 TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
                                                           TNC_ConnectionID connection_id)
 {
+       imv_msg_t *out_msg;
        imv_state_t *state;
+       imv_database_t *imv_db;
        imv_os_state_t *os_state;
-       TNC_IMV_Action_Recommendation rec;
-       TNC_IMV_Evaluation_Result eval;
-       TNC_Result result = TNC_RESULT_SUCCESS;
+       imv_os_handshake_state_t handshake_state;
+       pa_tnc_attr_t *attr;
+       TNC_Result result;
+       u_int received;
 
        if (!imv_os)
        {
@@ -554,43 +604,83 @@ TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
        }
        os_state = (imv_os_state_t*)state;
 
-       state->get_recommendation(state, &rec, &eval);
+       handshake_state = os_state->get_handshake_state(os_state);
+       received = os_state->get_received(os_state);
 
-       /*
-        * Don't send an attribute request if an evaluation is available 
-        * or if an attribute request has already been sent
-        */
-       if (eval != TNC_IMV_EVALUATION_RESULT_DONT_KNOW ||
-               os_state->get_attribute_request(os_state))
+       if (handshake_state == IMV_OS_STATE_INIT)
        {
-               return TNC_RESULT_SUCCESS;
-       }
+               if (received != IMV_OS_ATTR_ALL)
+               {
+                       /* send an attribute request for missing attributes */
+                       out_msg = imv_msg_create(imv_os, state, connection_id, imv_id,
+                                                                        TNC_IMCID_ANY, msg_types[0]);
+                       out_msg->add_attribute(out_msg, build_attr_request(received));
+
+                       /* send PA-TNC message with excl flag not set */
+                       result = out_msg->send(out_msg, FALSE);
+                       out_msg->destroy(out_msg);
 
-       if (os_state->get_info(os_state, NULL, NULL, NULL) == NULL)
+                       if (result != TNC_RESULT_SUCCESS)
+                       {
+                               return result;
+                       }
+               }
+       }
+       if (handshake_state < IMV_OS_STATE_POLICY_START)
        {
-               imv_msg_t *out_msg;
-               pa_tnc_attr_t *attr;
-               ietf_attr_attr_request_t *attr_cast;
-
-               out_msg = imv_msg_create(imv_os, state, connection_id, imv_id,
-                                                                TNC_IMCID_ANY, msg_types[0]);
-               attr = ietf_attr_attr_request_create(PEN_IETF,
-                                                                                        IETF_ATTR_PRODUCT_INFORMATION);
-               attr_cast = (ietf_attr_attr_request_t*)attr;
-               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_STRING_VERSION);
-               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_NUMERIC_VERSION);
-               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_OPERATIONAL_STATUS);
-               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_FORWARDING_ENABLED);
-               attr_cast->add(attr_cast, PEN_IETF, IETF_ATTR_FACTORY_DEFAULT_PWD_ENABLED);
-               out_msg->add_attribute(out_msg, attr);
-               os_state->set_attribute_request(os_state, TRUE);
+               if (((received & IMV_OS_ATTR_PRODUCT_INFORMATION) &&
+                        (received & IMV_OS_ATTR_STRING_VERSION)) &&
+                       ((received & IMV_OS_ATTR_DEVICE_ID) ||
+                        (handshake_state == IMV_OS_STATE_ATTR_REQ)))
+               {
+                       imv_db = imv_os->get_database(imv_os);
+                       if (imv_db)
+                       {
+                               /* trigger the policy manager */
+                               imv_db->policy_script(imv_db, state->get_session_id(state),
+                                                                         TRUE);
+                       }
+                       os_state->set_handshake_state(os_state, IMV_OS_STATE_POLICY_START);
 
-               /* send PA-TNC message with excl flag not set */
-               result = out_msg->send(out_msg, FALSE);
-               out_msg->destroy(out_msg);
+                       /* requesting installed packages */
+                       attr = ietf_attr_attr_request_create(PEN_IETF,
+                                                                        IETF_ATTR_INSTALLED_PACKAGES);
+                       out_msg = imv_msg_create(imv_os, state, connection_id, imv_id,
+                                                                        TNC_IMCID_ANY, msg_types[0]);
+                       out_msg->add_attribute(out_msg, attr);
+
+                       /* send PA-TNC message with excl flag set */
+                       result = out_msg->send(out_msg, TRUE);
+                       out_msg->destroy(out_msg);
+
+                       return result;
+               }
+               if (handshake_state == IMV_OS_STATE_ATTR_REQ)
+               {
+                       /**
+                        * Both the IETF Product Information and IETF String Version
+                        * attribute should have been present
+                        */
+                       state->set_recommendation(state,
+                                                               TNC_IMV_ACTION_RECOMMENDATION_NO_RECOMMENDATION,
+                                                               TNC_IMV_EVALUATION_RESULT_ERROR);
+
+                       /* send assessment */
+                       out_msg = imv_msg_create(imv_os, state, connection_id, imv_id,
+                                                                        TNC_IMCID_ANY, msg_types[0]);
+                       result = out_msg->send_assessment(out_msg);
+                       out_msg->destroy(out_msg);
+
+                       if (result != TNC_RESULT_SUCCESS)
+                       {
+                               return result;
+                       }  
+                       return imv_os->provide_recommendation(imv_os, state);
+               }
+               os_state->set_handshake_state(os_state, IMV_OS_STATE_ATTR_REQ);
        }
 
-       return result;
+       return TNC_RESULT_SUCCESS;
 }
 
 /**
index e9661ec..ff6bc12 100644 (file)
@@ -87,6 +87,11 @@ struct private_imv_os_state_t {
        TNC_IMV_Evaluation_Result eval;
 
        /**
+        * IMV OS handshake state
+        */
+       imv_os_handshake_state_t handshake_state;
+
+       /**
         * OS Product Information (concatenation of OS Name and Version)
         */
        char *info;
@@ -152,14 +157,9 @@ struct private_imv_os_state_t {
        int count_ok;
 
        /**
-        * Attribute request sent - mandatory response expected
-        */
-       bool attribute_request;
-
-       /**
-        * OS Installed Package request sent - mandatory response expected
+        * Flags set for received attributes
         */
-       bool package_request;
+       u_int received_flags;
 
        /**
         * OS Settings
@@ -490,6 +490,18 @@ METHOD(imv_state_t, destroy, void,
        free(this);
 }
 
+METHOD(imv_os_state_t, set_handshake_state, void,
+       private_imv_os_state_t *this, imv_os_handshake_state_t new_state)
+{
+       this->handshake_state = new_state;
+}
+
+METHOD(imv_os_state_t, get_handshake_state, imv_os_handshake_state_t,
+       private_imv_os_state_t *this)
+{
+       return this->handshake_state;
+}
+
 METHOD(imv_os_state_t, set_info, void,
        private_imv_os_state_t *this, os_type_t type, chunk_t name, chunk_t version)
 {
@@ -556,28 +568,16 @@ METHOD(imv_os_state_t, get_count, void,
        }
 }
 
-METHOD(imv_os_state_t, set_attribute_request, void,
-       private_imv_os_state_t *this, bool set)
-{
-       this->attribute_request = set;
-}
-
-METHOD(imv_os_state_t, get_attribute_request, bool,
-       private_imv_os_state_t *this)
-{
-       return this->attribute_request;
-}
-
-METHOD(imv_os_state_t, set_package_request, void,
-       private_imv_os_state_t *this, bool set)
+METHOD(imv_os_state_t, set_received, void,
+       private_imv_os_state_t *this, u_int flags)
 {
-       this->package_request = set;
+       this->received_flags |= flags;
 }
 
-METHOD(imv_os_state_t, get_package_request, bool,
+METHOD(imv_os_state_t, get_received, u_int,
        private_imv_os_state_t *this)
 {
-       return this->package_request;
+       return this->received_flags;
 }
 
 METHOD(imv_os_state_t, set_device_id, void,
@@ -659,14 +659,14 @@ imv_state_t *imv_os_state_create(TNC_ConnectionID connection_id)
                                .get_remediation_instructions = _get_remediation_instructions,
                                .destroy = _destroy,
                        },
+                       .set_handshake_state = _set_handshake_state,
+                       .get_handshake_state = _get_handshake_state,
                        .set_info = _set_info,
                        .get_info = _get_info,
                        .set_count = _set_count,
                        .get_count = _get_count,
-                       .set_attribute_request = _set_attribute_request,
-                       .get_attribute_request = _get_attribute_request,
-                       .set_package_request = _set_package_request,
-                       .get_package_request = _get_package_request,
+                       .set_received = _set_received,
+                       .get_received = _get_received,
                        .set_device_id = _set_device_id,
                        .get_device_id = _get_device_id,
                        .set_os_settings = _set_os_settings,
index 1c2adea..038acb6 100644 (file)
 #include <library.h>
 
 typedef struct imv_os_state_t imv_os_state_t;
+typedef enum imv_os_handshake_state_t imv_os_handshake_state_t;
 typedef enum os_settings_t os_settings_t;
 
+/**
+ * IMV OS Handshake States (state machine)
+ */
+enum imv_os_handshake_state_t {
+       IMV_OS_STATE_INIT,
+       IMV_OS_STATE_ATTR_REQ,
+       IMV_OS_STATE_POLICY_START
+};
+
+/**
+ * Flags for detected OS Settings
+ */
 enum os_settings_t {
-       OS_SETTINGS_FWD_ENABLED =         1,
-       OS_SETTINGS_DEFAULT_PWD_ENABLED = 2,
-       OS_SETTINGS_NON_MARKET_APPS =     4
+       OS_SETTINGS_FWD_ENABLED =         (1<<0),
+       OS_SETTINGS_DEFAULT_PWD_ENABLED = (1<<1),
+       OS_SETTINGS_NON_MARKET_APPS =     (1<<2)
 };
 
 /**
@@ -48,6 +61,21 @@ struct imv_os_state_t {
        imv_state_t interface;
 
        /**
+        * Set state of the handshake
+        *
+        * @param new_state                     the handshake state of IMV
+        */
+       void (*set_handshake_state)(imv_os_state_t *this,
+                                                               imv_os_handshake_state_t new_state);
+
+       /**
+        * Get state of the handshake
+        *
+        * @return                                      the handshake state of IMV
+        */
+       imv_os_handshake_state_t (*get_handshake_state)(imv_os_state_t *this);
+
+       /**
         * Set OS Product Information
         *
         * @param type                  OS type (enumerated)
@@ -91,32 +119,18 @@ struct imv_os_state_t {
                                          int *count_blacklist, int *count_ok);
 
        /**
-        * Set/reset attribute request status
-        *
-        * @param set                   TRUE to set, FALSE to clear
-        */
-       void (*set_attribute_request)(imv_os_state_t *this, bool set);
-
-       /**
-        * Get attribute request status
-        *
-        * @return                              TRUE if set, FALSE if unset
-        */
-       bool (*get_attribute_request)(imv_os_state_t *this);
-
-       /**
-        * Set/reset OS Installed Packages request status
+        * Set flags for received attributes
         *
-        * @param set                   TRUE to set, FALSE to clear
+        * @param flags                 Flags to be set
         */
-       void (*set_package_request)(imv_os_state_t *this, bool set);
+       void (*set_received)(imv_os_state_t *this, u_int flags);
 
        /**
-        * Get OS Installed Packages request status
+        * Get flags set for received attributes
         *
-        * @return                              TRUE if set, FALSE if unset
+        * @return                              Flags set for received attributes
         */
-       bool (*get_package_request)(imv_os_state_t *this);
+       u_int (*get_received)(imv_os_state_t *this);
 
        /**
         * Set device ID