implemented IETF Operational Status attribute
authorAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 13 Oct 2012 18:34:50 +0000 (20:34 +0200)
committerAndreas Steffen <andreas.steffen@strongswan.org>
Sat, 13 Oct 2012 18:34:50 +0000 (20:34 +0200)
src/libimcv/Makefile.am
src/libimcv/ietf/ietf_attr.c
src/libimcv/ietf/ietf_attr_op_status.c [new file with mode: 0644]
src/libimcv/ietf/ietf_attr_op_status.h [new file with mode: 0644]
src/libimcv/os_info/os_info.c
src/libimcv/os_info/os_info.h
src/libimcv/plugins/imc_os/imc_os.c
src/libimcv/plugins/imv_os/imv_os.c

index 249d5ae..a331870 100644 (file)
@@ -15,6 +15,7 @@ libimcv_la_SOURCES = \
        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_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 \
index 8aa05c1..f183e06 100644 (file)
@@ -19,6 +19,7 @@
 #include "ietf/ietf_attr_fwd_enabled.h"
 #include "ietf/ietf_attr_default_pwd_enabled.h"
 #include "ietf/ietf_attr_installed_packages.h"
+#include "ietf/ietf_attr_op_status.h"
 #include "ietf/ietf_attr_pa_tnc_error.h"
 #include "ietf/ietf_attr_port_filter.h"
 #include "ietf/ietf_attr_product_info.h"
@@ -54,6 +55,8 @@ pa_tnc_attr_t* ietf_attr_create_from_data(u_int32_t type, chunk_t value)
                        return ietf_attr_product_info_create_from_data(value);
                case IETF_ATTR_STRING_VERSION:
                        return ietf_attr_string_version_create_from_data(value);
+               case IETF_ATTR_OPERATIONAL_STATUS:
+                       return ietf_attr_op_status_create_from_data(value);
                case IETF_ATTR_PORT_FILTER:
                        return ietf_attr_port_filter_create_from_data(value);
                case IETF_ATTR_INSTALLED_PACKAGES:
@@ -68,7 +71,6 @@ pa_tnc_attr_t* ietf_attr_create_from_data(u_int32_t type, chunk_t value)
                        return ietf_attr_default_pwd_enabled_create_from_data(value);
                case IETF_ATTR_TESTING:
                case IETF_ATTR_NUMERIC_VERSION:
-               case IETF_ATTR_OPERATIONAL_STATUS:
                case IETF_ATTR_REMEDIATION_INSTRUCTIONS:
                case IETF_ATTR_RESERVED:
                default:
