Annotation of embedaddon/strongswan/src/libimcv/imv/imv_database.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2013-2015 Andreas Steffen
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16: #define _GNU_SOURCE
! 17:
! 18: #include <stdio.h>
! 19: #include <stdarg.h>
! 20: #include <string.h>
! 21: #include <time.h>
! 22:
! 23: #include "imv_database.h"
! 24:
! 25: #include <tncif_identity.h>
! 26:
! 27: #include <utils/debug.h>
! 28: #include <threading/mutex.h>
! 29:
! 30: typedef struct private_imv_database_t private_imv_database_t;
! 31:
! 32: /**
! 33: * Private data of a imv_database_t object.
! 34: */
! 35: struct private_imv_database_t {
! 36:
! 37: /**
! 38: * Public imv_database_t interface.
! 39: */
! 40: imv_database_t public;
! 41:
! 42: /**
! 43: * database instance
! 44: */
! 45: database_t *db;
! 46:
! 47: /**
! 48: * policy script
! 49: */
! 50: char *script;
! 51:
! 52: };
! 53:
! 54: METHOD(imv_database_t, get_database, database_t*,
! 55: private_imv_database_t *this)
! 56: {
! 57: return this->db;
! 58: }
! 59:
! 60: /**
! 61: * Create a session entry in the IMV database
! 62: */
! 63: static bool create_session(private_imv_database_t *this, imv_session_t *session)
! 64: {
! 65: enumerator_t *enumerator, *e;
! 66: imv_os_info_t *os_info;
! 67: chunk_t device_id;
! 68: tncif_identity_t *tnc_id;
! 69: TNC_ConnectionID conn_id;
! 70: char *product, *device;
! 71: int session_id = 0, pid = 0, did = 0, trusted = 0, created;
! 72: bool first = TRUE, success = TRUE;
! 73:
! 74: /* get product info string */
! 75: os_info = session->get_os_info(session);
! 76: product = os_info->get_info(os_info);
! 77: if (!product)
! 78: {
! 79: DBG1(DBG_IMV, "imv_db: product info is not available");
! 80: return FALSE;
! 81: }
! 82:
! 83: /* get primary key of product info string if it exists */
! 84: e = this->db->query(this->db,
! 85: "SELECT id FROM products WHERE name = ?", DB_TEXT, product, DB_INT);
! 86: if (e)
! 87: {
! 88: e->enumerate(e, &pid);
! 89: e->destroy(e);
! 90: }
! 91:
! 92: /* if product info string has not been found - register it */
! 93: if (!pid)
! 94: {
! 95: this->db->execute(this->db, &pid,
! 96: "INSERT INTO products (name) VALUES (?)", DB_TEXT, product);
! 97: }
! 98:
! 99: if (!pid)
! 100: {
! 101: DBG1(DBG_IMV, "imv_db: registering product info failed");
! 102: return FALSE;
! 103: }
! 104:
! 105: /* get device ID string */
! 106: if (!session->get_device_id(session, &device_id))
! 107: {
! 108: DBG1(DBG_IMV, "imv_db: device ID is not available");
! 109: return FALSE;
! 110: }
! 111: device = strndup(device_id.ptr, device_id.len);
! 112:
! 113: /* get primary key of device ID if it exists */
! 114: e = this->db->query(this->db,
! 115: "SELECT id, trusted FROM devices WHERE value = ? AND product = ?",
! 116: DB_TEXT, device, DB_INT, pid, DB_INT, DB_INT);
! 117: if (e)
! 118: {
! 119: e->enumerate(e, &did, &trusted);
! 120: e->destroy(e);
! 121: }
! 122:
! 123: /* if device ID is trusted, set trust in session */
! 124: if (trusted)
! 125: {
! 126: session->set_device_trust(session, TRUE);
! 127: }
! 128:
! 129: /* if device ID has not been found - register it */
! 130: if (!did)
! 131: {
! 132: this->db->execute(this->db, &did,
! 133: "INSERT INTO devices "
! 134: "(value, description, product, trusted, inactive) "
! 135: "VALUES (?, '', ?, 0, 0)", DB_TEXT, device, DB_INT, pid);
! 136: }
! 137: free(device);
! 138:
! 139: if (!did)
! 140: {
! 141: DBG1(DBG_IMV, "imv_db: registering device ID failed");
! 142: return FALSE;
! 143: }
! 144:
! 145: /* create a new session entry */
! 146: created = time(NULL);
! 147: conn_id = session->get_connection_id(session);
! 148: this->db->execute(this->db, &session_id,
! 149: "INSERT INTO sessions (time, connection, product, device) "
! 150: "VALUES (?, ?, ?, ?)",
! 151: DB_INT, created, DB_INT, conn_id, DB_INT, pid, DB_INT, did);
! 152:
! 153: if (session_id)
! 154: {
! 155: DBG2(DBG_IMV, "assigned session ID %d to Connection ID %d",
! 156: session_id, conn_id);
! 157: }
! 158: else
! 159: {
! 160: DBG1(DBG_IMV, "imv_db: registering session failed");
! 161: return FALSE;
! 162: }
! 163: session->set_session_id(session, session_id, pid, did);
! 164: session->set_creation_time(session, created);
! 165:
! 166: enumerator = session->create_ar_identities_enumerator(session);
! 167: while (enumerator->enumerate(enumerator, &tnc_id))
! 168: {
! 169: pen_type_t ar_id_type;
! 170: chunk_t ar_id_value;
! 171: int ar_id = 0, si_id = 0;
! 172:
! 173: ar_id_type = tnc_id->get_identity_type(tnc_id);
! 174: ar_id_value = tnc_id->get_identity_value(tnc_id);
! 175:
! 176: if (ar_id_type.vendor_id != PEN_TCG || ar_id_value.len == 0)
! 177: {
! 178: continue;
! 179: }
! 180:
! 181: /* get primary key of AR identity if it exists */
! 182: e = this->db->query(this->db,
! 183: "SELECT id FROM identities WHERE type = ? AND value = ?",
! 184: DB_INT, ar_id_type.type, DB_BLOB, ar_id_value, DB_INT);
! 185: if (e)
! 186: {
! 187: e->enumerate(e, &ar_id);
! 188: e->destroy(e);
! 189: }
! 190:
! 191: /* if AR identity has not been found - register it */
! 192: if (!ar_id)
! 193: {
! 194: this->db->execute(this->db, &ar_id,
! 195: "INSERT INTO identities (type, value) VALUES (?, ?)",
! 196: DB_INT, ar_id_type.type, DB_BLOB, ar_id_value);
! 197: }
! 198: if (!ar_id)
! 199: {
! 200: DBG1(DBG_IMV, "imv_db: registering access requestor failed");
! 201: success = FALSE;
! 202: break;
! 203: }
! 204:
! 205: this->db->execute(this->db, &si_id,
! 206: "INSERT INTO sessions_identities (session_id, identity_id) "
! 207: "VALUES (?, ?)",
! 208: DB_INT, session_id, DB_INT, ar_id);
! 209:
! 210: if (!si_id)
! 211: {
! 212: DBG1(DBG_IMV, "imv_db: assigning identity to session failed");
! 213: success = FALSE;
! 214: break;
! 215: }
! 216:
! 217: if (first)
! 218: {
! 219: this->db->execute(this->db, NULL,
! 220: "UPDATE sessions SET identity = ? WHERE id = ?",
! 221: DB_INT, ar_id, DB_INT, session_id);
! 222: first = FALSE;
! 223: }
! 224: }
! 225: enumerator->destroy(enumerator);
! 226:
! 227: return success;
! 228: }
! 229:
! 230: static bool add_workitems(private_imv_database_t *this, imv_session_t *session)
! 231: {
! 232: char *arg_str;
! 233: int id, arg_int, rec_fail, rec_noresult;
! 234: imv_workitem_t *workitem;
! 235: imv_workitem_type_t type;
! 236: enumerator_t *e;
! 237:
! 238: e = this->db->query(this->db,
! 239: "SELECT id, type, arg_str, arg_int, rec_fail, rec_noresult "
! 240: "FROM workitems WHERE session = ?",
! 241: DB_INT, session->get_session_id(session, NULL, NULL),
! 242: DB_INT, DB_INT, DB_TEXT, DB_INT,DB_INT, DB_INT);
! 243: if (!e)
! 244: {
! 245: DBG1(DBG_IMV, "imv_db: no workitem enumerator returned");
! 246: return FALSE;
! 247: }
! 248: while (e->enumerate(e, &id, &type, &arg_str, &arg_int, &rec_fail,
! 249: &rec_noresult))
! 250: {
! 251: DBG2(DBG_IMV, "%N workitem %d", imv_workitem_type_names, type, id);
! 252: workitem = imv_workitem_create(id, type, arg_str, arg_int, rec_fail,
! 253: rec_noresult);
! 254: session->insert_workitem(session, workitem);
! 255: }
! 256: e->destroy(e);
! 257:
! 258: return TRUE;
! 259: }
! 260:
! 261: METHOD(imv_database_t, add_recommendation, void,
! 262: private_imv_database_t *this, imv_session_t *session,
! 263: TNC_IMV_Action_Recommendation rec)
! 264: {
! 265: /* add final recommendation to session DB entry */
! 266: this->db->execute(this->db, NULL,
! 267: "UPDATE sessions SET rec = ? WHERE id = ?",
! 268: DB_INT, rec, DB_INT, session->get_session_id(session, NULL, NULL));
! 269: }
! 270:
! 271: METHOD(imv_database_t, policy_script, bool,
! 272: private_imv_database_t *this, imv_session_t *session, bool start)
! 273: {
! 274: char command[512], resp[128], *last;
! 275: FILE *shell;
! 276:
! 277: if (start)
! 278: {
! 279: if (session->get_policy_started(session))
! 280: {
! 281: DBG1(DBG_IMV, "policy script as already been started");
! 282: return FALSE;
! 283: }
! 284:
! 285: /* add product info and device ID to session DB entry */
! 286: if (!create_session(this, session))
! 287: {
! 288: return FALSE;
! 289: }
! 290: }
! 291: else
! 292: {
! 293: if (!session->get_policy_started(session))
! 294: {
! 295: DBG1(DBG_IMV, "policy script as already been stopped");
! 296: return FALSE;
! 297: }
! 298: }
! 299:
! 300: /* call the policy script */
! 301: snprintf(command, sizeof(command), "2>&1 %s %s %d",
! 302: this->script, start ? "start" : "stop",
! 303: session->get_session_id(session, NULL, NULL));
! 304: DBG3(DBG_IMV, "running policy script: %s", command);
! 305:
! 306: shell = popen(command, "r");
! 307: if (shell == NULL)
! 308: {
! 309: DBG1(DBG_IMV, "could not execute policy script '%s'",
! 310: this->script);
! 311: return FALSE;
! 312: }
! 313: while (TRUE)
! 314: {
! 315: if (fgets(resp, sizeof(resp), shell) == NULL)
! 316: {
! 317: if (ferror(shell))
! 318: {
! 319: DBG1(DBG_IMV, "error reading output from policy script");
! 320: }
! 321: break;
! 322: }
! 323: else
! 324: {
! 325: last = resp + strlen(resp) - 1;
! 326: if (last >= resp && *last == '\n')
! 327: {
! 328: /* replace trailing '\n' */
! 329: *last = '\0';
! 330: }
! 331: DBG1(DBG_IMV, "policy: %s", resp);
! 332: }
! 333: }
! 334: pclose(shell);
! 335:
! 336: if (start)
! 337: {
! 338: /* add workitem list generated by policy manager to session object */
! 339: if (!add_workitems(this, session))
! 340: {
! 341: return FALSE;
! 342: }
! 343: session->set_policy_started(session, TRUE);
! 344: }
! 345: else
! 346: {
! 347: session->set_policy_started(session, FALSE);
! 348: }
! 349:
! 350: return TRUE;
! 351: }
! 352:
! 353: METHOD(imv_database_t, finalize_workitem, bool,
! 354: private_imv_database_t *this, imv_workitem_t *workitem)
! 355: {
! 356: char *result;
! 357: int rec;
! 358:
! 359: rec = workitem->get_result(workitem, &result);
! 360:
! 361: return this->db->execute(this->db, NULL,
! 362: "UPDATE workitems SET result = ?, rec_final = ? WHERE id = ?",
! 363: DB_TEXT, result, DB_INT, rec,
! 364: DB_INT, workitem->get_id(workitem)) == 1;
! 365: }
! 366:
! 367: METHOD(imv_database_t, destroy, void,
! 368: private_imv_database_t *this)
! 369: {
! 370: DESTROY_IF(this->db);
! 371: free(this);
! 372: }
! 373:
! 374: /**
! 375: * See header
! 376: */
! 377: imv_database_t *imv_database_create(char *uri, char *script)
! 378: {
! 379: private_imv_database_t *this;
! 380:
! 381: INIT(this,
! 382: .public = {
! 383: .get_database = _get_database,
! 384: .policy_script = _policy_script,
! 385: .finalize_workitem = _finalize_workitem,
! 386: .add_recommendation = _add_recommendation,
! 387: .destroy = _destroy,
! 388: },
! 389: .db = lib->db->create(lib->db, uri),
! 390: .script = script,
! 391: );
! 392:
! 393: if (!this->db)
! 394: {
! 395: DBG1(DBG_IMV,
! 396: "failed to connect to IMV database '%s'", uri);
! 397: destroy(this);
! 398: return NULL;
! 399: }
! 400:
! 401: return &this->public;
! 402: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>