File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / sw-collector / sw_collector_db.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 09:46:44 2020 UTC (4 years, 3 months ago) by misho
Branches: strongswan, MAIN
CVS tags: v5_9_2p0, v5_8_4p7, HEAD
Strongswan

    1: /*
    2:  * Copyright (C) 2017 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: #include <sys/types.h>
   18: #include <sys/stat.h>
   19: #include <unistd.h>
   20: #include <time.h>
   21: 
   22: #include "sw_collector_db.h"
   23: 
   24: #include "swima/swima_event.h"
   25: 
   26: typedef struct private_sw_collector_db_t private_sw_collector_db_t;
   27: 
   28: /**
   29:  * Private data of an sw_collector_db_t object.
   30:  */
   31: struct private_sw_collector_db_t {
   32: 
   33: 	/**
   34: 	 * Public members of sw_collector_db_state_t
   35: 	 */
   36: 	sw_collector_db_t public;
   37: 
   38: 	/**
   39: 	 * Epoch
   40: 	 */
   41: 	uint32_t epoch;
   42: 
   43: 	/**
   44: 	 * Event ID of last event stored in database
   45: 	 */
   46: 	uint32_t last_eid;
   47: 
   48: 	/**
   49: 	 * Software collector database
   50: 	 */
   51: 	database_t *db;
   52: 
   53: };
   54: 
   55: METHOD(sw_collector_db_t, add_event, uint32_t,
   56: 	private_sw_collector_db_t *this, char *timestamp)
   57: {
   58: 	uint32_t eid = 0;
   59: 
   60: 	if (this->db->execute(this->db, &eid,
   61: 			"INSERT INTO events (epoch, timestamp) VALUES (?, ?)",
   62: 			 DB_UINT, this->epoch, DB_TEXT, timestamp) != 1)
   63: 	{
   64: 		DBG1(DBG_IMC, "unable to insert event into database");
   65: 		return 0;
   66: 	}
   67: 
   68: 	return eid;
   69: }
   70: 
   71: METHOD(sw_collector_db_t, get_last_event, bool,
   72: 	private_sw_collector_db_t *this, uint32_t *eid, uint32_t *epoch,
   73: 	char **last_time)
   74: {
   75: 	char *timestamp;
   76: 	enumerator_t *e;
   77: 
   78: 	e = this->db->query(this->db,
   79: 			"SELECT id, epoch, timestamp FROM events ORDER BY timestamp DESC",
   80: 			DB_UINT, DB_UINT, DB_TEXT);
   81: 	if (!e)
   82: 	{
   83: 		DBG1(DBG_IMC, "database query for event failed");
   84: 		return FALSE;
   85: 	}
   86: 	if (e->enumerate(e, eid, epoch, &timestamp))
   87: 	{
   88: 		if (last_time)
   89: 		{
   90: 			*last_time = strdup(timestamp);
   91: 		}
   92: 	}
   93: 	else
   94: 	{
   95: 		*eid = 0;
   96: 	}
   97: 	e->destroy(e);
   98: 
   99: 	return TRUE;
  100: }
  101: 
  102: METHOD(sw_collector_db_t, add_sw_event, bool,
  103: 	private_sw_collector_db_t *this, uint32_t eid, uint32_t sw_id,
  104: 	uint8_t action)
  105: {
  106: 	if (this->db->execute(this->db, NULL,
  107: 			"INSERT INTO sw_events (eid, sw_id, action) VALUES (?, ?, ?)",
  108: 			 DB_UINT, eid, DB_UINT, sw_id, DB_UINT, action) != 1)
  109: 	{
  110: 		DBG1(DBG_IMC, "unable to insert sw_event into database");
  111: 		return FALSE;
  112: 	}
  113: 
  114: 	return TRUE;
  115: }
  116: 
  117: METHOD(sw_collector_db_t, set_sw_id, uint32_t,
  118: 	private_sw_collector_db_t *this, char *name,  char *package, char *version,
  119: 	uint8_t source, bool installed)
  120: {
  121: 	uint32_t sw_id;
  122: 
  123: 	if (this->db->execute(this->db, &sw_id,
  124: 			"INSERT INTO sw_identifiers "
  125: 			"(name, package, version, source, installed) VALUES (?, ?, ?, ?, ?)",
  126: 			 DB_TEXT, name, DB_TEXT, package, DB_TEXT, version, DB_UINT, source,
  127: 			 DB_UINT, installed) != 1)
  128: 	{
  129: 		DBG1(DBG_IMC, "unable to insert sw_id into database");
  130: 		return 0;
  131: 	}
  132: 
  133: 	return sw_id;
  134: }
  135: 
  136: METHOD(sw_collector_db_t, get_sw_id, uint32_t,
  137: 	private_sw_collector_db_t *this, char *name, char **package, char **version,
  138: 	uint8_t *source, bool *installed)
  139: {
  140: 	char *sw_package, *sw_version;
  141: 	uint32_t sw_id = 0, sw_source, sw_installed;
  142: 	enumerator_t *e;
  143: 
  144: 	/* Does software identifier already exist in database? */
  145: 	e = this->db->query(this->db,
  146: 			"SELECT id, package, version, source, installed "
  147: 			"FROM sw_identifiers WHERE name = ?",
  148: 			DB_TEXT, name, DB_UINT, DB_TEXT, DB_TEXT, DB_UINT, DB_UINT);
  149: 	if (!e)
  150: 	{
  151: 		DBG1(DBG_IMC, "database query for sw_identifier failed");
  152: 		return 0;
  153: 	}
  154: 	if (e->enumerate(e, &sw_id, &sw_package, &sw_version, &sw_source,
  155: 						&sw_installed))
  156: 	{
  157: 		if (package)
  158: 		{
  159: 			*package = strdup(sw_package);
  160: 		}
  161: 		if (version)
  162: 		{
  163: 			*version = strdup(sw_version);
  164: 		}
  165: 		if (source)
  166: 		{
  167: 			*source = sw_source;
  168: 		}
  169: 		if (installed)
  170: 		{
  171: 			*installed = sw_installed;
  172: 		}
  173: 	}
  174: 	e->destroy(e);
  175: 
  176: 	return sw_id;
  177: }
  178: 
  179: METHOD(sw_collector_db_t, get_sw_id_count, uint32_t,
  180: 	private_sw_collector_db_t *this, sw_collector_db_query_t type)
  181: {
  182: 	uint32_t count, installed;
  183: 	enumerator_t *e;
  184: 
  185: 	if (type == SW_QUERY_ALL)
  186: 	{
  187: 		e = this->db->query(this->db,
  188: 			"SELECT COUNT(installed) FROM sw_identifiers", DB_UINT);
  189: 	}
  190: 	else
  191: 	{
  192: 		installed = (type == SW_QUERY_INSTALLED);
  193: 		e = this->db->query(this->db,
  194: 			"SELECT COUNT(installed) FROM sw_identifiers WHERE installed = ?",
  195: 			 DB_UINT, installed, DB_UINT);
  196: 	}
  197: 
  198: 	if (!e)
  199: 	{
  200: 		DBG1(DBG_IMC, "database query for sw_identifier count failed");
  201: 		return 0;
  202: 	}
  203: 	if (!e->enumerate(e, &count))
  204: 	{
  205: 		count = 0;
  206: 	}
  207: 	e->destroy(e);
  208: 
  209: 	return count;
  210: }
  211: 
  212: METHOD(sw_collector_db_t, update_sw_id, bool,
  213: 	private_sw_collector_db_t *this, uint32_t sw_id, char *name, char *version,
  214: 	bool installed)
  215: {
  216: 	int res;
  217: 
  218: 	if (name && version)
  219: 	{
  220: 		res = this->db->execute(this->db, NULL,
  221: 			"UPDATE sw_identifiers SET name = ?, version = ?, installed = ? "
  222: 			"WHERE id = ?", DB_TEXT, name, DB_TEXT, version, DB_UINT, installed,
  223: 			 DB_UINT, sw_id);
  224: 	}
  225: 	else
  226: 	{
  227: 		res = this->db->execute(this->db, NULL,
  228: 			"UPDATE sw_identifiers SET installed = ? WHERE id = ?",
  229: 			 DB_UINT, installed, DB_UINT, sw_id);
  230: 	}
  231: 	if (res != 1)
  232: 	{
  233: 		DBG1(DBG_IMC, "unable to update software identifier in database");
  234: 		return FALSE;
  235: 	}
  236: 	return TRUE;
  237: }
  238: 
  239: METHOD(sw_collector_db_t, update_package, int,
  240: 	private_sw_collector_db_t *this, char *package_filter, char *package)
  241: {
  242: 	int count;
  243: 
  244: 	count = this->db->execute(this->db, NULL,
  245: 			"UPDATE sw_identifiers SET package = ? WHERE package LIKE ?",
  246: 			 DB_TEXT, package, DB_TEXT, package_filter);
  247: 	if (count < 0)
  248: 	{
  249: 		DBG1(DBG_IMC, "unable to update package name in database");
  250: 	}
  251: 
  252: 	return count;
  253: }
  254: 
  255: METHOD(sw_collector_db_t, create_sw_enumerator, enumerator_t*,
  256: 	private_sw_collector_db_t *this, sw_collector_db_query_t type, char *package)
  257: {
  258: 	enumerator_t *e;
  259: 	u_int installed;
  260: 
  261: 	if (type == SW_QUERY_ALL)
  262: 	{
  263: 		if (package)
  264: 		{
  265: 			e = this->db->query(this->db,
  266: 				"SELECT id, name, package, version, installed "
  267: 				"FROM sw_identifiers WHERE package = ? ORDER BY name ASC",
  268: 				 DB_TEXT, package, DB_UINT, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
  269: 		}
  270: 		else
  271: 		{
  272: 			e = this->db->query(this->db,
  273: 				"SELECT id, name, package, version, installed "
  274: 				"FROM sw_identifiers ORDER BY name ASC",
  275: 				 DB_UINT, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
  276: 		}
  277: 	}
  278: 	else
  279: 	{
  280: 		installed = (type == SW_QUERY_INSTALLED);
  281: 
  282: 		if (package)
  283: 		{
  284: 			e = this->db->query(this->db,
  285: 				"SELECT id, name, package, version, installed "
  286: 				"FROM sw_identifiers WHERE package = ? AND installed = ? "
  287: 				"ORDER BY name ASC", DB_TEXT, package, DB_UINT, installed,
  288: 				 DB_UINT, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
  289: 		}
  290: 		else
  291: 		{
  292: 			e = this->db->query(this->db,
  293: 				"SELECT id, name, package, version, installed "
  294: 				"FROM sw_identifiers WHERE installed = ? ORDER BY name ASC",
  295: 				 DB_UINT, installed, DB_UINT, DB_TEXT, DB_TEXT, DB_TEXT, DB_UINT);
  296: 		}
  297: 	}
  298: 	if (!e)
  299: 	{
  300: 		DBG1(DBG_IMC, "database query for sw_identifier count failed");
  301: 		return NULL;
  302: 	}
  303: 
  304: 	return e;
  305: }
  306: 
  307: METHOD(sw_collector_db_t, destroy, void,
  308: 	private_sw_collector_db_t *this)
  309: {
  310: 	this->db->destroy(this->db);
  311: 	free(this);
  312: }
  313: 
  314: /**
  315:  * Determine file creation data and convert it into RFC 3339 format
  316:  */
  317: bool get_file_creation_date(char *pathname, char *timestamp)
  318: {
  319: 	struct stat st;
  320: 	struct tm ct;
  321: 
  322: 	if (stat(pathname, &st))
  323: 	{
  324: 		DBG1(DBG_IMC, "unable to obtain statistics on '%s'", pathname);
  325: 		return FALSE;
  326: 	}
  327: 
  328: 	/* Convert from local time to UTC */
  329: 	gmtime_r(&st.st_mtime, &ct);
  330: 	ct.tm_year += 1900;
  331: 	ct.tm_mon += 1;
  332: 
  333: 	/* Form timestamp according to RFC 3339 (20 characters) */
  334: 	snprintf(timestamp, 21, "%4d-%02d-%02dT%02d:%02d:%02dZ",
  335: 			 ct.tm_year, ct.tm_mon, ct.tm_mday,
  336: 			 ct.tm_hour, ct.tm_min, ct.tm_sec);
  337: 
  338: 	return TRUE;
  339: }
  340: 
  341: /**
  342:  * Described in header.
  343:  */
  344: sw_collector_db_t *sw_collector_db_create(char *uri)
  345: {
  346: 	private_sw_collector_db_t *this;
  347: 	uint32_t first_eid, last_eid;
  348: 	char first_time_buf[21], *first_time, *first_file;
  349: 
  350: 	INIT(this,
  351: 		.public = {
  352: 			.add_event = _add_event,
  353: 			.get_last_event = _get_last_event,
  354: 			.add_sw_event = _add_sw_event,
  355: 			.set_sw_id = _set_sw_id,
  356: 			.get_sw_id = _get_sw_id,
  357: 			.get_sw_id_count = _get_sw_id_count,
  358: 			.update_sw_id = _update_sw_id,
  359: 			.update_package = _update_package,
  360: 			.create_sw_enumerator = _create_sw_enumerator,
  361: 			.destroy = _destroy,
  362: 		},
  363: 		.db = lib->db->create(lib->db, uri),
  364: 	);
  365: 
  366: 	if (!this->db)
  367: 	{
  368: 		DBG1(DBG_IMC, "opening database URI '%s' failed", uri);
  369: 		free(this);
  370: 		return NULL;
  371: 	}
  372: 
  373: 	/* Retrieve last event in database */
  374: 	if (!get_last_event(this, &last_eid, &this->epoch, NULL))
  375: 	{
  376: 		destroy(this);
  377: 		return NULL;
  378: 	}
  379: 
  380: 	/* Create random epoch and first event if no events exist yet */
  381: 	if (!last_eid)
  382: 	{
  383: 		rng_t *rng;
  384: 
  385: 		rng = lib->crypto->create_rng(lib->crypto, RNG_STRONG);
  386: 		if (!rng ||
  387: 			!rng->get_bytes(rng, sizeof(uint32_t), (uint8_t*)&this->epoch))
  388: 		{
  389: 			DESTROY_IF(rng);
  390: 			destroy(this);
  391: 			DBG1(DBG_IMC, "generating random epoch value failed");
  392: 			return NULL;
  393: 		}
  394: 		rng->destroy(rng);
  395: 
  396: 		/* strongTNC workaround - limit epoch to 31 bit unsigned integer */
  397: 		this->epoch &= 0x7fffffff;
  398: 
  399: 		/* Create first event when the OS was installed */
  400: 		first_file = lib->settings->get_str(lib->settings,
  401: 						"sw-collector.first_file", "/var/log/bootstrap.log");
  402: 		first_time = lib->settings->get_str(lib->settings,
  403: 						"sw-collector.first_time", NULL);
  404: 		if (!first_time)
  405: 		{
  406: 			if (get_file_creation_date(first_file, first_time_buf))
  407: 			{
  408: 				first_time = first_time_buf;
  409: 			}
  410: 			else
  411: 			{
  412: 				first_time = "0000-00-00T00:00:00Z";
  413: 			}
  414: 		}
  415: 		first_eid = add_event(this, first_time);
  416: 
  417: 		if (!first_eid)
  418: 		{
  419: 			destroy(this);
  420: 			return NULL;
  421: 		}
  422: 		DBG0(DBG_IMC, "First-Date: %s, eid = %u, epoch = %u",
  423: 					   first_time, first_eid, this->epoch);
  424: 	}
  425: 
  426: 	return &this->public;
  427: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>