From: Andreas Steffen Date: Sun, 28 Apr 2013 20:47:09 +0000 (+0200) Subject: implemented IMV session control X-Git-Tag: 5.1.0dr1~78 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b8db66de15ce0234592564036cccd7de358cd108;p=thirdparty%2Fstrongswan.git implemented IMV session control --- diff --git a/src/libimcv/Makefile.am b/src/libimcv/Makefile.am index 51a7be046f..470f30974f 100644 --- a/src/libimcv/Makefile.am +++ b/src/libimcv/Makefile.am @@ -10,6 +10,7 @@ libimcv_la_SOURCES = \ 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_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 \ diff --git a/src/libimcv/imv/imv_agent.c b/src/libimcv/imv/imv_agent.c index 879a0103af..fdc76abf94 100644 --- a/src/libimcv/imv/imv_agent.c +++ b/src/libimcv/imv/imv_agent.c @@ -62,6 +62,11 @@ struct private_imv_agent_t { */ linked_list_t *additional_ids; + /** + * IMV database + */ + imv_database_t *db; + /** * list of TNCS connection entries */ @@ -402,11 +407,14 @@ METHOD(imv_agent_t, create_state, TNC_Result, { TNC_ConnectionID conn_id; char *tnccs_p = NULL, *tnccs_v = NULL, *t_p = NULL, *t_v = NULL; - bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE; + bool has_long = FALSE, has_excl = FALSE, has_soh = FALSE, first = TRUE; linked_list_t *ar_identities; enumerator_t *enumerator; tncif_identity_t *tnc_id; + int session_id; u_int32_t max_msg_len; + u_int32_t ar_id_type = TNC_ID_UNKNOWN; + chunk_t ar_id_value = chunk_empty; conn_id = state->get_connection_id(state); if (find_connection(this, conn_id)) @@ -462,10 +470,31 @@ METHOD(imv_agent_t, create_state, TNC_Result, TNC_Subject_names, tcg_subject_type, id_value.len, id_value.ptr, TNC_Authentication_names, tcg_auth_type); - state->set_ar_id(state, tcg_id_type, id_value); + + if (first) + { + ar_id_type = tcg_id_type; + ar_id_value = id_value; + state->set_ar_id(state, ar_id_type, ar_id_value); + first = FALSE; + } } enumerator->destroy(enumerator); + if (this->db) + { + session_id = this->db->get_session_id(this->db, conn_id, + ar_id_type, ar_id_value); + if (session_id) + { + DBG2(DBG_IMV, " assigned session ID %d", session_id); + state->set_session_id(state, session_id); + } + else + { + DBG1(DBG_IMV, " no session ID assigned"); + } + } ar_identities->destroy_offset(ar_identities, offsetof(tncif_identity_t, destroy)); free(tnccs_p); @@ -553,6 +582,12 @@ METHOD(imv_agent_t, get_state, bool, return TRUE; } +METHOD(imv_agent_t, get_database, imv_database_t*, + private_imv_agent_t *this) +{ + return this->db; +} + METHOD(imv_agent_t, get_name, const char*, private_imv_agent_t *this) { @@ -754,6 +789,7 @@ METHOD(imv_agent_t, destroy, void, private_imv_agent_t *this) { DBG1(DBG_IMV, "IMV %u \"%s\" terminated", this->id, this->name); + DESTROY_IF(this->db); this->additional_ids->destroy(this->additional_ids); this->connections->destroy_offset(this->connections, offsetof(imv_state_t, destroy)); @@ -772,6 +808,7 @@ imv_agent_t *imv_agent_create(const char *name, TNC_IMVID id, TNC_Version *actual_version) { private_imv_agent_t *this; + char *uri; /* initialize or increase the reference count */ if (!libimcv_init()) @@ -786,6 +823,7 @@ imv_agent_t *imv_agent_create(const char *name, .delete_state = _delete_state, .change_state = _change_state, .get_state = _get_state, + .get_database = _get_database, .get_name = _get_name, .get_id = _get_id, .reserve_additional_ids = _reserve_additional_ids, @@ -804,6 +842,13 @@ imv_agent_t *imv_agent_create(const char *name, .connection_lock = rwlock_create(RWLOCK_TYPE_DEFAULT), ); + /* attach IMV database */ + uri = lib->settings->get_str(lib->settings, "libimcv.database", NULL); + if (uri) + { + this->db = imv_database_create(uri); + } + *actual_version = TNC_IFIMV_VERSION_1; DBG1(DBG_IMV, "IMV %u \"%s\" initialized", this->id, this->name); diff --git a/src/libimcv/imv/imv_agent.h b/src/libimcv/imv/imv_agent.h index 6f3d2b4b70..5c78418863 100644 --- a/src/libimcv/imv/imv_agent.h +++ b/src/libimcv/imv/imv_agent.h @@ -23,6 +23,7 @@ #define IMV_AGENT_H_ #include "imv_state.h" +#include "imv_database.h" #include "pa_tnc/pa_tnc_msg.h" #include @@ -137,6 +138,13 @@ struct imv_agent_t { bool (*get_state)(imv_agent_t *this, TNC_ConnectionID connection_id, imv_state_t **state); + /** + * Get IMV database + * + * @return IMV database if it exists, NULL otherwise + */ + imv_database_t* (*get_database)(imv_agent_t *this); + /** * Get IMV name * diff --git a/src/libimcv/imv/imv_database.c b/src/libimcv/imv/imv_database.c new file mode 100644 index 0000000000..1402e2e81f --- /dev/null +++ b/src/libimcv/imv/imv_database.c @@ -0,0 +1,209 @@ +/* + * 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 . + * + * 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 "imv_database.h" + +#include + +#include +#include + +typedef struct private_imv_database_t private_imv_database_t; + +#define SESSION_TIME_DELTA_MAX 2 /* seconds */ + +/** + * Private data of a imv_database_t object. + * + */ +struct private_imv_database_t { + + /** + * Public imv_database_t interface. + */ + imv_database_t public; + + /** + * database instance + */ + database_t *db; + +}; + +METHOD(imv_database_t, get_session_id, int, + private_imv_database_t *this, TNC_ConnectionID id, u_int32_t ar_id_type, + chunk_t ar_id_value) +{ + enumerator_t *e; + int ar_id = 0, session_id = 0; + u_int created; + time_t now; + + /* get most recent session for a given connection ID if available */ + e = this->db->query(this->db, + "SELECT id, time FROM sessions WHERE connection = ? " + "ORDER BY time DESC", DB_INT, id, DB_INT, DB_UINT); + if (e) + { + e->enumerate(e, &session_id, &created); + e->destroy(e); + } + + /* get current time */ + now = time(NULL); + + /* check if a new session has already been created by another IMV */ + if (session_id && (now - created) <= SESSION_TIME_DELTA_MAX) + { + return session_id; + } + + if (ar_id_value.len) + { + /* get primary key of AR identity if it exists */ + e = this->db->query(this->db, + "SELECT id FROM identities WHERE type = ? AND value = ?", + DB_INT, ar_id_type, DB_BLOB, ar_id_value, DB_INT); + if (e) + { + e->enumerate(e, &ar_id); + e->destroy(e); + } + + /* if AR identity has not been found - register it */ + if (!ar_id) + { + this->db->execute(this->db, &ar_id, + "INSERT INTO identities (type, value) VALUES (?, ?)", + DB_INT, ar_id_type, DB_BLOB, ar_id_value); + } + } + + /* create a new session ID */ + this->db->execute(this->db, &session_id, + "INSERT INTO sessions (time, connection, identity) " + "VALUES (?, ?, ?)", DB_UINT, now, DB_INT, id, DB_INT, ar_id); + + return session_id; +} + +METHOD(imv_database_t, add_product, int, + private_imv_database_t *this, int session_id, char *product) +{ + enumerator_t *e; + int pid = 0; + + /* get primary key of product info string if it exists */ + e = this->db->query(this->db, + "SELECT id FROM products WHERE name = ?", DB_TEXT, product, DB_INT); + if (e) + { + e->enumerate(e, &pid); + e->destroy(e); + } + + /* if product info string has not been found - register it */ + if (!pid) + { + this->db->execute(this->db, &pid, + "INSERT INTO products (name) VALUES (?)", DB_TEXT, product); + } + + /* add product reference to session */ + if (pid) + { + this->db->execute(this->db, NULL, + "UPDATE sessions SET product = ? WHERE id = ?", + DB_INT, pid, DB_INT, session_id); + } + + return pid; +} + +METHOD(imv_database_t, add_device, int, + private_imv_database_t *this, int session_id, chunk_t device) +{ + enumerator_t *e; + int did = 0; + + /* get primary key of device identification if it exists */ + e = this->db->query(this->db, + "SELECT id FROM devices WHERE value = ?", DB_BLOB, device, DB_INT); + if (e) + { + e->enumerate(e, &did); + e->destroy(e); + } + + /* if device identification has not been found - register it */ + if (!did) + { + this->db->execute(this->db, &did, + "INSERT INTO devices (value) VALUES (?)", DB_BLOB, device); + } + + /* add device reference to session */ + if (did) + { + this->db->execute(this->db, NULL, + "UPDATE sessions SET device = ? WHERE id = ?", + DB_INT, did, DB_INT, session_id); + } + + return did; +} + +METHOD(imv_database_t, get_database, database_t*, + private_imv_database_t *this) +{ + return this->db; +} + +METHOD(imv_database_t, destroy, void, + private_imv_database_t *this) +{ + this->db->destroy(this->db); + free(this); +} + +/** + * See header + */ +imv_database_t *imv_database_create(char *uri) +{ + private_imv_database_t *this; + + INIT(this, + .public = { + .get_session_id = _get_session_id, + .add_product = _add_product, + .add_device = _add_device, + .get_database = _get_database, + .destroy = _destroy, + }, + .db = lib->db->create(lib->db, uri), + ); + + if (!this->db) + { + DBG1(DBG_IMV, + "failed to connect to IMV database '%s'", uri); + free(this); + return NULL; + } + + return &this->public; +} + diff --git a/src/libimcv/imv/imv_database.h b/src/libimcv/imv/imv_database.h new file mode 100644 index 0000000000..3b3cbd6a93 --- /dev/null +++ b/src/libimcv/imv/imv_database.h @@ -0,0 +1,85 @@ +/* + * 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 . + * + * 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 imv_database_t imv_database + * @{ @ingroup libimcv_imv + */ + +#ifndef IMV_DATABASE_H_ +#define IMV_DATABASE_H_ + +#include + +#include + +typedef struct imv_database_t imv_database_t; + +/** + * IMV database interface + */ +struct imv_database_t { + + /** + * Register or get a unique session ID using the TNCCS connection ID + * + * @param id TNCCS Connection ID + * @param ar_id_type Access Requestor identity type + * @param ar_id_value Access Requestor identity value + * @return Session ID or 0 if not available + */ + int (*get_session_id)(imv_database_t *this, TNC_ConnectionID id, + u_int32_t ar_id_type, chunk_t ar_id_value); + + /** + * Add product information string to a session + * + * @param session_id Session ID + * @param product Product information string + * @return Product ID or 0 if not available + */ + int (*add_product)(imv_database_t *this, int session_id, char *product); + + /** + * Add device identification to a session + * + * @param session_id Sessiion ID + * @param device Device identification + * @return Device ID or 0 if not available + */ + int (*add_device)(imv_database_t *this, int session_id, chunk_t device); + + /** + * Get database handle + * + * @return Database handle + */ + database_t* (*get_database)(imv_database_t *this); + + /** + * Destroys an imv_database_t object + */ + void (*destroy)(imv_database_t *this); +}; + +/** + * Create an imv_database_t instance + * + * @param uri database uri + */ +imv_database_t* imv_database_create(char *uri); + +#endif /** IMV_DATABASE_H_ @}*/ diff --git a/src/libimcv/imv/imv_state.h b/src/libimcv/imv/imv_state.h index d1a87d2d72..aa0104ccc1 100644 --- a/src/libimcv/imv/imv_state.h +++ b/src/libimcv/imv/imv_state.h @@ -94,6 +94,20 @@ struct imv_state_t { */ chunk_t (*get_ar_id)(imv_state_t *this, u_int32_t *id_type); + /** + * Set unique session ID + * + * @param session_id Unique session ID + */ + void (*set_session_id)(imv_state_t *this, int session_id); + + /** + * Get unique session_id + * + * @return Unique session ID + */ + int (*get_session_id)(imv_state_t *this); + /** * Change the connection state * diff --git a/src/libimcv/plugins/imv_os/imv_os.c b/src/libimcv/plugins/imv_os/imv_os.c index f1cb74e50b..48af9c5a1e 100644 --- a/src/libimcv/plugins/imv_os/imv_os.c +++ b/src/libimcv/plugins/imv_os/imv_os.c @@ -65,8 +65,6 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, TNC_Version max_version, TNC_Version *actual_version) { - char *uri; - if (imv_os) { DBG1(DBG_IMV, "IMV \"%s\" has already been initialized", imv_name); @@ -84,13 +82,8 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, return TNC_RESULT_NO_COMMON_VERSION; } - /* attach OS database */ - uri = lib->settings->get_str(lib->settings, - "libimcv.plugins.imv-os.database", NULL); - if (uri) - { - os_db = imv_os_database_create(uri); - } + /* attach OS database co-located with IMV database */ + os_db = imv_os_database_create(imv_os->get_database(imv_os)); return TNC_RESULT_SUCCESS; } @@ -289,7 +282,9 @@ 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 did; char *name; chunk_t value; @@ -306,8 +301,13 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg) else if ((streq(name, android_id_str) || streq(name, machine_id_str)) && os_db) { - os_state->set_device_id(os_state, - os_db->get_device_id(os_db, value)); + imv_db = imv_os->get_database(imv_os); + if (imv_db) + { + did = imv_db->add_device(imv_db, + state->get_session_id(state), value); + os_state->set_device_id(os_state, did); + } } DBG1(DBG_IMV, "setting '%s'\n %.*s", name, value.len, value.ptr); @@ -332,11 +332,19 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg) { os_type_t os_type; ita_attr_get_settings_t *attr_cast; + imv_database_t *imv_db; /* set the OS type, name and version */ os_type = os_type_from_name(os_name); os_state->set_info(os_state,os_type, os_name, os_version); + imv_db = imv_os->get_database(imv_os); + if (imv_db) + { + 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, @@ -376,10 +384,8 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg) !os_state->get_angel_count(os_state) && os_state->get_info(os_state, NULL, NULL, NULL)) { - int device_id, count, count_update, count_blacklist, count_ok; + int count, count_update, count_blacklist, count_ok; u_int os_settings; - u_int32_t id_type; - chunk_t id_value; os_settings = os_state->get_os_settings(os_state); os_state->get_count(os_state, &count, &count_update, &count_blacklist, @@ -389,13 +395,10 @@ static TNC_Result receive_message(imv_state_t *state, imv_msg_t *in_msg) count_ok, count - count_update - count_blacklist - count_ok); /* Store device information in database */ - device_id = os_state->get_device_id(os_state); - id_value = state->get_ar_id(state, &id_type); - if (os_db && device_id) + if (os_db) { - os_db->set_device_info(os_db, device_id, id_type, id_value, - os_state->get_info(os_state, NULL, NULL, NULL), - count, count_update, count_blacklist, os_settings); + os_db->set_device_info(os_db, state->get_session_id(state), + count, count_update, count_blacklist, os_settings); } if (count_update || count_blacklist || os_settings) @@ -589,6 +592,7 @@ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) return TNC_RESULT_NOT_INITIALIZED; } DESTROY_IF(os_db); + os_db = NULL; imv_os->destroy(imv_os); imv_os = NULL; diff --git a/src/libimcv/plugins/imv_os/imv_os_database.c b/src/libimcv/plugins/imv_os/imv_os_database.c index a7f9f2eed7..6f7b29b6d9 100644 --- a/src/libimcv/plugins/imv_os/imv_os_database.c +++ b/src/libimcv/plugins/imv_os/imv_os_database.c @@ -187,148 +187,46 @@ METHOD(imv_os_database_t, check_packages, status_t, return status; } -METHOD(imv_os_database_t, get_device_id, int, - private_imv_os_database_t *this, chunk_t value) -{ - enumerator_t *e; - int id; - - /* get primary key of device ID */ - e = this->db->query(this->db, "SELECT id FROM devices WHERE value = ?", - DB_BLOB, value, DB_INT); - if (!e) - { - return 0; - } - if (e->enumerate(e, &id)) - { - /* device ID already exists in database - return primary key */ - e->destroy(e); - return id; - } - e->destroy(e); - - /* register new device ID in database and return primary key */ - return (this->db->execute(this->db, &id, - "INSERT INTO devices (value) VALUES (?)", DB_BLOB, value) == 1) ? - id : 0; -} - METHOD(imv_os_database_t, set_device_info, void, - private_imv_os_database_t *this, int device_id, u_int32_t ar_id_type, - chunk_t ar_id_value, char *os_info, int count, int count_update, - int count_blacklist, u_int flags) + private_imv_os_database_t *this, int session_id, int count, + int count_update, int count_blacklist, u_int flags) { enumerator_t *e; - time_t last_time; - int pid = 0, last_pid = 0, iid = 0, last_iid; - int last_count_update = 0, last_count_blacklist = 0; - u_int last_flags; - bool found = FALSE; - - /* get primary key of OS info string if it exists */ - e = this->db->query(this->db, - "SELECT id FROM products WHERE name = ?", DB_TEXT, os_info, - DB_INT); - if (e) - { - e->enumerate(e, &pid); - e->destroy(e); - } - - /* if OS info string has not been found - register it */ - if (!pid) - { - this->db->execute(this->db, &pid, - "INSERT INTO products (name) VALUES (?)", DB_TEXT, os_info); - } - - /* get primary key of AR identity if it exists */ - e = this->db->query(this->db, - "SELECT id FROM identities WHERE type = ? AND data = ?", - DB_INT, ar_id_type, DB_BLOB, ar_id_value, DB_INT); - if (e) - { - e->enumerate(e, &iid); - e->destroy(e); - } - - /* if AR identity has not been found - register it */ - if (!iid) - { - this->db->execute(this->db, &iid, - "INSERT INTO identities (type, data) VALUES (?, ?)", - DB_INT, ar_id_type, DB_BLOB, ar_id_value); - } - /* get latest device info record if it exists */ - e = this->db->query(this->db, - "SELECT time, ar_id, product, count_update, count_blacklist, flags " - "FROM device_infos WHERE device = ? ORDER BY time DESC", - DB_INT, device_id, DB_INT, DB_INT, DB_INT, DB_INT, DB_INT, DB_UINT); - if (e) - { - found = e->enumerate(e, &last_time, &last_iid, &last_pid, - &last_count_update, &last_count_blacklist, - &last_flags); - e->destroy(e); - } - if (found && !last_count_update && !last_count_blacklist && !last_flags && - iid == last_iid && pid == last_pid) - { - /* update device info */ - this->db->execute(this->db, NULL, - "UPDATE device_infos SET time = ?, count = ?, count_update = ?, " - "count_blacklist = ?, flags = ? WHERE device = ? AND time = ?", - DB_UINT, time(NULL), DB_INT, count, DB_INT, count_update, - DB_INT, count_blacklist, DB_UINT, flags, - DB_INT, device_id, DB_UINT, last_time); - } - else - { - /* insert device info */ - this->db->execute(this->db, NULL, - "INSERT INTO device_infos (device, time, ar_id, product, count, " - "count_update, count_blacklist, flags) " - "VALUES (?, ?, ?, ?, ?, ?, ?, ?)", - DB_INT, device_id, DB_UINT, time(NULL), DB_INT, iid, DB_INT, pid, - DB_INT, count, DB_INT, count_update, DB_INT, count_blacklist, - DB_UINT, flags); - } + this->db->execute(this->db, NULL, + "INSERT INTO device_infos (session, count, count_update, " + "count_blacklist, flags) VALUES (?, ?, ?, ?, ?)", + DB_INT, session_id, DB_INT, count, DB_INT, count_update, + DB_INT, count_blacklist, DB_UINT, flags); } METHOD(imv_os_database_t, destroy, void, private_imv_os_database_t *this) { - this->db->destroy(this->db); free(this); } /** * See header */ -imv_os_database_t *imv_os_database_create(char *uri) +imv_os_database_t *imv_os_database_create(imv_database_t *imv_db) { private_imv_os_database_t *this; + if (!imv_db) + { + return NULL; + } + INIT(this, .public = { .check_packages = _check_packages, - .get_device_id = _get_device_id, .set_device_info = _set_device_info, .destroy = _destroy, }, - .db = lib->db->create(lib->db, uri), + .db = imv_db->get_database(imv_db), ); - if (!this->db) - { - DBG1(DBG_IMV, - "failed to connect to OS database '%s'", uri); - free(this); - return NULL; - } - return &this->public; } diff --git a/src/libimcv/plugins/imv_os/imv_os_database.h b/src/libimcv/plugins/imv_os/imv_os_database.h index 01d7e84a26..7b9ef3c331 100644 --- a/src/libimcv/plugins/imv_os/imv_os_database.h +++ b/src/libimcv/plugins/imv_os/imv_os_database.h @@ -22,6 +22,7 @@ #define IMV_OS_DATABASE_H_ #include "imv_os_state.h" +#include "imv/imv_database.h" #include @@ -42,32 +43,20 @@ struct imv_os_database_t { enumerator_t *package_enumerator); /** - * Get the primary database key of the device ID - * - * @param value Device ID value - */ - int (*get_device_id)(imv_os_database_t *this, chunk_t value); - - /** - * Set health infos for a given device - * - * @param device_id Device ID primary key - * @param ar_id_type Access Requestor ID Type - * @param ar_id_value Access Requestor ID Value - * @param os_info OS info string - * @param count Number of installed packages - * @param count_update Number of packages to be updated - * @param count_blacklist Number of blacklisted packages - * @param flags Various flags, e.g. illegal OS settings - */ - void (*set_device_info)(imv_os_database_t *this, int device_id, - u_int32_t ar_id_type, chunk_t ar_id_value, - char *os_info, int count, int count_update, - int count_blacklist, u_int flags); + * Set health infos for a given device + * + * @param sesson_id Session ID + * @param count Number of installed packages + * @param count_update Number of packages to be updated + * @param count_blacklist Number of blacklisted packages + * @param flags Various flags, e.g. illegal OS settings + */ + void (*set_device_info)(imv_os_database_t *this, int session_id, int count, + int count_update, int count_blacklist, u_int flags); /** - * Destroys an imv_os_database_t object. - */ + * Destroys an imv_os_database_t object. + */ void (*destroy)(imv_os_database_t *this); }; @@ -75,8 +64,8 @@ struct imv_os_database_t { /** * Create an imv_os_database_t instance * - * @param uri database uri + * @param imv_db Already attached IMV database */ -imv_os_database_t* imv_os_database_create(char *uri); +imv_os_database_t* imv_os_database_create(imv_database_t *imv_db); #endif /** IMV_OS_DATABASE_H_ @}*/ diff --git a/src/libimcv/plugins/imv_os/imv_os_state.c b/src/libimcv/plugins/imv_os/imv_os_state.c index 073d7133ab..e9661ec884 100644 --- a/src/libimcv/plugins/imv_os/imv_os_state.c +++ b/src/libimcv/plugins/imv_os/imv_os_state.c @@ -71,6 +71,11 @@ struct private_imv_os_state_t { */ chunk_t ar_id_value; + /** + * Unique session ID + */ + int session_id; + /** * IMV action recommendation */ @@ -346,6 +351,18 @@ METHOD(imv_state_t, get_ar_id, chunk_t, return this->ar_id_value; } +METHOD(imv_state_t, set_session_id, void, + private_imv_os_state_t *this, int session_id) +{ + this->session_id = session_id; +} + +METHOD(imv_state_t, get_session_id, int, + private_imv_os_state_t *this) +{ + return this->session_id; +} + METHOD(imv_state_t, change_state, void, private_imv_os_state_t *this, TNC_ConnectionState new_state) { @@ -633,6 +650,8 @@ imv_state_t *imv_os_state_create(TNC_ConnectionID connection_id) .get_max_msg_len = _get_max_msg_len, .set_ar_id = _set_ar_id, .get_ar_id = _get_ar_id, + .set_session_id = _set_session_id, + .get_session_id = _get_session_id, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, diff --git a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c index 2123af7a8e..f75dce542e 100644 --- a/src/libimcv/plugins/imv_scanner/imv_scanner_state.c +++ b/src/libimcv/plugins/imv_scanner/imv_scanner_state.c @@ -68,6 +68,11 @@ struct private_imv_scanner_state_t { */ chunk_t ar_id_value; + /** + * Unique session ID + */ + int session_id; + /** * IMV action recommendation */ @@ -182,6 +187,18 @@ METHOD(imv_state_t, set_ar_id, void, this->ar_id_value = chunk_clone(id_value); } +METHOD(imv_state_t, set_session_id, void, + private_imv_scanner_state_t *this, int session_id) +{ + this->session_id = session_id; +} + +METHOD(imv_state_t, get_session_id, int, + private_imv_scanner_state_t *this) +{ + return this->session_id; +} + METHOD(imv_state_t, get_ar_id, chunk_t, private_imv_scanner_state_t *this, u_int32_t *id_type) { @@ -296,6 +313,8 @@ imv_state_t *imv_scanner_state_create(TNC_ConnectionID connection_id) .get_max_msg_len = _get_max_msg_len, .set_ar_id = _set_ar_id, .get_ar_id = _get_ar_id, + .set_session_id = _set_session_id, + .get_session_id = _get_session_id, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, diff --git a/src/libimcv/plugins/imv_test/imv_test_state.c b/src/libimcv/plugins/imv_test/imv_test_state.c index 41da44d674..4f916183d1 100644 --- a/src/libimcv/plugins/imv_test/imv_test_state.c +++ b/src/libimcv/plugins/imv_test/imv_test_state.c @@ -68,6 +68,11 @@ struct private_imv_test_state_t { */ chunk_t ar_id_value; + /** + * Unique session ID + */ + int session_id; + /** * IMV action recommendation */ @@ -170,6 +175,18 @@ METHOD(imv_state_t, get_ar_id, chunk_t, return this->ar_id_value; } +METHOD(imv_state_t, set_session_id, void, + private_imv_test_state_t *this, int session_id) +{ + this->session_id = session_id; +} + +METHOD(imv_state_t, get_session_id, int, + private_imv_test_state_t *this) +{ + return this->session_id; +} + METHOD(imv_state_t, change_state, void, private_imv_test_state_t *this, TNC_ConnectionState new_state) { @@ -307,6 +324,8 @@ imv_state_t *imv_test_state_create(TNC_ConnectionID connection_id) .get_max_msg_len = _get_max_msg_len, .set_ar_id = _set_ar_id, .get_ar_id = _get_ar_id, + .set_session_id = _set_session_id, + .get_session_id = _get_session_id, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, diff --git a/src/libpts/Makefile.am b/src/libpts/Makefile.am index edf3f7416c..7810e981cf 100644 --- a/src/libpts/Makefile.am +++ b/src/libpts/Makefile.am @@ -1,5 +1,8 @@ -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/libimcv +INCLUDES = \ + -I$(top_srcdir)/src/libstrongswan \ + -I$(top_srcdir)/src/libtncif \ + -I$(top_srcdir)/src/libimcv ipseclib_LTLIBRARIES = libpts.la diff --git a/src/libpts/plugins/imv_attestation/attest.c b/src/libpts/plugins/imv_attestation/attest.c index 944716ac36..365a7cb1c1 100644 --- a/src/libpts/plugins/imv_attestation/attest.c +++ b/src/libpts/plugins/imv_attestation/attest.c @@ -108,6 +108,7 @@ static void do_args(int argc, char *argv[]) OP_MEASUREMENTS, OP_PACKAGES, OP_PRODUCTS, + OP_SESSIONS, OP_ADD, OP_DEL, } op = OP_UNDEF; @@ -131,6 +132,7 @@ static void do_args(int argc, char *argv[]) { "products", no_argument, NULL, 'p' }, { "hashes", no_argument, NULL, 'H' }, { "measurements", no_argument, NULL, 'm' }, + { "sessions", no_argument, NULL, 's' }, { "add", no_argument, NULL, 'a' }, { "delete", no_argument, NULL, 'r' }, { "del", no_argument, NULL, 'r' }, @@ -201,6 +203,9 @@ static void do_args(int argc, char *argv[]) case 'm': op = OP_MEASUREMENTS; continue; + case 's': + op = OP_SESSIONS; + continue; case 'a': op = OP_ADD; continue; @@ -408,6 +413,9 @@ static void do_args(int argc, char *argv[]) case OP_MEASUREMENTS: attest->list_measurements(attest); break; + case OP_SESSIONS: + attest->list_sessions(attest); + break; case OP_ADD: attest->add(attest); break; diff --git a/src/libpts/plugins/imv_attestation/attest_db.c b/src/libpts/plugins/imv_attestation/attest_db.c index 8459e2b233..633d6c58dc 100644 --- a/src/libpts/plugins/imv_attestation/attest_db.c +++ b/src/libpts/plugins/imv_attestation/attest_db.c @@ -13,16 +13,18 @@ * for more details. */ +#define _GNU_SOURCE + +#include +#include +#include + #include "attest_db.h" #include "libpts.h" #include "pts/pts_meas_algo.h" #include "pts/pts_file_meas.h" #include "pts/components/pts_comp_func_name.h" - -#include -#include - #define IMA_MAX_NAME_LEN 255 typedef struct private_attest_db_t private_attest_db_t; @@ -815,18 +817,19 @@ METHOD(attest_db_t, list_devices, void, u_int tstamp, flags = 0; e = this->db->query(this->db, - "SELECT d.id, d.value, i.time, i.count, i.count_update, " - "i.count_blacklist, i.flags, i.ar_id, p.name FROM devices AS d " - "JOIN device_infos AS i ON d.id = i.device " - "JOIN products AS p ON p.id = i.product " - "ORDER BY d.value, i.time DESC", - DB_INT, DB_BLOB, DB_UINT, DB_INT, DB_INT, DB_INT, DB_UINT, - DB_INT, DB_TEXT); + "SELECT d.id, d.value, s.time, s.identity, p.name, " + "i.count, i.count_update, i.count_blacklist, i.flags " + "FROM devices AS d " + "JOIN sessions AS s ON d.id = s.device " + "JOIN products AS p ON p.id = s.product " + "JOIN device_infos AS i ON i.session = s.id " + "ORDER BY d.value, s.time DESC", DB_INT, DB_BLOB, DB_UINT, + DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, DB_UINT); if (e) { - while (e->enumerate(e, &id, &value, &tstamp, &count, &count_update, - &count_blacklist, &flags, &ar_id, &product)) + while (e->enumerate(e, &id, &value, &tstamp, &ar_id, &product, + &count, &count_update, &count_blacklist, &flags)) { if (id != last_id) { @@ -843,7 +846,7 @@ METHOD(attest_db_t, list_devices, void, { chunk_free(&ar_id_value); e_ar = this->db->query(this->db, - "SELECT type, data FROM identities " + "SELECT type, value FROM identities " "WHERE id = ?", DB_INT, ar_id, DB_INT, DB_BLOB); if (e_ar) { @@ -1124,67 +1127,63 @@ METHOD(attest_db_t, list_products, void, printf("\n"); } -/** - * get the directory if there is one from the files tables - */ -static void get_directory(private_attest_db_t *this, int did, char **directory) +METHOD(attest_db_t, list_hashes, void, + private_attest_db_t *this) { enumerator_t *e; - char *dir; - - free(*directory); - *directory = strdup(""); + chunk_t hash; + char *file, *dir, *product; + int id, fid, fid_old = 0, did, did_old = 0, pid, pid_old = 0, count = 0; - if (did) + if (this->pid && this->fid && this->did) { + printf("%4d: %s\n", this->did, this->dir); + printf("%4d: %s\n", this->fid, this->file); e = this->db->query(this->db, - "SELECT path from files WHERE id = ?", - DB_UINT, did, DB_TEXT); + "SELECT id, hash FROM file_hashes " + "WHERE algo = ? AND file = ? AND product = ?", + DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->pid, + DB_INT, DB_BLOB); if (e) { - if (e->enumerate(e, &dir)) + while (e->enumerate(e, &id, &hash)) { - free(*directory); - *directory = strdup(dir); + printf("%4d: %#B\n", id, &hash); + count++; } e->destroy(e); + + printf("%d %N value%s found for product '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", this->product); } } -} - -static bool slash(char *directory, char *file) -{ - return *file != '/' && directory[max(0, strlen(directory)-1)] != '/'; -} - -METHOD(attest_db_t, list_hashes, void, - private_attest_db_t *this) -{ - enumerator_t *e; - chunk_t hash; - char *file, *dir, *product; - int fid, fid_old = 0, did, did_old = 0, count = 0; - - dir = strdup(""); - - if (this->pid && this->fid & this->did) + else if (this->pid && this->file) { e = this->db->query(this->db, - "SELECT hash FROM file_hashes " - "WHERE algo = ? AND file = ? AND directory = ? AND product = ?", - DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->did, - DB_INT, this->pid, DB_BLOB); + "SELECT h.id, h.hash, f.id, d.id, d.path " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN directories AS d ON f.dir = d.id " + "WHERE h.algo = ? AND h.product = ? AND f.name = ? " + "ORDER BY d.path, f.name, h.hash", + DB_INT, this->algo, DB_INT, this->pid, DB_TEXT, this->file, + DB_INT, DB_BLOB, DB_INT, DB_INT, DB_TEXT); if (e) { - while (e->enumerate(e, &hash)) + while (e->enumerate(e, &id, &hash, &fid, &did, &dir)) { - if (this->fid != fid_old) + if (did != did_old) { - printf("%4d: %s%s%s\n", this->fid, this->dir, - slash(this->dir, this->file) ? "/" : "", this->file); - fid_old = this->fid; + printf("%4d: %s\n", did, dir); + did_old = did; + } + if (fid != fid_old) + { + printf("%4d: %s\n", fid, this->file); + fid_old = fid; } - printf(" %#B\n", &hash); + printf("%4d: %#B\n", id, &hash); count++; } e->destroy(e); @@ -1194,22 +1193,27 @@ METHOD(attest_db_t, list_hashes, void, (count == 1) ? "" : "s", this->product); } } - else if (this->pid && this->fid) + else if (this->pid && this->did) { + printf("%4d: %s\n", this->did, this->dir); e = this->db->query(this->db, - "SELECT f.path, fh.hash FROM file_hashes AS fh " - "JOIN files AS f ON f.id = fh.file " - "WHERE algo = ? AND file = ? AND product = ?", - DB_INT, this->algo, DB_INT, this->fid, DB_INT, this->pid, - DB_TEXT, DB_BLOB); + "SELECT h.id, h.hash, f.id, f.name " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "WHERE h.algo = ? AND h.product = ? AND f.dir = ? " + "ORDER BY f.name, h.hash", + DB_INT, this->algo, DB_INT, this->pid, DB_INT, this->did, + DB_INT, DB_BLOB, DB_INT, DB_TEXT); if (e) { - free(dir); - while (e->enumerate(e, &dir, &hash)) + while (e->enumerate(e, &id, &hash, &fid, &file)) { - printf("%4d: %s%s%s\n", this->fid, dir, - slash(dir, this->file) ? "/" : "", this->file); - printf(" %#B\n", &hash); + if (fid != fid_old) + { + printf("%4d: %s\n", fid, file); + fid_old = fid; + } + printf("%4d: %#B\n", id, &hash); count++; } e->destroy(e); @@ -1217,35 +1221,34 @@ METHOD(attest_db_t, list_hashes, void, printf("%d %N value%s found for product '%s'\n", count, pts_meas_algorithm_names, this->algo, (count == 1) ? "" : "s", this->product); - dir = NULL; } } else if (this->pid) { e = this->db->query(this->db, - "SELECT f.id, f. f.path, fh.hash, fh.directory " - "FROM file_hashes AS fh " - "JOIN files AS f ON f.id = fh.file " - "WHERE fh.algo = ? AND fh.product = ? " - "ORDER BY fh.directory, f.path", - DB_INT, this->algo, DB_UINT, this->pid, - DB_INT, DB_TEXT, DB_BLOB, DB_INT); + "SELECT h.id, h.hash, f.id, f.name, d.id, d.path " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN directories AS d ON f.dir = d.id " + "WHERE h.algo = ? AND h.product = ? " + "ORDER BY d.path, f.name, h.hash", + DB_INT, this->algo, DB_INT, this->pid, + DB_INT, DB_BLOB, DB_INT, DB_TEXT, DB_INT, DB_TEXT); if (e) { - while (e->enumerate(e, &fid, &file, &hash, &did)) + while (e->enumerate(e, &id, &hash, &fid, &file, &did, &dir)) { - if (fid != fid_old || did != did_old) + if (did != did_old) { - if (did != did_old) - { - get_directory(this, did, &dir); - } - printf("%4d: %s%s%s\n", fid, - dir, slash(dir, file) ? "/" : "", file); - fid_old = fid; + printf("%4d: %s\n", did, dir); did_old = did; } - printf(" %#B\n", &hash); + if (fid != fid_old) + { + printf("%4d: %s\n", fid, file); + fid_old = fid; + } + printf("%4d: %#B\n", id, &hash); count++; } e->destroy(e); @@ -1255,58 +1258,147 @@ METHOD(attest_db_t, list_hashes, void, (count == 1) ? "" : "s", this->product); } } - else if (this->fid) + else if (this->fid && this->did) { e = this->db->query(this->db, - "SELECT p.name, fh.hash, fh.directory " - "FROM file_hashes AS fh " - "JOIN products AS p ON p.id = fh.product " - "WHERE fh.algo = ? AND fh.file = ? AND fh.directory = ?" - "ORDER BY p.name", - DB_INT, this->algo, DB_UINT, this->fid, DB_UINT, this->did, - DB_TEXT, DB_BLOB, DB_INT); + "SELECT h.id, h.hash, p.id, p.name FROM file_hashes AS h " + "JOIN products AS p ON h.product = p.id " + "WHERE h.algo = ? AND h.file = ? " + "ORDER BY p.name, h.hash", + DB_INT, this->algo, DB_INT, this->fid, + DB_INT, DB_BLOB, DB_INT, DB_TEXT); if (e) { - while (e->enumerate(e, &product, &hash, &did)) + while (e->enumerate(e, &id, &hash, &pid, &product)) { - printf("%#B '%s'\n", &hash, product); + if (pid != pid_old) + { + printf("%4d: %s\n", pid, product); + pid_old = pid; + } + printf("%4d: %#B\n", id, &hash); count++; } e->destroy(e); - printf("%d %N value%s found for file '%s%s%s'\n", - count, pts_meas_algorithm_names, this->algo, + printf("%d %N value%s found for file '%s%s%s'\n", count, + pts_meas_algorithm_names, this->algo, (count == 1) ? "" : "s", this->dir, - slash(this->dir, this->file) ? "/" : "", this->file); + streq(this->dir, "/") ? "" : "/", this->file); + } + } + else if (this->file) + { + e = this->db->query(this->db, + "SELECT h.id, h.hash, f.id, d.id, d.path, p.id, p.name " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN directories AS d ON f.dir = d.id " + "JOIN products AS p ON h.product = p.id " + "WHERE h.algo = ? AND f.name = ? " + "ORDER BY d.path, f.name, p.name, h.hash", + DB_INT, this->algo, DB_TEXT, this->file, + DB_INT, DB_BLOB, DB_INT, DB_INT, DB_TEXT, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &hash, &fid, &did, &dir, &pid, &product)) + { + if (did != did_old) + { + printf("%4d: %s\n", did, dir); + did_old = did; + } + if (fid != fid_old) + { + printf("%4d: %s\n", fid, this->file); + fid_old = fid; + pid_old = 0; + } + if (pid != pid_old) + { + printf("%4d: %s\n", pid, product); + pid_old = pid; + } + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found\n", count, pts_meas_algorithm_names, + this->algo, (count == 1) ? "" : "s"); + } + + } + else if (this->did) + { + e = this->db->query(this->db, + "SELECT h.id, h.hash, f.id, f.name, p.id, p.name " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN products AS p ON h.product = p.id " + "WHERE h.algo = ? AND f.dir = ? " + "ORDER BY f.name, p.name, h.hash", + DB_INT, this->algo, DB_INT, this->did, + DB_INT, DB_BLOB, DB_INT, DB_TEXT, DB_INT, DB_TEXT); + if (e) + { + while (e->enumerate(e, &id, &hash, &fid, &file, &pid, &product)) + { + if (fid != fid_old) + { + printf("%4d: %s\n", fid, file); + fid_old = fid; + pid_old = 0; + } + if (pid != pid_old) + { + printf("%4d: %s\n", pid, product); + pid_old = pid; + } + printf("%4d: %#B\n", id, &hash); + count++; + } + e->destroy(e); + + printf("%d %N value%s found for directory '%s'\n", count, + pts_meas_algorithm_names, this->algo, + (count == 1) ? "" : "s", this->dir); } } else { e = this->db->query(this->db, - "SELECT f.id, f.path, p.name, fh.hash, fh.directory " - "FROM file_hashes AS fh " - "JOIN files AS f ON f.id = fh.file " - "JOIN products AS p ON p.id = fh.product " - "WHERE fh.algo = ? " - "ORDER BY fh.directory, f.path, p.name", - DB_INT, this->algo, - DB_INT, DB_TEXT, DB_TEXT, DB_BLOB, DB_INT); + "SELECT h.id, h.hash, f.id, f.name, d.id, d.path, p.id, p.name " + "FROM file_hashes AS h " + "JOIN files AS f ON h.file = f.id " + "JOIN directories AS d ON f.dir = d.id " + "JOIN products AS p on h.product = p.id " + "WHERE h.algo = ? " + "ORDER BY d.path, f.name, p.name, h.hash", + DB_INT, this->algo, DB_INT, DB_BLOB, DB_INT, DB_TEXT, + DB_INT, DB_TEXT, DB_INT, DB_TEXT); if (e) { - while (e->enumerate(e, &fid, &file, &product, &hash, &did)) + while (e->enumerate(e, &id, &hash, &fid, &file, &did, &dir, &pid, + &product)) { - if (fid != fid_old || did != did_old) + if (did != did_old) { - if (did != did_old) - { - get_directory(this, did, &dir); - did_old = did; - } - printf("%4d: %s%s%s\n", fid, - dir, slash(dir, file) ? "/" : "", file); + printf("%4d: %s\n", did, dir); + did_old = did; + } + if (fid != fid_old) + { + printf("%4d: %s\n", fid, file); fid_old = fid; + pid_old = 0; + } + if (pid != pid_old) + { + printf("%4d: %s\n", pid, product); + pid_old = pid; } - printf(" %#B '%s'\n", &hash, product); + printf("%4d: %#B\n", id, &hash); count++; } e->destroy(e); @@ -1315,7 +1407,6 @@ METHOD(attest_db_t, list_hashes, void, this->algo, (count == 1) ? "" : "s"); } } - free(dir); } METHOD(attest_db_t, list_measurements, void, @@ -1422,9 +1513,49 @@ METHOD(attest_db_t, list_measurements, void, } } -bool insert_file_hash(private_attest_db_t *this, pts_meas_algorithms_t algo, - chunk_t measurement, int fid, int did, bool ima, - int *hashes_added, int *hashes_updated) +METHOD(attest_db_t, list_sessions, void, + private_attest_db_t *this) +{ + enumerator_t *e; + chunk_t device, identity; + char *product; + int session_id, conn_id; + time_t created; + u_int t; + + e = this->db->query(this->db, + "SELECT s.id, s.time, s.connection, p.name, d.value, i.value " + "FROM sessions AS s " + "LEFT JOIN products AS p ON s.product = p.id " + "LEFT JOIN devices AS d ON s.device = d.id " + "LEFT JOIN identities AS i ON s.identity = i.id " + "ORDER BY s.time DESC", + DB_INT, DB_UINT, DB_INT, DB_TEXT, DB_BLOB, DB_BLOB); + if (e) + { + while (e->enumerate(e, &session_id, &t, &conn_id, &product, &device, + &identity)) + { + created = t; + product = product ? product : "-"; + device = device.len ? device : chunk_from_str("-"); + device.len = min(device.len, 20); + identity = identity.len ? identity : chunk_from_str("-"); + printf("%4d: %T %2d %-20s %.*s%*s %.*s\n", session_id, &created, + FALSE, conn_id, product, device.len, device.ptr, + 20-device.len, " ", identity.len, identity.ptr); + } + e->destroy(e); + } +} + +/** + * Insert a file hash into the database + */ +static bool insert_file_hash(private_attest_db_t *this, + pts_meas_algorithms_t algo, + chunk_t measurement, int fid, bool ima, + int *hashes_added, int *hashes_updated) { enumerator_t *e; chunk_t hash; @@ -1434,8 +1565,8 @@ bool insert_file_hash(private_attest_db_t *this, pts_meas_algorithms_t algo, e = this->db->query(this->db, "SELECT hash FROM file_hashes WHERE algo = ? " - "AND file = ? AND directory = ? AND product = ? and key = 0", - DB_INT, algo, DB_UINT, fid, DB_UINT, did, DB_UINT, this->pid, DB_BLOB); + "AND file = ? AND product = ? AND device = 0", + DB_INT, algo, DB_UINT, fid, DB_UINT, this->pid, DB_BLOB); if (!e) { printf("file_hashes query failed\n"); @@ -1451,8 +1582,8 @@ bool insert_file_hash(private_attest_db_t *this, pts_meas_algorithms_t algo, { if (this->db->execute(this->db, NULL, "UPDATE file_hashes SET hash = ? WHERE algo = ? " - "AND file = ? AND directory = ? AND product = ? and key = 0", - DB_BLOB, measurement, DB_INT, algo, DB_UINT, fid, DB_UINT, did, + "AND file = ? AND product = ? and device = 0", + DB_BLOB, measurement, DB_INT, algo, DB_UINT, fid, DB_UINT, this->pid) == 1) { label = "updated"; @@ -1464,9 +1595,9 @@ bool insert_file_hash(private_attest_db_t *this, pts_meas_algorithms_t algo, { if (this->db->execute(this->db, NULL, "INSERT INTO file_hashes " - "(file, directory, product, key, algo, hash) " - "VALUES (?, ?, ?, 0, ?, ?)", - DB_UINT, fid, DB_UINT, did, DB_UINT, this->pid, + "(file, product, device, algo, hash) " + "VALUES (?, ?, 0, ?, ?)", + DB_UINT, fid, DB_UINT, this->pid, DB_INT, algo, DB_BLOB, measurement) == 1) { label = "created"; @@ -1479,77 +1610,75 @@ bool insert_file_hash(private_attest_db_t *this, pts_meas_algorithms_t algo, return TRUE; } -METHOD(attest_db_t, add, bool, - private_attest_db_t *this) +/** + * Add hash measurement for a single file or all files in a directory + */ +static bool add_hash(private_attest_db_t *this) { - bool success = FALSE; - - /* add key/component pair */ - if (this->kid && this->cid) - { - success = this->db->execute(this->db, NULL, - "INSERT INTO key_component (key, component, seq_no) " - "VALUES (?, ?, ?)", - DB_UINT, this->kid, DB_UINT, this->cid, - DB_UINT, this->seq_no) == 1; - - printf("key/component pair (%d/%d) %sinserted into database at " - "position %d\n", this->kid, this->cid, - success ? "" : "could not be ", this->seq_no); - - return success; - } - - /* add directory or file measurement for a given product */ - if ((this->did || this->fid) && this->pid) - { - char *pathname, *filename, *label; - char ima_buffer[IMA_MAX_NAME_LEN + 1]; - chunk_t measurement, ima_template; - pts_file_meas_t *measurements; - hasher_t *hasher = NULL; - bool ima = FALSE; - int fid, did; - int files_added = 0, hashes_added = 0, hashes_updated = 0; - int ima_hashes_added = 0, ima_hashes_updated = 0; - enumerator_t *enumerator, *e; - - if (this->algo == PTS_MEAS_ALGO_SHA1_IMA) + char *pathname, *filename, *sep, *label, *pos; + char ima_buffer[IMA_MAX_NAME_LEN + 1]; + chunk_t measurement, ima_template; + pts_file_meas_t *measurements; + hasher_t *hasher = NULL; + bool ima = FALSE; + int fid, files_added = 0, hashes_added = 0, hashes_updated = 0; + int len, ima_hashes_added = 0, ima_hashes_updated = 0; + enumerator_t *enumerator, *e; + + if (this->algo == PTS_MEAS_ALGO_SHA1_IMA) + { + ima = TRUE; + this->algo = PTS_MEAS_ALGO_SHA1; + hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); + if (!hasher) { - ima = TRUE; - this->algo = PTS_MEAS_ALGO_SHA1; - hasher = lib->crypto->create_hasher(lib->crypto, HASH_SHA1); - if (!hasher) - { - printf("could not create hasher\n"); - return FALSE; - } + printf("could not create hasher\n"); + return FALSE; } + } + sep = streq(this->dir, "/") ? "" : "/"; - pathname = this->did ? this->dir : this->file; - measurements = pts_file_meas_create_from_path(0, pathname, this->did, - this->relative, this->algo); - if (!measurements) + if (this->fid) + { + /* build pathname from directory path and relative filename */ + if (asprintf(&pathname, "%s%s%s", this->dir, sep, this->file) == -1) { - printf("file measurement failed\n"); - DESTROY_IF(hasher); return FALSE; } - if (this->fid && this->relative) + measurements = pts_file_meas_create_from_path(0, pathname, FALSE, + TRUE, this->algo); + free(pathname); + } + else + { + measurements = pts_file_meas_create_from_path(0, pathname, TRUE, + TRUE, this->algo); + } + if (!measurements) + { + printf("file measurement failed\n"); + DESTROY_IF(hasher); + return FALSE; + } + + enumerator = measurements->create_enumerator(measurements); + while (enumerator->enumerate(enumerator, &filename, &measurement)) + { + if (this->fid) { - set_directory(this, dirname(pathname), TRUE); + /* a single file already exists */ + filename = this->file; + fid = this->fid; + label = "exists"; } - did = this->relative ? this->did : 0; - - enumerator = measurements->create_enumerator(measurements); - while (enumerator->enumerate(enumerator, &filename, &measurement)) + else { /* retrieve or create filename */ label = "could not be created"; e = this->db->query(this->db, - "SELECT id FROM files WHERE path = ?", - DB_TEXT, filename, DB_INT); + "SELECT id FROM files WHERE name = ? AND dir = ?", + DB_TEXT, filename, DB_INT, this->did, DB_INT); if (!e) { printf("files query failed\n"); @@ -1562,65 +1691,101 @@ METHOD(attest_db_t, add, bool, else { if (this->db->execute(this->db, &fid, - "INSERT INTO files (type, path) VALUES (0, ?)", - DB_TEXT, filename) == 1) + "INSERT INTO files (name, dir) VALUES (?, ?)", + DB_TEXT, filename, DB_INT, this->did) == 1) { label = "created"; files_added++; } } e->destroy(e); + } + printf("%4d: %s - %s\n", fid, filename, label); - printf("%4d: %s - %s\n", fid, filename, label); - - /* compute file measurement hash */ - if (!insert_file_hash(this, this->algo, measurement, - fid, did, FALSE, - &hashes_added, &hashes_updated)) - { - break; - } - - if (!ima) - { - continue; - } - - /* compute IMA template hash */ - strncpy(ima_buffer, filename, IMA_MAX_NAME_LEN); - ima_buffer[IMA_MAX_NAME_LEN] = '\0'; - ima_template = chunk_create(ima_buffer, sizeof(ima_buffer)); - if (!hasher->get_hash(hasher, measurement, NULL) || - !hasher->get_hash(hasher, ima_template, measurement.ptr)) - { - printf("could not compute IMA template hash\n"); - break; - } - if (!insert_file_hash(this, PTS_MEAS_ALGO_SHA1_IMA, measurement, - fid, did, TRUE, - &ima_hashes_added, &ima_hashes_updated)) - { - break; - } + /* compute file measurement hash */ + if (!insert_file_hash(this, this->algo, measurement, fid, FALSE, + &hashes_added, &hashes_updated)) + { + break; + } + if (!ima) + { + continue; } - enumerator->destroy(enumerator); - printf("%d measurements, added %d new files, %d file hashes", - measurements->get_file_count(measurements), files_added, - hashes_added); - if (ima) + /* compute IMA template hash */ + pos = ima_buffer; + len = IMA_MAX_NAME_LEN; + if (!this->relative) + { + strncpy(pos, this->dir, len); + len = max(0, len - strlen(this->dir)); + pos = ima_buffer + IMA_MAX_NAME_LEN - len; + strncpy(pos, sep, len); + len = max(0, len - strlen(sep)); + pos = ima_buffer + IMA_MAX_NAME_LEN - len; + } + strncpy(pos, filename, len); + ima_buffer[IMA_MAX_NAME_LEN] = '\0'; + ima_template = chunk_create(ima_buffer, sizeof(ima_buffer)); + if (!hasher->get_hash(hasher, measurement, NULL) || + !hasher->get_hash(hasher, ima_template, measurement.ptr)) { - printf(", %d ima hashes", ima_hashes_added); - hasher->destroy(hasher); + printf("could not compute IMA template hash\n"); + break; } - printf(", updated %d file hashes", hashes_updated); - if (ima) + if (!insert_file_hash(this, PTS_MEAS_ALGO_SHA1_IMA, measurement, fid, + TRUE, &ima_hashes_added, &ima_hashes_updated)) { - printf(", %d ima hashes", ima_hashes_updated); + break; } - printf("\n"); - measurements->destroy(measurements); - success = TRUE; + } + enumerator->destroy(enumerator); + + printf("%d measurements, added %d new files, %d file hashes", + measurements->get_file_count(measurements), files_added, + hashes_added); + if (ima) + { + printf(", %d ima hashes", ima_hashes_added); + hasher->destroy(hasher); + } + printf(", updated %d file hashes", hashes_updated); + if (ima) + { + printf(", %d ima hashes", ima_hashes_updated); + } + printf("\n"); + measurements->destroy(measurements); + + return TRUE; +} + +METHOD(attest_db_t, add, bool, + private_attest_db_t *this) +{ + bool success = FALSE; + + /* add key/component pair */ + if (this->kid && this->cid) + { + success = this->db->execute(this->db, NULL, + "INSERT INTO key_component (key, component, seq_no) " + "VALUES (?, ?, ?)", + DB_UINT, this->kid, DB_UINT, this->cid, + DB_UINT, this->seq_no) == 1; + + printf("key/component pair (%d/%d) %sinserted into database at " + "position %d\n", this->kid, this->cid, + success ? "" : "could not be ", this->seq_no); + + return success; + } + + /* add directory or file hash measurement for a given product */ + if (this->did && this->pid) + { + return add_hash(this); } /* insert package version */ @@ -1656,13 +1821,12 @@ METHOD(attest_db_t, delete, bool, { success = this->db->execute(this->db, NULL, "DELETE FROM file_hashes " - "WHERE algo = ? AND product = ? " - "AND file = ? AND directory = ?", + "WHERE algo = ? AND product = ? AND file = ?", DB_UINT, this->algo, DB_UINT, this->pid, - DB_UINT, this->fid, DB_UINT, this->did) > 0; + DB_UINT, this->fid) > 0; - printf("%4d: %s%s%s\n", this->fid, this->dir, this->did ? "/":"", - this->file); + printf("%4d: %s%s%s\n", this->fid, this->dir, + streq(this->dir, "/") ? "" : "/", this->file); printf("%N value for product '%s' %sdeleted from database\n", pts_meas_algorithm_names, this->algo, this->product, success ? "" : "could not be "); @@ -1829,6 +1993,7 @@ attest_db_t *attest_db_create(char *uri) .list_keys = _list_keys, .list_hashes = _list_hashes, .list_measurements = _list_measurements, + .list_sessions = _list_sessions, .add = _add, .delete = _delete, .destroy = _destroy, diff --git a/src/libpts/plugins/imv_attestation/attest_db.h b/src/libpts/plugins/imv_attestation/attest_db.h index a110be9748..0d29be9977 100644 --- a/src/libpts/plugins/imv_attestation/attest_db.h +++ b/src/libpts/plugins/imv_attestation/attest_db.h @@ -227,6 +227,11 @@ struct attest_db_t { */ void (*list_measurements)(attest_db_t *this); + /** + * List sessions stored in the database + */ + void (*list_sessions)(attest_db_t *this); + /** * Add an entry to the database */ diff --git a/src/libpts/plugins/imv_attestation/imv_attestation.c b/src/libpts/plugins/imv_attestation/imv_attestation.c index 3c5488ebaa..fb32fcf4e2 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation.c @@ -83,7 +83,7 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, TNC_Version max_version, TNC_Version *actual_version) { - char *hash_alg, *dh_group, *uri, *cadir; + char *hash_alg, *dh_group, *cadir; if (imv_attestation) { @@ -133,10 +133,8 @@ TNC_Result TNC_IMV_Initialize(TNC_IMVID imv_id, pts_credmgr->add_set(pts_credmgr, pts_creds->get_set(pts_creds)); } - /* attach file measurement database */ - uri = lib->settings->get_str(lib->settings, - "libimcv.plugins.imv-attestation.database", NULL); - pts_db = pts_database_create(uri); + /* attach PTS database co-located with IMV database */ + pts_db = pts_database_create(imv_attestation->get_database(imv_attestation)); return TNC_RESULT_SUCCESS; } @@ -473,7 +471,9 @@ TNC_Result TNC_IMV_Terminate(TNC_IMVID imv_id) pts_creds->destroy(pts_creds); } DESTROY_IF(pts_db); + pts_db = NULL; DESTROY_IF(pts_credmgr); + pts_credmgr = NULL; libpts_deinit(); diff --git a/src/libpts/plugins/imv_attestation/imv_attestation_state.c b/src/libpts/plugins/imv_attestation/imv_attestation_state.c index fc42466145..8f0fb3686d 100644 --- a/src/libpts/plugins/imv_attestation/imv_attestation_state.c +++ b/src/libpts/plugins/imv_attestation/imv_attestation_state.c @@ -73,6 +73,11 @@ struct private_imv_attestation_state_t { */ chunk_t ar_id_value; + /** + * Unique session ID + */ + int session_id; + /** * IMV Attestation handshake state */ @@ -243,6 +248,18 @@ METHOD(imv_state_t, get_ar_id, chunk_t, return this->ar_id_value; } +METHOD(imv_state_t, set_session_id, void, + private_imv_attestation_state_t *this, int session_id) +{ + this->session_id = session_id; +} + +METHOD(imv_state_t, get_session_id, int, + private_imv_attestation_state_t *this) +{ + return this->session_id; +} + METHOD(imv_state_t, change_state, void, private_imv_attestation_state_t *this, TNC_ConnectionState new_state) { @@ -510,6 +527,8 @@ imv_state_t *imv_attestation_state_create(TNC_ConnectionID connection_id) .get_max_msg_len = _get_max_msg_len, .set_ar_id = _set_ar_id, .get_ar_id = _get_ar_id, + .set_session_id = _set_session_id, + .get_session_id = _get_session_id, .change_state = _change_state, .get_recommendation = _get_recommendation, .set_recommendation = _set_recommendation, diff --git a/src/libpts/plugins/imv_attestation/tables.sql b/src/libpts/plugins/imv_attestation/tables.sql index 5e9f4d79bc..64802c925e 100644 --- a/src/libpts/plugins/imv_attestation/tables.sql +++ b/src/libpts/plugins/imv_attestation/tables.sql @@ -13,7 +13,7 @@ CREATE INDEX directories_path ON directories ( DROP TABLE IF EXISTS files; CREATE TABLE files ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - dir INTEGER DEFAULT 0, + dir INTEGER DEFAULT 0 REFERENCES directories(id), name TEXT NOT NULL ); DROP INDEX IF EXISTS files_name; @@ -31,22 +31,41 @@ CREATE INDEX products_name ON products ( name ); +DROP TABLE IF EXISTS product_file; +CREATE TABLE product_file ( + product INTEGER NOT NULL REFERENCES products(id), + file INTEGER NOT NULL REFERENCES files(id), + measurement INTEGER DEFAULT 0, + metadata INTEGER DEFAULT 0, + PRIMARY KEY (product, file) +); + DROP TABLE IF EXISTS algorithms; CREATE TABLE algorithms ( id INTEGER PRIMARY KEY, - name TEXT not NULL + name VARCHAR(20) not NULL ); DROP TABLE IF EXISTS file_hashes; CREATE TABLE file_hashes ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - file INTEGER NOT NULL, - product INTEGER NOT NULL, + file INTEGER NOT NULL REFERENCES files(id), + product INTEGER NOT NULL REFERENCES products(id), device INTEGER DEFAULT 0, - algo INTEGER NOT NULL, + algo INTEGER NOT NULL REFERENCES algorithms(id), hash BLOB NOT NULL ); +DROP TABLE IF EXISTS sessions; +CREATE TABLE sessions ( + id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, + time INTEGER NOT NULL, + connection INTEGER NOT NULL, + identity INTEGER DEFAULT 0 REFERENCES identities(id), + device INTEGER DEFAULT 0 REFERENCES devices(id), + product INTEGER DEFAULT 0 REFERENCES products(id) +); + DROP TABLE IF EXISTS components; CREATE TABLE components ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, @@ -118,10 +137,7 @@ CREATE INDEX devices_value ON devices ( DROP TABLE IF EXISTS device_infos; CREATE TABLE device_infos ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, - device INTEGER NOT NULL, - time INTEGER NOT NULL, - ar_id INTEGER DEFAULT 0, - product INTEGER DEFAULT 0, + session INTEGER NOT NULL REFERENCES sessions(id), count INTEGER DEFAULT 0, count_update INTEGER DEFAULT 0, count_blacklist INTEGER DEFAULT 0, @@ -132,6 +148,6 @@ DROP TABLE IF EXISTS identities; CREATE TABLE identities ( id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, type INTEGER NOT NULL, - data BLOB NOT NULL, - UNIQUE (type, data) + value BLOB NOT NULL, + UNIQUE (type, value) ); diff --git a/src/libpts/pts/pts_database.c b/src/libpts/pts/pts_database.c index e0778aaefb..561db8686d 100644 --- a/src/libpts/pts/pts_database.c +++ b/src/libpts/pts/pts_database.c @@ -308,17 +308,21 @@ METHOD(pts_database_t, get_comp_measurement_count, status_t, METHOD(pts_database_t, destroy, void, private_pts_database_t *this) { - this->db->destroy(this->db); free(this); } /** * See header */ -pts_database_t *pts_database_create(char *uri) +pts_database_t *pts_database_create(imv_database_t *imv_db) { private_pts_database_t *this; + if (!imv_db) + { + return NULL; + } + INIT(this, .public = { .create_file_meas_enumerator = _create_file_meas_enumerator, @@ -333,17 +337,9 @@ pts_database_t *pts_database_create(char *uri) .get_comp_measurement_count = _get_comp_measurement_count, .destroy = _destroy, }, - .db = lib->db->create(lib->db, uri), + .db = imv_db->get_database(imv_db), ); - if (!this->db) - { - DBG1(DBG_PTS, - "failed to connect to PTS file measurement database '%s'", uri); - free(this); - return NULL; - } - return &this->public; } diff --git a/src/libpts/pts/pts_database.h b/src/libpts/pts/pts_database.h index 649ef0e31f..630342129c 100644 --- a/src/libpts/pts/pts_database.h +++ b/src/libpts/pts/pts_database.h @@ -25,6 +25,8 @@ typedef struct pts_database_t pts_database_t; #include "pts_meas_algo.h" #include "components/pts_comp_func_name.h" + +#include #include /** @@ -159,8 +161,8 @@ struct pts_database_t { /** * Creates an pts_database_t object * - * @param uri database uri + * @param imv_db Already attached IMV database */ -pts_database_t* pts_database_create(char *uri); +pts_database_t* pts_database_create(imv_database_t *imv_db); #endif /** PTS_DATABASE_H_ @}*/