diff --git a/src/libimcv/ietf/ietf_attr_op_status.c b/src/libimcv/ietf/ietf_attr_op_status.c
new file mode 100644 (file)
index 0000000..9f3af09
--- /dev/null
@@ -0,0 +1,313 @@
+/*
+ * Copyright (C) 2012 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 "ietf_attr_op_status.h"
+
+#include <pa_tnc/pa_tnc_msg.h>
+#include <bio/bio_writer.h>
+#include <bio/bio_reader.h>
+#include <debug.h>
+
+#include <time.h>
+
+typedef struct private_ietf_attr_op_status_t private_ietf_attr_op_status_t;
+
+ENUM(op_status_names, OP_STATUS_UNKNOWN, OP_STATUS_OPERATIONAL,
+       "unknown",
+       "not installed",
+       "installed",
+       "operational"
+);
+
+ENUM(op_result_names, OP_RESULT_UNKNOWN, OP_RESULT_UNSUCCESSFUL,
+       "unknown",
+       "successful",
+       "errored",
+       "unsuccessful"
+);
+
+/**
+ * PA-TNC Operational Status type  (see section 4.2.5 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
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |    Status     |     Result    |         Reserved              |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                          Last Use                             |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                     Last Use (continued)                      |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                     Last Use (continued)                      |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                     Last Use (continued)                      |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ *  |                     Last Use (continued)                      |
+ *  +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+
+#define OP_STATUS_SIZE         24
+
+/**
+ * Private data of an ietf_attr_op_status_t object.
+ */
+struct private_ietf_attr_op_status_t {
+
+       /**
+        * Public members of ietf_attr_op_status_t
+        */
+       ietf_attr_op_status_t public;
+
+       /**
+        * Vendor-specific attribute type
+        */
+       pen_type_t type;
+
+       /**
+        * Attribute value
+        */
+       chunk_t value;
+
+       /**
+        * Noskip flag
+        */
+       bool noskip_flag;
+
+       /**
+        * Status
+        */
+       u_int8_t status;
+
+       /**
+        * Result
+        */
+       u_int8_t result;
+
+       /**
+        * Last Use
+        */
+       time_t last_use;
+
+       /**
+        * Reference count
+        */
+       refcount_t ref;
+};
+
+METHOD(pa_tnc_attr_t, get_type, pen_type_t,
+       private_ietf_attr_op_status_t *this)
+{
+       return this->type;
+}
+
+METHOD(pa_tnc_attr_t, get_value, chunk_t,
+       private_ietf_attr_op_status_t *this)
+{
+       return this->value;
+}
+
+METHOD(pa_tnc_attr_t, get_noskip_flag, bool,
+       private_ietf_attr_op_status_t *this)
+{
+       return this->noskip_flag;
+}
+
+METHOD(pa_tnc_attr_t, set_noskip_flag,void,
+       private_ietf_attr_op_status_t *this, bool noskip)
+{
+       this->noskip_flag = noskip;
+}
+
+METHOD(pa_tnc_attr_t, build, void,
+       private_ietf_attr_op_status_t *this)
+{
+       bio_writer_t *writer;
+       char last_use[24];
+       struct tm t;
+
+       if (this->value.ptr)
+       {
+               return;
+       }
+
+       /* Conversion from time_t to RFC 3339 ASCII string */
+       gmtime_r(&this->last_use, &t);
+       snprintf(last_use, 21, "%04d-%02d-%02dT%02d:%02d:%02dZ", 1900 + t.tm_year,
+                        t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
+
+       writer = bio_writer_create(OP_STATUS_SIZE);
+       writer->write_uint8 (writer, this->status);
+       writer->write_uint8 (writer, this->result);
+       writer->write_uint16(writer, 0x0000);
+       writer->write_data  (writer, chunk_create(last_use, 20));
+
+       this->value = chunk_clone(writer->get_buf(writer));
+       writer->destroy(writer);
+}
+
+METHOD(pa_tnc_attr_t, process, status_t,
+       private_ietf_attr_op_status_t *this, u_int32_t *offset)
+{
+       bio_reader_t *reader;
+       chunk_t last_use;
+       u_int16_t reserved;
+       struct tm t;
+       int nr;
+
+       *offset = 0;
+
+       if (this->value.len != OP_STATUS_SIZE)
+       {
+               DBG1(DBG_TNC, "incorrect size for IETF operational status");
+               return FAILED;
+       }
+       reader = bio_reader_create(this->value);
+       reader->read_uint8 (reader, &this->status);
+       reader->read_uint8 (reader, &this->result);
+       reader->read_uint16(reader, &reserved);
+       reader->read_data  (reader, 20, &last_use);
+       reader->destroy(reader);
+
+       if (this->status > OP_STATUS_ROOF)
+       {
+               DBG1(DBG_TNC, "invalid status value %c for IETF operational status",
+                                          this->status);
+               return FAILED;
+       }
+
+       *offset = 1;
+
+       if (this->result > OP_RESULT_ROOF)
+       {
+               DBG1(DBG_TNC, "invalid result value %c for IETF operational status",
+                                          this->result);
+               return FAILED;
+       }
+
+       *offset = 4;
+
+       /* Conversion from RFC 3339 ASCII string to time_t */
+       if (sscanf(last_use.ptr, "%4d-%2d-%2dT%2d:%2d:%2dZ", &t.tm_year, &t.tm_mon,
+                          &t.tm_mday, &t.tm_hour, &t.tm_min, &t.tm_sec) != 6)
+       {
+               DBG1(DBG_TNC, "invalid last_use time format in IETF operational status");
+               return FAILED;
+       }
+       t.tm_year -= 1900;
+       t.tm_mon -= 1;
+       t.tm_isdst = 0;
+       this->last_use = mktime(&t) - timezone;
+
+       return SUCCESS;
+}
+
+METHOD(pa_tnc_attr_t, get_ref, pa_tnc_attr_t*,
+       private_ietf_attr_op_status_t *this)
+{
+       ref_get(&this->ref);
+       return &this->public.pa_tnc_attribute;
+}
+
+METHOD(pa_tnc_attr_t, destroy, void,
+       private_ietf_attr_op_status_t *this)
+{
+       if (ref_put(&this->ref))
+       {
+               free(this->value.ptr);
+               free(this);
+       }
+}
+
+METHOD(ietf_attr_op_status_t, get_status, u_int8_t,
+       private_ietf_attr_op_status_t *this)
+{
+       return this->status;
+}
+
+METHOD(ietf_attr_op_status_t, get_result, u_int8_t,
+       private_ietf_attr_op_status_t *this)
+{
+       return this->result;
+}
+
+METHOD(ietf_attr_op_status_t, get_last_use, time_t,
+       private_ietf_attr_op_status_t *this)
+{
+       return this->last_use;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *ietf_attr_op_status_create(u_int8_t status, u_int8_t result,
+                                                                                 time_t last_use)
+{
+       private_ietf_attr_op_status_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,
+                       },
+                       .get_status = _get_status,
+                       .get_result = _get_result,
+                       .get_last_use = _get_last_use,
+               },
+               .type = { PEN_IETF, IETF_ATTR_OPERATIONAL_STATUS },
+               .status = status,
+               .result = result,
+               .last_use = last_use,
+               .ref = 1,
+       );
+
+       return &this->public.pa_tnc_attribute;
+}
+
+/**
+ * Described in header.
+ */
+pa_tnc_attr_t *ietf_attr_op_status_create_from_data(chunk_t data)
+{
+       private_ietf_attr_op_status_t *this;
+
+       INIT(this,
+               .public = {
+                       .pa_tnc_attribute = {
+                               .get_type = _get_type,
+                               .get_value = _get_value,
+                               .build = _build,
+                               .process = _process,
+                               .get_ref = _get_ref,
+                               .destroy = _destroy,
+                       },
+                       .get_status = _get_status,
+                       .get_result = _get_result,
+                       .get_last_use = _get_last_use,
+               },
+               .type = { PEN_IETF, IETF_ATTR_OPERATIONAL_STATUS },
+               .value = chunk_clone(data),
+               .ref = 1,
+       );
+
+       return &this->public.pa_tnc_attribute;
+}
+
diff --git a/src/libimcv/ietf/ietf_attr_op_status.h b/src/libimcv/ietf/ietf_attr_op_status.h
new file mode 100644 (file)
index 0000000..2e14148
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2012 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 ietf_attr_op_statust ietf_attr_op_status
+ * @{ @ingroup ietf
+ */
+
+#ifndef IETF_ATTR_OP_STATUS_H_
+#define IETF_ATTR_OP_STATUS_H_
+
+typedef struct ietf_attr_op_status_t ietf_attr_op_status_t;
+typedef enum op_status_t op_status_t;
+typedef enum op_result_t op_result_t;
+
+#include "ietf_attr.h"
+#include "pa_tnc/pa_tnc_attr.h"
+
+/**
+ * Operational Status type
+ */
+enum op_status_t {
+       OP_STATUS_UNKNOWN =       0,
+       OP_STATUS_NOT_INSTALLED = 1,
+       OP_STATUS_INSTALLED =     2,
+       OP_STATUS_OPERATIONAL =   3,
+       OP_STATUS_ROOF =          3
+};
+
+extern enum_name_t *op_status_names;
+/**
+ * Operational Result type
+ */
+enum op_result_t {
+       OP_RESULT_UNKNOWN =      0,
+       OP_RESULT_SUCCESSFUL =   1,
+       OP_RESULT_ERRORED =      2,
+       OP_RESULT_UNSUCCESSFUL = 3,
+       OP_RESULT_ROOF         = 3
+};
+
+extern enum_name_t *op_result_names;
+
+/**
+ * Class implementing the IETF PA-TNC Operational Status attribute.
+ *
+ */
+struct ietf_attr_op_status_t {
+
+       /**
+        * Public PA-TNC attribute interface
+        */
+       pa_tnc_attr_t pa_tnc_attribute;
+
+       /**
+        * Gets the Operational Status
+        *
+        * @return                              Operational Status
+        */
+       u_int8_t (*get_status)(ietf_attr_op_status_t *this);
+
+       /**
+        * Gets the Operational Result
+        *
+        * @return                              Operational Result
+        */
+       u_int8_t (*get_result)(ietf_attr_op_status_t *this);
+
+       /**
+        * Gets the time of last use
+        *
+        * @return                              Time of last use
+        */
+       time_t (*get_last_use)(ietf_attr_op_status_t *this);
+};
+
+/**
+ * Creates an ietf_attr_op_status_t object
+ *
+ * @param status                       Operational Status
+ * @param result                       Operational Result
+ * @param last_use                     Time of last use 
+ */
+pa_tnc_attr_t* ietf_attr_op_status_create(u_int8_t status, u_int8_t result,
+                                                                                 time_t last_use);
+
+/**
+ * Creates an ietf_attr_op_status_t object from received data
+ *
+ * @param value                                unparsed attribute value
+ */
+pa_tnc_attr_t* ietf_attr_op_status_create_from_data(chunk_t value);
+
+#endif /** IETF_ATTR_OP_STATUS_H_ @}*/
index 25d6467..fd7d6ce 100644 (file)
@@ -95,20 +95,44 @@ METHOD(os_info_t, get_fwd_status, os_fwd_status_t,
                {
                        DBG1(DBG_IMC, "could not read from \"%s\"", ip_forward);
                }
+               fclose(file);
        }
        else
        {
                DBG1(DBG_IMC, "failed to open \"%s\"", ip_forward);
        }
-       fclose(file);
 
        return fwd_status;
 }
 
