diff options
Diffstat (limited to 'src/libimcv/imv/imv_policy_manager.c')
-rw-r--r-- | src/libimcv/imv/imv_policy_manager.c | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/src/libimcv/imv/imv_policy_manager.c b/src/libimcv/imv/imv_policy_manager.c new file mode 100644 index 000000000..61e0cd05b --- /dev/null +++ b/src/libimcv/imv/imv_policy_manager.c @@ -0,0 +1,359 @@ +/* + * 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 "imv_policy_manager_usage.h" +#include "imv_workitem.h" + +#include <library.h> +#include <utils/debug.h> + +#include <stdlib.h> +#include <stdio.h> +#include <time.h> + +/* The default policy group #1 is assumed to always exist */ +#define DEFAULT_GROUP_ID 1 + +/** + * global debug output variables + */ +static int debug_level = 1; +static bool stderr_quiet = FALSE; + +/** + * attest dbg function + */ +static void stderr_dbg(debug_t group, level_t level, char *fmt, ...) +{ + va_list args; + + if (level <= debug_level) + { + if (!stderr_quiet) + { + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + } + } +} + +/** + * Collect all enforcements by iterating up through parent groups + */ +static bool iterate_enforcements(database_t *db, int device_id, int session_id, + int group_id) +{ + int id, type, file, dir, arg_int, parent, policy, max_age; + int p_rec_fail, p_rec_noresult, e_rec_fail, e_rec_noresult, latest_rec; + bool latest_success; + char *argument; + time_t now; + enumerator_t *e, *e1, *e2; + + now = time(NULL); + + while (group_id) + { + e1 = db->query(db, + "SELECT e.id, p.type, p.argument, p.file, p.dir, p.rec_fail, " + "p.rec_noresult, e.policy, e.max_age, e.rec_fail, e.rec_noresult " + "FROM enforcements AS e JOIN policies as p ON e.policy = p.id " + "WHERE e.group_id = ?", DB_INT, group_id, + DB_INT, DB_INT, DB_TEXT, DB_INT, DB_INT, DB_INT, DB_INT, + DB_INT, DB_INT, DB_INT, DB_INT); + if (!e1) + { + return FALSE; + } + while (e1->enumerate(e1, &id, &type, &argument, &file, &dir, + &p_rec_fail, &p_rec_noresult, &policy, &max_age, + &e_rec_fail, &e_rec_noresult)) + { + /* check if the latest measurement of the device was successful */ + latest_success = FALSE; + + if (device_id) + { + e2 = db->query(db, + "SELECT r.rec FROM results AS r " + "JOIN sessions AS s ON s.id = r.session " + "WHERE r.policy = ? AND s.device = ? AND s.time > ? " + "ORDER BY s.time DESC", + DB_INT, policy, DB_INT, device_id, + DB_UINT, now - max_age, DB_INT); + if (!e2) + { + e1->destroy(e1); + return FALSE; + } + if (e2->enumerate(e2, &latest_rec) && + latest_rec == TNC_IMV_ACTION_RECOMMENDATION_ALLOW) + { + latest_success = TRUE; + } + e2->destroy(e2); + } + + if (latest_success) + { + /*skipping enforcement */ + printf("skipping enforcment %d\n", id); + continue; + } + + /* determine arg_int */ + switch ((imv_workitem_type_t)type) + { + case IMV_WORKITEM_FILE_REF_MEAS: + case IMV_WORKITEM_FILE_MEAS: + case IMV_WORKITEM_FILE_META: + arg_int = file; + break; + case IMV_WORKITEM_DIR_REF_MEAS: + case IMV_WORKITEM_DIR_MEAS: + case IMV_WORKITEM_DIR_META: + arg_int = dir; + break; + default: + arg_int = 0; + } + + /* insert a workitem */ + if (db->execute(db, NULL, + "INSERT INTO workitems (session, enforcement, type, arg_str, " + "arg_int, rec_fail, rec_noresult) VALUES (?, ?, ?, ?, ?, ?, ?)", + DB_INT, session_id, DB_INT, id, DB_INT, type, DB_TEXT, argument, + DB_INT, arg_int, DB_INT, e_rec_fail ? e_rec_fail : p_rec_fail, + DB_INT, e_rec_noresult ? e_rec_noresult : p_rec_noresult) != 1) + { + e1->destroy(e1); + fprintf(stderr, "could not insert workitem\n"); + return FALSE; + } + } + e1->destroy(e1); + + e = db->query(db, + "SELECT parent FROM groups WHERE id = ?", + DB_INT, group_id, DB_INT); + if (!e) + { + return FALSE; + } + if (e->enumerate(e, &parent)) + { + group_id = parent; + } + else + { + fprintf(stderr, "group information not found\n"); + group_id = 0; + } + e->destroy(e); + } + return TRUE; +} + +static bool policy_start(database_t *db, int session_id) +{ + enumerator_t *e; + int device_id, product_id, gid, group_id = DEFAULT_GROUP_ID; + u_int created; + + /* get session data */ + e = db->query(db, + "SELECT s.device, s.product, d.created FROM sessions AS s " + "LEFT JOIN devices AS d ON s.device = d.id WHERE s.id = ?", + DB_INT, session_id, DB_INT, DB_INT, DB_UINT); + if (!e || !e->enumerate(e, &device_id, &product_id, &created)) + { + DESTROY_IF(e); + fprintf(stderr, "session %d not found\n", session_id); + return FALSE; + } + e->destroy(e); + + /* if a device ID with a creation date exists, get all group memberships */ + if (device_id & created) + { + e = db->query(db, + "SELECT group_id FROM groups_members WHERE device_id = ?", + DB_INT, device_id, DB_INT); + if (!e) + { + return FALSE; + } + while (e->enumerate(e, &group_id)) + { + if (!iterate_enforcements(db, device_id, session_id, group_id)) + { + e->destroy(e); + return FALSE; + } + } + e->destroy(e); + + return TRUE; + } + + /* determine if a default product group exists */ + e = db->query(db, + "SELECT group_id FROM groups_product_defaults " + "WHERE product_id = ?", DB_INT, product_id, DB_INT); + if (!e) + { + return FALSE; + } + if (e->enumerate(e, &gid)) + { + group_id = gid; + } + e->destroy(e); + + if (device_id && !created) + { + /* assign a newly created device to a default group */ + if (db->execute(db, NULL, + "INSERT INTO groups_members (device_id, group_id) " + "VALUES (?, ?)", DB_INT, device_id, DB_INT, group_id) != 1) + { + fprintf(stderr, "could not assign device to a default group\n"); + return FALSE; + } + + /* set the creation date if it hasn't been set yet */ + if (db->execute(db, NULL, + "UPDATE devices SET created = ? WHERE id = ?", + DB_UINT, time(NULL), DB_INT, device_id) != 1) + { + fprintf(stderr, "creation date of device could not be set\n"); + return FALSE; + } + } + + return iterate_enforcements(db, device_id, session_id, group_id); +} + +static bool policy_stop(database_t *db, int session_id) +{ + enumerator_t *e; + int rec, policy; + char *result; + + e = db->query(db, + "SELECT w.rec_final, w.result, e.policy FROM workitems AS w " + "JOIN enforcements AS e ON w.enforcement = e.id " + "WHERE w.session = ? AND w.result IS NOT NULL", + DB_INT, session_id, DB_INT, DB_TEXT, DB_INT); + if (e) + { + while (e->enumerate(e, &rec, &result, &policy)) + { + db->execute(db, NULL, + "INSERT INTO results (session, policy, rec, result) " + "VALUES (?, ?, ?, ?)", DB_INT, session_id, DB_INT, policy, + DB_INT, rec, DB_TEXT, result); + } + e->destroy(e); + } + return db->execute(db, NULL, + "DELETE FROM workitems WHERE session = ?", + DB_UINT, session_id) >= 0; +} + +int main(int argc, char *argv[]) +{ + database_t *db; + char *uri, *tnc_session_id; + int session_id; + bool start, success; + + /* enable attest debugging hook */ + dbg = stderr_dbg; + + atexit(library_deinit); + + /* initialize library */ + if (!library_init(NULL)) + { + exit(SS_RC_LIBSTRONGSWAN_INTEGRITY); + } + if (!lib->plugins->load(lib->plugins, + lib->settings->get_str(lib->settings, "imv_policy_manager.load", + "sqlite"))) + { + exit(SS_RC_INITIALIZATION_FAILED); + } + + if (argc < 2) + { + usage(); + exit(SS_RC_INITIALIZATION_FAILED); + } + if (streq(argv[1], "start")) + { + start = TRUE; + } + else if (streq(argv[1], "stop")) + { + start = FALSE; + } + else + { + usage(); + exit(SS_RC_INITIALIZATION_FAILED); + } + + /* get session ID */ + tnc_session_id = getenv("TNC_SESSION_ID"); + if (!tnc_session_id) + { + fprintf(stderr, "environment variable TNC_SESSION_ID is not defined\n"); + exit(SS_RC_INITIALIZATION_FAILED); + } + session_id = atoi(tnc_session_id); + + /* attach IMV database */ + uri = lib->settings->get_str(lib->settings, "libimcv.database", NULL); + if (!uri) + { + fprintf(stderr, "database uri not defined.\n"); + exit(SS_RC_INITIALIZATION_FAILED); + } + + db = lib->db->create(lib->db, uri); + if (!db) + { + fprintf(stderr, "opening database failed.\n"); + exit(SS_RC_INITIALIZATION_FAILED); + } + + if (start) + { + success = policy_start(db, session_id); + } + else + { + success = policy_stop(db, session_id); + } + db->destroy(db); + + fprintf(stderr, "imv_policy_manager %s %s\n", start ? "start" : "stop", + success ? "successful" : "failed"); + + exit(EXIT_SUCCESS); +} |