diff --git a/src/libimcv/os_info/os_info.c b/src/libimcv/os_info/os_info.c index 02e32b098..4f2a15dc5 100644 --- a/src/libimcv/os_info/os_info.c +++ b/src/libimcv/os_info/os_info.c @@ -24,6 +24,18 @@ typedef struct private_os_info_t private_os_info_t; +ENUM(os_type_names, OS_TYPE_UNKNOWN, OS_TYPE_ANDROID, + "Unknown", + "Debian", + "Ubuntu", + "Fedora", + "Red Hat", + "CentOS", + "SUSE", + "Gentoo", + "Android" +); + ENUM(os_fwd_status_names, OS_FWD_DISABLED, OS_FWD_UNKNOWN, "disabled", "enabled", @@ -41,6 +53,11 @@ struct private_os_info_t { */ os_info_t public; + /** + * OS type + */ + os_type_t type; + /** * OS name */ @@ -53,6 +70,12 @@ struct private_os_info_t { }; +METHOD(os_info_t, get_type, os_type_t, + private_os_info_t *this) +{ + return this->type; +} + METHOD(os_info_t, get_name, chunk_t, private_os_info_t *this) { @@ -190,7 +213,7 @@ typedef struct { enumerator_t public; /** - * streamed pipe + * package info pipe stream */ FILE* file; @@ -247,11 +270,9 @@ METHOD(os_info_t, create_package_enumerator, enumerator_t*, { FILE *file; package_enumerator_t *enumerator; - chunk_t debian = { "Debian", 6 }; - chunk_t ubuntu = { "Ubuntu", 6 }; /* Only Debian and Ubuntu package enumeration is currently supported */ - if (!chunk_equals(this->name, debian) && !chunk_equals(this->name, ubuntu)) + if (this->type != OS_TYPE_DEBIAN && this->type != OS_TYPE_UBUNTU) { return NULL; } @@ -288,15 +309,18 @@ METHOD(os_info_t, destroy, void, /** * Determine Linux distribution version and hardware platform */ -static bool extract_platform_info(chunk_t *name, chunk_t *version) +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; + int i, t; /* Linux/Unix distribution release info (from http://linuxmafia.com) */ const char* releases[] = { @@ -367,7 +391,6 @@ static bool extract_platform_info(chunk_t *name, chunk_t *version) DBG1(DBG_IMC, "failed to find end of DISTRIB_ID field"); return FALSE; } - os_name.len = pos - os_name.ptr; /* Determine Distribution Release */ @@ -387,18 +410,15 @@ static bool extract_platform_info(chunk_t *name, chunk_t *version) DBG1(DBG_IMC, "failed to find end of DISTRIB_RELEASE field"); return FALSE; } - os_version.len = pos - os_version.ptr; break; } case RELEASE_DEBIAN: { - char str_debian[] = "Debian"; + os_type = OS_TYPE_DEBIAN; - os_name = chunk_create(str_debian, strlen(str_debian)); os_version.ptr = buf; - pos = strchr(buf, '\n'); if (!pos) { @@ -424,6 +444,7 @@ static bool extract_platform_info(chunk_t *name, chunk_t *version) } os_name.len = pos - os_name.ptr; + pos += strlen(str_release); os_version.ptr = pos; @@ -454,6 +475,29 @@ static bool extract_platform_info(chunk_t *name, chunk_t *version) return FALSE; } + /* Try to find a matching OS type */ + if (os_type == OS_TYPE_UNKNOWN) + { + for (t = OS_TYPE_DEBIAN; t <= OS_TYPE_GENTOO; t++) + { + os_str = enum_to_name(os_type_names, t); + if (memeq(os_name.ptr, os_str, min(os_name.len, strlen(os_str)))) + { + os_type = t; + os_name = chunk_create(os_str, strlen(os_str)); + break; + } + } + } + else + { + 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); @@ -475,8 +519,9 @@ os_info_t *os_info_create(void) { private_os_info_t *this; chunk_t name, version; + os_type_t type; - /* As an opton OS name and OS version can be configured manually */ + /* As an option OS name and OS version can be configured manually */ name.ptr = lib->settings->get_str(lib->settings, "libimcv.os_info.name", NULL); version.ptr = lib->settings->get_str(lib->settings, @@ -491,7 +536,7 @@ os_info_t *os_info_create(void) } else { - if (!extract_platform_info(&name, &version)) + if (!extract_platform_info(&type, &name, &version)) { return NULL; } @@ -503,6 +548,7 @@ os_info_t *os_info_create(void) INIT(this, .public = { + .get_type = _get_type, .get_name = _get_name, .get_numeric_version = _get_numeric_version, .get_version = _get_version, @@ -512,6 +558,7 @@ os_info_t *os_info_create(void) .create_package_enumerator = _create_package_enumerator, .destroy = _destroy, }, + .type = type, .name = name, .version = version, ); diff --git a/src/libimcv/os_info/os_info.h b/src/libimcv/os_info/os_info.h index 6a477ca1f..d8b53f8fc 100644 --- a/src/libimcv/os_info/os_info.h +++ b/src/libimcv/os_info/os_info.h @@ -22,12 +22,27 @@ #define OS_INFO_H_ typedef struct os_info_t os_info_t; +typedef enum os_type_t os_type_t; typedef enum os_fwd_status_t os_fwd_status_t; #include #include +enum os_type_t { + OS_TYPE_UNKNOWN, + OS_TYPE_DEBIAN, + OS_TYPE_UBUNTU, + OS_TYPE_FEDORA, + OS_TYPE_REDHAT, + OS_TYPE_CENTOS, + OS_TYPE_SUSE, + OS_TYPE_GENTOO, + OS_TYPE_ANDROID +}; + +extern enum_name_t *os_type_names; + /** * Defines the IPv4 forwarding status */ @@ -44,6 +59,13 @@ extern enum_name_t *os_fwd_status_names; */ struct os_info_t { + /** + * Get the OS type if it can be determined + * + * @return OS type + */ + os_type_t (*get_type)(os_info_t *this); + /** * Get the OS product name or distribution * diff --git a/src/libimcv/plugins/imc_os/imc_os.c b/src/libimcv/plugins/imc_os/imc_os.c index c487e21fe..5f2af9baf 100644 --- a/src/libimcv/plugins/imc_os/imc_os.c +++ b/src/libimcv/plugins/imc_os/imc_os.c @@ -128,32 +128,33 @@ TNC_Result TNC_IMC_NotifyConnectionChange(TNC_IMCID imc_id, static void add_product_info(imc_msg_t *msg) { pa_tnc_attr_t *attr; - chunk_t os_name; + os_type_t os_type; pen_t vendor_id = PEN_IETF; - char *vendor; int i; typedef struct vendor_pen_t { - char *vendor; + os_type_t os_type; pen_t pen; } vendor_pen_t; vendor_pen_t vendor_pens[] = { - { "Debian", PEN_DEBIAN }, - { "Ubuntu", PEN_CANONICAL } + { OS_TYPE_DEBIAN, PEN_DEBIAN }, + { OS_TYPE_UBUNTU, PEN_CANONICAL }, + { OS_TYPE_FEDORA, PEN_FEDORA }, + { OS_TYPE_REDHAT, PEN_REDHAT }, + { OS_TYPE_ANDROID, PEN_GOOGLE } }; - os_name = os->get_name(os); + os_type = os->get_type(os); for (i = 0; i < countof(vendor_pens); i++) { - vendor = vendor_pens[i].vendor; - if (chunk_equals(os_name, chunk_create(vendor, strlen(vendor)))) + if (os_type == vendor_pens[i].os_type) { vendor_id = vendor_pens[i].pen; break; } } - attr = ietf_attr_product_info_create(vendor_id, 0, os_name); + attr = ietf_attr_product_info_create(vendor_id, 0, os->get_name(os)); msg->add_attribute(msg, attr); }