+METHOD(os_info_t, get_uptime, time_t,
+       private_os_info_t *this)
+{
+       const char proc_uptime[] = "/proc/uptime";
+       FILE *file;
+       time_t uptime;
+
+       file = fopen(proc_uptime, "r");
+       if (!file)
+       {
+               DBG1(DBG_IMC, "failed to open \"%s\"", proc_uptime);
+               return 0;       
+       }
+       if (fscanf(file, "%u", &uptime) != 1)
+       {
+               DBG1(DBG_IMC, "failed to read file \"%s\"", proc_uptime);
+               uptime = 0;
+       }               
+       fclose(file);
+
+       return uptime;
+}
+
 METHOD(os_info_t, create_package_enumerator, enumerator_t*,
        private_os_info_t *this)
 {
        /* TODO */
+
        return NULL;
 }
 
@@ -345,6 +369,7 @@ os_info_t *os_info_create(void)
                        .get_name = _get_name,
                        .get_version = _get_version,
                        .get_fwd_status = _get_fwd_status,
+                       .get_uptime = _get_uptime,
                        .create_package_enumerator = _create_package_enumerator,
                        .destroy = _destroy,
                },
index 1044263..f39d8ae 100644 (file)
@@ -26,6 +26,8 @@ typedef enum os_fwd_status_t os_fwd_status_t;
 
 #include <library.h>
 
