Separated IMV session management from IMV policy database
This commit is contained in:
@@ -0,0 +1,562 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 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 "imc_os_info.h"
|
||||
|
||||
#include <sys/utsname.h>
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <collections/linked_list.h>
|
||||
#include <utils/debug.h>
|
||||
|
||||
typedef struct private_imc_os_info_t private_imc_os_info_t;
|
||||
|
||||
/**
|
||||
* Private data of an imc_os_info_t object.
|
||||
*
|
||||
*/
|
||||
struct private_imc_os_info_t {
|
||||
|
||||
/**
|
||||
* Public imc_os_info_t interface.
|
||||
*/
|
||||
imc_os_info_t public;
|
||||
|
||||
/**
|
||||
* OS type
|
||||
*/
|
||||
os_type_t type;
|
||||
|
||||
/**
|
||||
* OS name
|
||||
*/
|
||||
chunk_t name;
|
||||
|
||||
/**
|
||||
* OS version
|
||||
*/
|
||||
chunk_t version;
|
||||
|
||||
};
|
||||
|
||||
METHOD(imc_os_info_t, get_type, os_type_t,
|
||||
private_imc_os_info_t *this)
|
||||
{
|
||||
return this->type;
|
||||
}
|
||||
|
||||
METHOD(imc_os_info_t, get_name, chunk_t,
|
||||
private_imc_os_info_t *this)
|
||||
{
|
||||
return this->name;
|
||||
}
|
||||
|
||||
METHOD(imc_os_info_t, get_numeric_version, void,
|
||||
private_imc_os_info_t *this, u_int32_t *major, u_int32_t *minor)
|
||||
{
|
||||
u_char *pos;
|
||||
|
||||
if (major)
|
||||
{
|
||||
*major = atol(this->version.ptr);
|
||||
}
|
||||
pos = memchr(this->version.ptr, '.', this->version.len);
|
||||
if (minor)
|
||||
{
|
||||
*minor = pos ? atol(pos + 1) : 0;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(imc_os_info_t, get_version, chunk_t,
|
||||
private_imc_os_info_t *this)
|
||||
{
|
||||
return this->version;
|
||||
}
|
||||
|
||||
METHOD(imc_os_info_t, get_fwd_status, os_fwd_status_t,
|
||||
private_imc_os_info_t *this)
|
||||
{
|
||||
const char ip_forward[] = "/proc/sys/net/ipv4/ip_forward";
|
||||
char buf[2];
|
||||
FILE *file;
|
||||
|
||||
os_fwd_status_t fwd_status = OS_FWD_UNKNOWN;
|
||||
|
||||
file = fopen(ip_forward, "r");
|
||||
if (file)
|
||||
{
|
||||
if (fread(buf, 1, 1, file) == 1)
|
||||
{
|
||||
switch (buf[0])
|
||||
{
|
||||
case '0':
|
||||
fwd_status = OS_FWD_DISABLED;
|
||||
break;
|
||||
case '1':
|
||||
fwd_status = OS_FWD_ENABLED;
|
||||
break;
|
||||
default:
|
||||
DBG1(DBG_IMC, "\"%s\" returns invalid value ", ip_forward);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IMC, "could not read from \"%s\"", ip_forward);
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to open \"%s\"", ip_forward);
|
||||
}
|
||||
|
||||
return fwd_status;
|
||||
}
|
||||
|
||||
METHOD(imc_os_info_t, get_uptime, time_t,
|
||||
private_imc_os_info_t *this)
|
||||
{
|
||||
const char proc_uptime[] = "/proc/uptime";
|
||||
FILE *file;
|
||||
u_int 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(imc_os_info_t, get_setting, chunk_t,
|
||||
private_imc_os_info_t *this, char *name)
|
||||
{
|
||||
FILE *file;
|
||||
u_char buf[2048];
|
||||
size_t i = 0;
|
||||
chunk_t value;
|
||||
|
||||
if (!strpfx(name, "/etc/") && !strpfx(name, "/proc/") &&
|
||||
!strpfx(name, "/sys/") && !strpfx(name, "/var/"))
|
||||
{
|
||||
/**
|
||||
* In order to guarantee privacy, only settings from the
|
||||
* /etc/, /proc/ and /sys/ directories can be retrieved
|
||||
*/
|
||||
DBG1(DBG_IMC, "not allowed to access '%s'", name);
|
||||
|
||||
return chunk_empty;
|
||||
}
|
||||
|
||||
file = fopen(name, "r");
|
||||
if (!file)
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to open '%s'", name);
|
||||
|
||||
return chunk_empty;
|
||||
}
|
||||
while (i < sizeof(buf) && fread(buf + i, 1, 1, file) == 1)
|
||||
{
|
||||
i++;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
value = chunk_create(buf, i);
|
||||
|
||||
return chunk_clone(value);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
/**
|
||||
* implements enumerator_t
|
||||
*/
|
||||
enumerator_t public;
|
||||
|
||||
/**
|
||||
* package info pipe stream
|
||||
*/
|
||||
FILE* file;
|
||||
|
||||
/**
|
||||
* line buffer
|
||||
*/
|
||||
u_char line[512];
|
||||
|
||||
} package_enumerator_t;
|
||||
|
||||
/**
|
||||
* Implementation of package_enumerator.destroy.
|
||||
*/
|
||||
static void package_enumerator_destroy(package_enumerator_t *this)
|
||||
{
|
||||
pclose(this->file);
|
||||
free(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of package_enumerator.enumerate
|
||||
*/
|
||||
static bool package_enumerator_enumerate(package_enumerator_t *this, ...)
|
||||
{
|
||||
chunk_t *name, *version;
|
||||
u_char *pos;
|
||||
va_list args;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
if (!fgets(this->line, sizeof(this->line), this->file))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
pos = strchr(this->line, '\t');
|
||||
if (!pos)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
*pos++ = '\0';
|
||||
|
||||
if (!streq(this->line, "install ok installed"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
va_start(args, this);
|
||||
|
||||
name = va_arg(args, chunk_t*);
|
||||
name->ptr = pos;
|
||||
pos = strchr(pos, '\t');
|
||||
if (!pos)
|
||||
{
|
||||
va_end(args);
|
||||
return FALSE;
|
||||
}
|
||||
name->len = pos++ - name->ptr;
|
||||
|
||||
version = va_arg(args, chunk_t*);
|
||||
version->ptr = pos;
|
||||
version->len = strlen(pos) - 1;
|
||||
|
||||
va_end(args);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
METHOD(imc_os_info_t, create_package_enumerator, enumerator_t*,
|
||||
private_imc_os_info_t *this)
|
||||
{
|
||||
FILE *file;
|
||||
const char command[] = "dpkg-query --show --showformat="
|
||||
"'${Status}\t${Package}\t${Version}\n'";
|
||||
package_enumerator_t *enumerator;
|
||||
|
||||
/* Only Debian and Ubuntu package enumeration is currently supported */
|
||||
if (this->type != OS_TYPE_DEBIAN && this->type != OS_TYPE_UBUNTU)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Open a pipe stream for reading the output of the dpkg-query commmand */
|
||||
file = popen(command, "r");
|
||||
if (!file)
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to run dpkg command");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Create a package enumerator instance */
|
||||
enumerator = malloc_thing(package_enumerator_t);
|
||||
enumerator->public.enumerate = (void*)package_enumerator_enumerate;
|
||||
enumerator->public.destroy = (void*)package_enumerator_destroy;
|
||||
enumerator->file = file;
|
||||
|
||||
return (enumerator_t*)enumerator;
|
||||
}
|
||||
|
||||
|
||||
METHOD(imc_os_info_t, destroy, void,
|
||||
private_imc_os_info_t *this)
|
||||
{
|
||||
free(this->name.ptr);
|
||||
free(this->version.ptr);
|
||||
free(this);
|
||||
}
|
||||
|
||||
#define RELEASE_LSB 0
|
||||
#define RELEASE_DEBIAN 1
|
||||
|
||||
/**
|
||||
* Determine Linux distribution version and hardware platform
|
||||
*/
|
||||
static bool extract_platform_info(os_type_t *type, chunk_t *name,
|
||||
chunk_t *version)
|
||||
{
|
||||
FILE *file;
|
||||
u_char buf[BUF_LEN], *pos = buf;
|
||||
int len = BUF_LEN - 1;
|
||||
os_type_t os_type = OS_TYPE_UNKNOWN;
|
||||
chunk_t os_name = chunk_empty;
|
||||
chunk_t os_version = chunk_empty;
|
||||
char *os_str;
|
||||
struct utsname uninfo;
|
||||
int i;
|
||||
|
||||
/* Linux/Unix distribution release info (from http://linuxmafia.com) */
|
||||
const char* releases[] = {
|
||||
"/etc/lsb-release", "/etc/debian_version",
|
||||
"/etc/SuSE-release", "/etc/novell-release",
|
||||
"/etc/sles-release", "/etc/redhat-release",
|
||||
"/etc/fedora-release", "/etc/gentoo-release",
|
||||
"/etc/slackware-version", "/etc/annvix-release",
|
||||
"/etc/arch-release", "/etc/arklinux-release",
|
||||
"/etc/aurox-release", "/etc/blackcat-release",
|
||||
"/etc/cobalt-release", "/etc/conectiva-release",
|
||||
"/etc/debian_release", "/etc/immunix-release",
|
||||
"/etc/lfs-release", "/etc/linuxppc-release",
|
||||
"/etc/mandrake-release", "/etc/mandriva-release",
|
||||
"/etc/mandrakelinux-release", "/etc/mklinux-release",
|
||||
"/etc/pld-release", "/etc/redhat_version",
|
||||
"/etc/slackware-release", "/etc/e-smith-release",
|
||||
"/etc/release", "/etc/sun-release",
|
||||
"/etc/tinysofa-release", "/etc/turbolinux-release",
|
||||
"/etc/ultrapenguin-release", "/etc/UnitedLinux-release",
|
||||
"/etc/va-release", "/etc/yellowdog-release"
|
||||
};
|
||||
|
||||
const char lsb_distrib_id[] = "DISTRIB_ID=";
|
||||
const char lsb_distrib_release[] = "DISTRIB_RELEASE=";
|
||||
|
||||
for (i = 0; i < countof(releases); i++)
|
||||
{
|
||||
file = fopen(releases[i], "r");
|
||||
if (!file)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
/* read release file into buffer */
|
||||
fseek(file, 0, SEEK_END);
|
||||
len = min(ftell(file), len);
|
||||
rewind(file);
|
||||
buf[len] = '\0';
|
||||
if (fread(buf, 1, len, file) != len)
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to read file \"%s\"", releases[i]);
|
||||
fclose(file);
|
||||
return FALSE;
|
||||
}
|
||||
fclose(file);
|
||||
|
||||
DBG1(DBG_IMC, "processing \"%s\" file", releases[i]);
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case RELEASE_LSB:
|
||||
{
|
||||
/* Determine Distribution ID */
|
||||
pos = strstr(buf, lsb_distrib_id);
|
||||
if (!pos)
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to find begin of DISTRIB_ID field");
|
||||
return FALSE;
|
||||
}
|
||||
pos += strlen(lsb_distrib_id);
|
||||
|
||||
os_name.ptr = pos;
|
||||
|
||||
pos = strchr(pos, '\n');
|
||||
if (!pos)
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to find end of DISTRIB_ID field");
|
||||
return FALSE;
|
||||
}
|
||||
os_name.len = pos - os_name.ptr;
|
||||
|
||||
/* Determine Distribution Release */
|
||||
pos = strstr(buf, lsb_distrib_release);
|
||||
if (!pos)
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to find begin of DISTRIB_RELEASE field");
|
||||
return FALSE;
|
||||
}
|
||||
pos += strlen(lsb_distrib_release);
|
||||
|
||||
os_version.ptr = pos;
|
||||
|
||||
pos = strchr(pos, '\n');
|
||||
if (!pos)
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to find end of DISTRIB_RELEASE field");
|
||||
return FALSE;
|
||||
}
|
||||
os_version.len = pos - os_version.ptr;
|
||||
|
||||
break;
|
||||
}
|
||||
case RELEASE_DEBIAN:
|
||||
{
|
||||
os_type = OS_TYPE_DEBIAN;
|
||||
|
||||
os_version.ptr = buf;
|
||||
pos = strchr(buf, '\n');
|
||||
if (!pos)
|
||||
{
|
||||
DBG1(DBG_PTS, "failed to find end of release string");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
os_version.len = pos - os_version.ptr;
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
const char str_release[] = " release ";
|
||||
|
||||
os_name.ptr = buf;
|
||||
|
||||
pos = strstr(buf, str_release);
|
||||
if (!pos)
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to find release keyword");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
os_name.len = pos - os_name.ptr;
|
||||
|
||||
pos += strlen(str_release);
|
||||
os_version.ptr = pos;
|
||||
|
||||
pos = strchr(pos, '\n');
|
||||
if (!pos)
|
||||
{
|
||||
DBG1(DBG_IMC, "failed to find end of release string");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
os_version.len = pos - os_version.ptr;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (!os_version.ptr)
|
||||
{
|
||||
DBG1(DBG_IMC, "no distribution release file found");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (uname(&uninfo) < 0)
|
||||
{
|
||||
DBG1(DBG_IMC, "could not retrieve machine architecture");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Try to find a matching OS type based on the OS name */
|
||||
if (os_type == OS_TYPE_UNKNOWN)
|
||||
{
|
||||
os_type = os_type_from_name(os_name);
|
||||
}
|
||||
|
||||
/* If known use the official OS name */
|
||||
if (os_type != OS_TYPE_UNKNOWN)
|
||||
{
|
||||
os_str = enum_to_name(os_type_names, os_type);
|
||||
os_name = chunk_create(os_str, strlen(os_str));
|
||||
}
|
||||
|
||||
/* copy OS type */
|
||||
*type = os_type;
|
||||
|
||||
/* copy OS name */
|
||||
*name = chunk_clone(os_name);
|
||||
|
||||
/* copy OS version and machine architecture */
|
||||
*version = chunk_alloc(os_version.len + 1 + strlen(uninfo.machine));
|
||||
pos = version->ptr;
|
||||
memcpy(pos, os_version.ptr, os_version.len);
|
||||
pos += os_version.len;
|
||||
*pos++ = ' ';
|
||||
memcpy(pos, uninfo.machine, strlen(uninfo.machine));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* See header
|
||||
*/
|
||||
imc_os_info_t *imc_os_info_create(void)
|
||||
{
|
||||
private_imc_os_info_t *this;
|
||||
chunk_t name, version;
|
||||
os_type_t type;
|
||||
|
||||
/* As an option OS name and OS version can be configured manually */
|
||||
name.ptr = lib->settings->get_str(lib->settings,
|
||||
"%s.imcv.imc_os_info.name", NULL, lib->ns);
|
||||
version.ptr = lib->settings->get_str(lib->settings,
|
||||
"%s.imcv.imc_os_info.version", NULL, lib->ns);
|
||||
if (name.ptr && version.ptr)
|
||||
{
|
||||
name.len = strlen(name.ptr);
|
||||
name = chunk_clone(name);
|
||||
|
||||
version.len = strlen(version.ptr);
|
||||
version = chunk_clone(version);
|
||||
|
||||
type = os_type_from_name(name);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!extract_platform_info(&type, &name, &version))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
DBG1(DBG_IMC, "operating system name is '%.*s'",
|
||||
name.len, name.ptr);
|
||||
DBG1(DBG_IMC, "operating system version is '%.*s'",
|
||||
version.len, version.ptr);
|
||||
|
||||
INIT(this,
|
||||
.public = {
|
||||
.get_type = _get_type,
|
||||
.get_name = _get_name,
|
||||
.get_numeric_version = _get_numeric_version,
|
||||
.get_version = _get_version,
|
||||
.get_fwd_status = _get_fwd_status,
|
||||
.get_uptime = _get_uptime,
|
||||
.get_setting = _get_setting,
|
||||
.create_package_enumerator = _create_package_enumerator,
|
||||
.destroy = _destroy,
|
||||
},
|
||||
.type = type,
|
||||
.name = name,
|
||||
.version = version,
|
||||
);
|
||||
|
||||
return &this->public;
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2014 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 imc_os_info imc_os_info
|
||||
* @{ @ingroup libimcv
|
||||
*/
|
||||
|
||||
#ifndef IMC_OS_INFO_H_
|
||||
#define IMC_OS_INFO_H_
|
||||
|
||||
typedef struct imc_os_info_t imc_os_info_t;
|
||||
|
||||
#include "os_info/os_info.h"
|
||||
|
||||
#include <library.h>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
/**
|
||||
* Interface for the IMC Operating System (OS) information module
|
||||
*/
|
||||
struct imc_os_info_t {
|
||||
|
||||
/**
|
||||
* Get the OS type if it can be determined
|
||||
*
|
||||
* @return OS type
|
||||
*/
|
||||
os_type_t (*get_type)(imc_os_info_t *this);
|
||||
|
||||
/**
|
||||
* Get the OS product name or distribution
|
||||
*
|
||||
* @return OS name
|
||||
*/
|
||||
chunk_t (*get_name)(imc_os_info_t *this);
|
||||
|
||||
/**
|
||||
* Get the numeric OS version or release
|
||||
*
|
||||
* @param major OS major version number
|
||||
* @param minor OS minor version number
|
||||
*/
|
||||
void (*get_numeric_version)(imc_os_info_t *this, u_int32_t *major,
|
||||
u_int32_t *minor);
|
||||
|
||||
/**
|
||||
* Get the OS version or release
|
||||
*
|
||||
* @return OS version
|
||||
*/
|
||||
chunk_t (*get_version)(imc_os_info_t *this);
|
||||
|
||||
/**
|
||||
* Get the OS IPv4 forwarding status
|
||||
*
|
||||
* @return IP forwarding status
|
||||
*/
|
||||
os_fwd_status_t (*get_fwd_status)(imc_os_info_t *this);
|
||||
|
||||
/**
|
||||
* Get the OS uptime in seconds
|
||||
*
|
||||
* @return OS uptime
|
||||
*/
|
||||
time_t (*get_uptime)(imc_os_info_t *this);
|
||||
|
||||
/**
|
||||
* Get an OS setting (restricted to /proc, /sys, and /etc)
|
||||
*
|
||||
* @param name name of OS setting
|
||||
* @return value of OS setting
|
||||
*/
|
||||
chunk_t (*get_setting)(imc_os_info_t *this, char *name);
|
||||
|
||||
/**
|
||||
* Enumerates over all installed packages
|
||||
*
|
||||
* @return return package enumerator
|
||||
*/
|
||||
enumerator_t* (*create_package_enumerator)(imc_os_info_t *this);
|
||||
|
||||
/**
|
||||
* Destroys an imc_os_info_t object.
|
||||
*/
|
||||
void (*destroy)(imc_os_info_t *this);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create an imc_os_info_t object
|
||||
*/
|
||||
imc_os_info_t* imc_os_info_create(void);
|
||||
|
||||
#endif /** IMC_OS_INFO_H_ @}*/
|
||||
Reference in New Issue
Block a user