+#include <time.h>
+
 /**
  * Defines the IPv4 forwarding status
  */
@@ -64,6 +66,13 @@ struct os_info_t {
        os_fwd_status_t (*get_fwd_status)(os_info_t *this);
 
        /**
+        * Get the OS uptime in seconds
+        *
+        * @return                                      OS uptime
+        */
+       time_t (*get_uptime)(os_info_t *this);
+
+       /**
         * Enumerates over all installed packages
         *
         * @return                              return package enumerator
index cbadc9c..beaec2f 100644 (file)
@@ -23,6 +23,7 @@
 #include <ietf/ietf_attr_default_pwd_enabled.h>
 #include <ietf/ietf_attr_fwd_enabled.h>
 #include <ietf/ietf_attr_installed_packages.h>
+#include <ietf/ietf_attr_op_status.h>
 #include <ietf/ietf_attr_pa_tnc_error.h>
 #include <ietf/ietf_attr_product_info.h>
 #include <ietf/ietf_attr_string_version.h>
@@ -140,6 +141,25 @@ static void add_string_version(linked_list_t *attr_list)
 }
 
 /**
+ * Add IETF Operational Status attribute to the send queue
+ */
+static void add_op_status(linked_list_t *attr_list)
+{
+       pa_tnc_attr_t *attr;
+       time_t uptime, last_boot;
+
+       uptime = os->get_uptime(os);
+       last_boot = uptime ? time(NULL) - uptime : UNDEFINED_TIME;
+       if (last_boot != UNDEFINED_TIME)
+       {
+               DBG1(DBG_IMC, "last boot: %T, %u s ago", &last_boot, TRUE, uptime);
+       }
+       attr = ietf_attr_op_status_create(OP_STATUS_OPERATIONAL,
+                                                                         OP_RESULT_SUCCESSFUL, last_boot);
+       attr_list->insert_last(attr_list, attr);
+}
+
+/**
  * Add IETF Forwarding Enabled attribute to the send queue
  */
 static void add_fwd_enabled(linked_list_t *attr_list)
@@ -207,6 +227,7 @@ TNC_Result TNC_IMC_BeginHandshake(TNC_IMCID imc_id,
                attr_list = linked_list_create();
                add_product_info(attr_list);
                add_string_version(attr_list);
+               add_op_status(attr_list);
                add_fwd_enabled(attr_list);
                add_default_pwd_enabled(attr_list);
                result = imc_os->send_message(imc_os, connection_id, FALSE, 0,
@@ -296,6 +317,9 @@ static TNC_Result receive_message(TNC_IMCID imc_id,
                                        case IETF_ATTR_STRING_VERSION:
                                                add_string_version(attr_list);
                                                break;
+                                       case IETF_ATTR_OPERATIONAL_STATUS:
+                                               add_op_status(attr_list);
+                                               break;
                                        case IETF_ATTR_FORWARDING_ENABLED:
                                                add_fwd_enabled(attr_list);
                                                break;
index 655d1bf..b085b85 100644 (file)
@@ -22,6 +22,7 @@
 #include <ietf/ietf_attr_default_pwd_enabled.h>
 #include <ietf/ietf_attr_fwd_enabled.h>
 #include <ietf/ietf_attr_installed_packages.h>
+#include <ietf/ietf_attr_op_status.h>
 #include <ietf/ietf_attr_pa_tnc_error.h>
 #include <ietf/ietf_attr_product_info.h>
 #include <ietf/ietf_attr_string_version.h>
@@ -181,6 +182,22 @@ static TNC_Result receive_message(TNC_IMVID imv_id,
                                }
                                break;
                        }
+                       case IETF_ATTR_OPERATIONAL_STATUS:
+                       {
+                               ietf_attr_op_status_t *attr_cast;
+                               op_status_t op_status;
+                               op_result_t op_result;
+                               time_t last_boot;
+
+                               attr_cast = (ietf_attr_op_status_t*)attr;
+                               op_status = attr_cast->get_status(attr_cast);
+                               op_result = attr_cast->get_result(attr_cast);
+                               last_boot = attr_cast->get_last_use(attr_cast);
+                               DBG1(DBG_IMV, "operational status: %N, result: %N",
+                                        op_status_names, op_status, op_result_names, op_result);
+                               DBG1(DBG_IMV, "last boot: %T", &last_boot, TRUE);
+                               break;
+                       }
                        case IETF_ATTR_FORWARDING_ENABLED:
                        {
                                ietf_attr_fwd_enabled_t *attr_cast;
@@ -364,6 +381,7 @@ TNC_Result TNC_IMV_BatchEnding(TNC_IMVID imv_id,
                                                                                         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_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);
                attr_list->insert_last(attr_list, attr);