Annotation of embedaddon/strongswan/src/libimcv/imc/imc_os_info.c, revision 1.1.1.2

1.1       misho       1: /*
                      2:  * Copyright (C) 2012-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: /* for GetTickCount64, Windows 7 */
                     17: #ifdef WIN32
                     18: # define _WIN32_WINNT 0x0601
                     19: #endif
                     20: 
                     21: #include "imc_os_info.h"
                     22: 
                     23: #include <stdio.h>
                     24: #include <stdarg.h>
                     25: 
                     26: #include <collections/linked_list.h>
                     27: #include <utils/debug.h>
                     28: 
                     29: typedef struct private_imc_os_info_t private_imc_os_info_t;
                     30: 
                     31: /**
                     32:  * Private data of an imc_os_info_t object.
                     33:  *
                     34:  */
                     35: struct private_imc_os_info_t {
                     36: 
                     37:        /**
                     38:         * Public imc_os_info_t interface.
                     39:         */
                     40:        imc_os_info_t public;
                     41: 
                     42:        /**
                     43:         * OS type
                     44:         */
                     45:        os_type_t type;
                     46: 
                     47:        /**
                     48:         * OS name
                     49:         */
                     50:        chunk_t name;
                     51: 
                     52:        /**
                     53:         * OS version
                     54:         */
                     55:        chunk_t version;
                     56: 
                     57: };
                     58: 
                     59: METHOD(imc_os_info_t, get_type, os_type_t,
                     60:        private_imc_os_info_t *this)
                     61: {
                     62:        return this->type;
                     63: }
                     64: 
                     65: METHOD(imc_os_info_t, get_name, chunk_t,
                     66:        private_imc_os_info_t *this)
                     67: {
                     68:        return this->name;
                     69: }
                     70: 
                     71: METHOD(imc_os_info_t, get_numeric_version, void,
                     72:        private_imc_os_info_t *this, uint32_t *major, uint32_t *minor)
                     73: {
                     74:        u_char *pos;
                     75: 
                     76:        if (major)
                     77:        {
                     78:                *major = atol(this->version.ptr);
                     79:        }
                     80:        pos = memchr(this->version.ptr, '.', this->version.len);
                     81:        if (minor)
                     82:        {
                     83:                *minor = pos ? atol(pos + 1) : 0;
                     84:        }
                     85: }
                     86: 
                     87: METHOD(imc_os_info_t, get_version, chunk_t,
                     88:        private_imc_os_info_t *this)
                     89: {
                     90:        return this->version;
                     91: }
                     92: 
                     93: METHOD(imc_os_info_t, get_default_pwd_status, bool,
                     94:        private_imc_os_info_t *this)
                     95: {
                     96:        /* As an option the default password status can be configured manually */
                     97:        return lib->settings->get_bool(lib->settings,
                     98:                                        "%s.imcv.os_info.default_password_enabled", FALSE, lib->ns);
                     99: }
                    100: 
                    101: #ifdef WIN32
                    102: 
                    103: METHOD(imc_os_info_t, get_fwd_status, os_fwd_status_t,
                    104:        private_imc_os_info_t *this)
                    105: {
                    106:        return OS_FWD_UNKNOWN;
                    107: }
                    108: 
                    109: METHOD(imc_os_info_t, get_uptime, time_t,
                    110:        private_imc_os_info_t *this)
                    111: {
                    112:        return GetTickCount64() / 1000;
                    113: }
                    114: 
                    115: METHOD(imc_os_info_t, get_setting, chunk_t,
                    116:        private_imc_os_info_t *this, char *name)
                    117: {
                    118:        return chunk_empty;
                    119: }
                    120: 
                    121: METHOD(imc_os_info_t, create_package_enumerator, enumerator_t*,
                    122:        private_imc_os_info_t *this)
                    123: {
                    124:        return NULL;
                    125: }
                    126: 
                    127: /**
                    128:  * Determine Windows release
                    129:  */
                    130: static bool extract_platform_info(os_type_t *type, chunk_t *name,
                    131:                                                                  chunk_t *version)
                    132: {
                    133:        OSVERSIONINFOEX osvie;
                    134:        char buf[64];
                    135: 
                    136:        memset(&osvie, 0, sizeof(osvie));
                    137:        osvie.dwOSVersionInfoSize = sizeof(osvie);
                    138: 
                    139:        if (!GetVersionEx((LPOSVERSIONINFO)&osvie))
                    140:        {
                    141:                return FALSE;
                    142:        }
                    143:        *type = OS_TYPE_WINDOWS;
                    144:        snprintf(buf, sizeof(buf), "Windows %s %s",
                    145:                         osvie.wProductType == VER_NT_WORKSTATION ? "Client" : "Server",
                    146: #ifdef WIN64
                    147:                         "x86_64"
                    148: #else
                    149:                         "x86"
                    150: #endif
                    151:        );
                    152:        *name = chunk_clone(chunk_from_str(buf));
                    153: 
                    154:        snprintf(buf, sizeof(buf), "%d.%d.%d (SP %d.%d)",
                    155:                         osvie.dwMajorVersion, osvie.dwMinorVersion, osvie.dwBuildNumber,
                    156:                         osvie.wServicePackMajor, osvie.wServicePackMinor);
                    157:        *version = chunk_clone(chunk_from_str(buf));
                    158: 
                    159:        return TRUE;
                    160: }
                    161: 
                    162: #else /* !WIN32 */
                    163: 
                    164: #include <sys/utsname.h>
                    165: 
                    166: METHOD(imc_os_info_t, get_fwd_status, os_fwd_status_t,
                    167:        private_imc_os_info_t *this)
                    168: {
                    169:        const char ip_forward[] = "/proc/sys/net/ipv4/ip_forward";
                    170:        char buf[2];
                    171:        FILE *file;
                    172: 
                    173:        os_fwd_status_t fwd_status = OS_FWD_UNKNOWN;
                    174: 
                    175:        file = fopen(ip_forward, "r");
                    176:        if (file)
                    177:        {
                    178:                if (fread(buf, 1, 1, file) == 1)
                    179:                {
                    180:                        switch (buf[0])
                    181:                        {
                    182:                                case '0':
                    183:                                        fwd_status = OS_FWD_DISABLED;
                    184:                                        break;
                    185:                                case '1':
                    186:                                        fwd_status = OS_FWD_ENABLED;
                    187:                                        break;
                    188:                                default:
                    189:                                        DBG1(DBG_IMC, "\"%s\" returns invalid value ", ip_forward);
                    190:                                        break;
                    191:                        }
                    192:                }
                    193:                else
                    194:                {
                    195:                        DBG1(DBG_IMC, "could not read from \"%s\"", ip_forward);
                    196:                }
                    197:                fclose(file);
                    198:        }
                    199:        else
                    200:        {
                    201:                DBG1(DBG_IMC, "failed to open \"%s\"", ip_forward);
                    202:        }
                    203: 
                    204:        return fwd_status;
                    205: }
                    206: 
                    207: METHOD(imc_os_info_t, get_uptime, time_t,
                    208:        private_imc_os_info_t *this)
                    209: {
                    210:        const char proc_uptime[] = "/proc/uptime";
                    211:        FILE *file;
                    212:        u_int uptime;
                    213: 
                    214:        file = fopen(proc_uptime, "r");
                    215:        if (!file)
                    216:        {
                    217:                DBG1(DBG_IMC, "failed to open \"%s\"", proc_uptime);
                    218:                return 0;
                    219:        }
                    220:        if (fscanf(file, "%u", &uptime) != 1)
                    221:        {
                    222:                DBG1(DBG_IMC, "failed to read file \"%s\"", proc_uptime);
                    223:                uptime = 0;
                    224:        }
                    225:        fclose(file);
                    226: 
                    227:        return uptime;
                    228: }
                    229: 
                    230: METHOD(imc_os_info_t, get_setting, chunk_t,
                    231:        private_imc_os_info_t *this, char *name)
                    232: {
                    233:        FILE *file;
                    234:        u_char buf[2048];
                    235:        size_t i = 0;
                    236:        chunk_t value;
                    237: 
                    238:        if (!strpfx(name, "/etc/") && !strpfx(name, "/proc/") &&
                    239:                !strpfx(name, "/sys/") && !strpfx(name, "/var/"))
                    240:        {
                    241:                /**
                    242:                 * In order to guarantee privacy, only settings from the
                    243:                 * /etc/, /proc/ and /sys/ directories can be retrieved
                    244:                 */
                    245:                DBG1(DBG_IMC, "not allowed to access '%s'", name);
                    246: 
                    247:                return chunk_empty;
                    248:        }
                    249: 
                    250:        file = fopen(name, "r");
                    251:        if (!file)
                    252:        {
                    253:                DBG1(DBG_IMC, "failed to open '%s'", name);
                    254: 
                    255:                return chunk_empty;
                    256:        }
                    257:        while (i < sizeof(buf) && fread(buf + i, 1, 1, file) == 1)
                    258:        {
                    259:                i++;
                    260:        }
                    261:        fclose(file);
                    262: 
                    263:        value = chunk_create(buf, i);
                    264: 
                    265:        return chunk_clone(value);
                    266: }
                    267: 
                    268: typedef struct {
                    269:        /**
                    270:         * implements enumerator_t
                    271:         */
                    272:        enumerator_t public;
                    273: 
                    274:        /**
                    275:         * package info pipe stream
                    276:         */
                    277:        FILE* file;
                    278: 
                    279:        /**
                    280:         * line buffer
                    281:         */
                    282:        u_char line[512];
                    283: 
                    284: } package_enumerator_t;
                    285: 
                    286: METHOD(enumerator_t, package_enumerator_destroy, void,
                    287:        package_enumerator_t *this)
                    288: {
                    289:        pclose(this->file);
                    290:        free(this);
                    291: }
                    292: 
                    293: METHOD(enumerator_t, package_enumerator_enumerate, bool,
                    294:        package_enumerator_t *this, va_list args)
                    295: {
                    296:        chunk_t *name, *version;
                    297:        u_char *pos;
                    298: 
                    299:        VA_ARGS_VGET(args, name, version);
                    300: 
                    301:        while (TRUE)
                    302:        {
                    303:                if (!fgets(this->line, sizeof(this->line), this->file))
                    304:                {
                    305:                        return FALSE;
                    306:                }
                    307: 
                    308:                pos = strchr(this->line, '\t');
                    309:                if (!pos)
                    310:                {
                    311:                        return FALSE;
                    312:                }
                    313:                *pos++ = '\0';
                    314: 
                    315:                if (!streq(this->line, "install ok installed"))
                    316:                {
                    317:                        continue;
                    318:                }
                    319:                name->ptr = pos;
                    320:                pos = strchr(pos, '\t');
                    321:                if (!pos)
                    322:                {
                    323:                        return FALSE;
                    324:                }
                    325:                name->len = pos++ - name->ptr;
                    326: 
                    327:                version->ptr = pos;
                    328:                version->len = strlen(pos) - 1;
                    329:                return TRUE;
                    330:        }
                    331: }
                    332: 
                    333: METHOD(imc_os_info_t, create_package_enumerator, enumerator_t*,
                    334:        private_imc_os_info_t *this)
                    335: {
                    336:        FILE *file;
                    337:        const char command[] = "dpkg-query --show --showformat="
                    338:                                                                "'${Status}\t${Package}\t${Version}\n'";
                    339:        package_enumerator_t *enumerator;
                    340: 
                    341:        /* Only Debian and Ubuntu package enumeration is currently supported */
                    342:        if (this->type != OS_TYPE_DEBIAN && this->type != OS_TYPE_UBUNTU)
                    343:        {
                    344:                return NULL;
                    345:        }
                    346: 
                    347:        /* Open a pipe stream for reading the output of the dpkg-query command */
                    348:        file = popen(command, "r");
                    349:        if (!file)
                    350:        {
                    351:                DBG1(DBG_IMC, "failed to run dpkg command");
                    352:                return NULL;
                    353:        }
                    354: 
                    355:        INIT(enumerator,
                    356:                .public = {
                    357:                        .enumerate = enumerator_enumerate_default,
                    358:                        .venumerate = _package_enumerator_enumerate,
                    359:                        .destroy = _package_enumerator_destroy,
                    360:                },
                    361:                .file = file,
                    362:        );
                    363:        return (enumerator_t*)enumerator;
                    364: }
                    365: 
                    366: #define RELEASE_LSB            0
                    367: #define RELEASE_DEBIAN 1
                    368: 
                    369: /**
                    370:  * Determine Linux distribution version and hardware platform
                    371:  */
                    372: static bool extract_platform_info(os_type_t *type, chunk_t *name,
                    373:                                                                  chunk_t *version)
                    374: {
                    375:        FILE *file;
                    376:        u_char buf[BUF_LEN], *pos = buf;
                    377:        int len = BUF_LEN - 1;
                    378:        long file_len;
                    379:        os_type_t os_type = OS_TYPE_UNKNOWN;
                    380:        chunk_t os_name = chunk_empty;
                    381:        chunk_t os_version = chunk_empty;
                    382:        char *os_str;
                    383:        struct utsname uninfo;
                    384:        int i;
                    385: 
                    386:        /* Linux/Unix distribution release info (from http://linuxmafia.com) */
                    387:        const char* releases[] = {
                    388:                "/etc/lsb-release",           "/etc/debian_version",
                    389:                "/etc/SuSE-release",          "/etc/novell-release",
                    390:                "/etc/sles-release",          "/etc/redhat-release",
                    391:                "/etc/fedora-release",        "/etc/gentoo-release",
                    392:                "/etc/slackware-version",     "/etc/annvix-release",
                    393:                "/etc/arch-release",          "/etc/arklinux-release",
                    394:                "/etc/aurox-release",         "/etc/blackcat-release",
                    395:                "/etc/cobalt-release",        "/etc/conectiva-release",
                    396:                "/etc/debian_release",        "/etc/immunix-release",
                    397:                "/etc/lfs-release",           "/etc/linuxppc-release",
                    398:                "/etc/mandrake-release",      "/etc/mandriva-release",
                    399:                "/etc/mandrakelinux-release", "/etc/mklinux-release",
                    400:                "/etc/pld-release",           "/etc/redhat_version",
                    401:                "/etc/slackware-release",     "/etc/e-smith-release",
                    402:                "/etc/release",               "/etc/sun-release",
                    403:                "/etc/tinysofa-release",      "/etc/turbolinux-release",
                    404:                "/etc/ultrapenguin-release",  "/etc/UnitedLinux-release",
                    405:                "/etc/va-release",            "/etc/yellowdog-release"
                    406:        };
                    407: 
                    408:        const char lsb_distrib_id[]      = "DISTRIB_ID=";
                    409:        const char lsb_distrib_release[] = "DISTRIB_RELEASE=";
                    410: 
                    411:        for (i = 0; i < countof(releases); i++)
                    412:        {
                    413:                file = fopen(releases[i], "r");
                    414:                if (!file)
                    415:                {
                    416:                        continue;
                    417:                }
                    418: 
                    419:                /* read release file into buffer */
                    420:                fseek(file, 0, SEEK_END);
                    421:                file_len = ftell(file);
                    422:                if (file_len < 0)
                    423:                {
                    424:                        DBG1(DBG_IMC, "failed to determine size of \"%s\"", releases[i]);
                    425:                        fclose(file);
                    426:                        return FALSE;
                    427:                }
                    428:                len = min(file_len, len);
                    429:                rewind(file);
                    430:                if (fread(buf, 1, len, file) != len)
                    431:                {
                    432:                        DBG1(DBG_IMC, "failed to read file \"%s\"", releases[i]);
                    433:                        fclose(file);
                    434:                        return FALSE;
                    435:                }
                    436:                buf[len] = '\0';
                    437:                fclose(file);
                    438: 
                    439:                DBG1(DBG_IMC, "processing \"%s\" file", releases[i]);
                    440: 
                    441:                switch (i)
                    442:                {
                    443:                        case RELEASE_LSB:
                    444:                        {
                    445:                                /* Determine Distribution ID */
                    446:                                pos = strstr(buf, lsb_distrib_id);
                    447:                                if (!pos)
                    448:                                {
                    449:                                        DBG1(DBG_IMC, "failed to find begin of DISTRIB_ID field");
                    450:                                        return FALSE;
                    451:                                }
                    452:                                pos += strlen(lsb_distrib_id);
                    453: 
                    454:                                os_name.ptr = pos;
                    455: 
                    456:                                pos = strchr(pos, '\n');
                    457:                                if (!pos)
                    458:                                {
                    459:                                        DBG1(DBG_IMC, "failed to find end of DISTRIB_ID field");
                    460:                                        return FALSE;
                    461:                                }
                    462:                                os_name.len = pos - os_name.ptr;
                    463: 
                    464:                                /* Determine Distribution Release */
                    465:                                pos = strstr(buf, lsb_distrib_release);
                    466:                                if (!pos)
                    467:                                {
                    468:                                        DBG1(DBG_IMC, "failed to find begin of DISTRIB_RELEASE field");
                    469:                                        return FALSE;
                    470:                                }
                    471:                                pos += strlen(lsb_distrib_release);
                    472: 
                    473:                                os_version.ptr = pos;
                    474: 
                    475:                                pos = strchr(pos, '\n');
                    476:                                if (!pos)
                    477:                                {
                    478:                                        DBG1(DBG_IMC, "failed to find end of DISTRIB_RELEASE field");
                    479:                                        return FALSE;
                    480:                                }
                    481:                                os_version.len = pos - os_version.ptr;
                    482: 
                    483:                                break;
                    484:                        }
                    485:                        case RELEASE_DEBIAN:
                    486:                        {
                    487:                                os_type = OS_TYPE_DEBIAN;
                    488: 
                    489:                                os_version.ptr = buf;
1.1.1.2 ! misho     490: 
        !           491:                                /* extract major release number only */
        !           492:                                pos = strchr(buf, '.');
        !           493:                                if (!pos)
        !           494:                                {
        !           495:                                        pos = strchr(buf, '\n');
        !           496:                                }
1.1       misho     497:                                if (!pos)
                    498:                                {
                    499:                                        DBG1(DBG_PTS, "failed to find end of release string");
                    500:                                        return FALSE;
                    501:                                }
                    502: 
                    503:                                os_version.len = pos - os_version.ptr;
                    504: 
                    505:                                break;
                    506:                        }
                    507:                        default:
                    508:                        {
                    509:                                const char str_release[] = " release ";
                    510: 
                    511:                                os_name.ptr = buf;
                    512: 
                    513:                                pos = strstr(buf, str_release);
                    514:                                if (!pos)
                    515:                                {
                    516:                                        DBG1(DBG_IMC, "failed to find release keyword");
                    517:                                        return FALSE;
                    518:                                }
                    519: 
                    520:                                os_name.len = pos - os_name.ptr;
                    521: 
                    522:                                pos += strlen(str_release);
                    523:                                os_version.ptr = pos;
                    524: 
                    525:                                pos = strchr(pos, '\n');
                    526:                                if (!pos)
                    527:                                {
                    528:                                        DBG1(DBG_IMC, "failed to find end of release string");
                    529:                                        return FALSE;
                    530:                                }
                    531: 
                    532:                                os_version.len = pos - os_version.ptr;
                    533: 
                    534:                                break;
                    535:                        }
                    536:                }
                    537:                break;
                    538:        }
                    539: 
                    540:        if (!os_version.ptr)
                    541:        {
                    542:                DBG1(DBG_IMC, "no distribution release file found");
                    543:                return FALSE;
                    544:        }
                    545: 
                    546:        if (uname(&uninfo) < 0)
                    547:        {
                    548:                DBG1(DBG_IMC, "could not retrieve machine architecture");
                    549:                return FALSE;
                    550:        }
                    551: 
                    552:        /* Try to find a matching OS type based on the OS name */
                    553:        if (os_type == OS_TYPE_UNKNOWN)
                    554:        {
                    555:                os_type = os_type_from_name(os_name);
                    556:        }
                    557: 
                    558:        /* If known use the official OS name */
                    559:        if (os_type != OS_TYPE_UNKNOWN)
                    560:        {
                    561:                os_str = enum_to_name(os_type_names, os_type);
                    562:                os_name = chunk_create(os_str, strlen(os_str));
                    563:        }
                    564: 
                    565:        /* copy OS type */
                    566:        *type = os_type;
                    567: 
                    568:        /* copy OS name */
                    569:        *name = chunk_clone(os_name);
                    570: 
                    571:        /* copy OS version and machine architecture */
                    572:        *version = chunk_alloc(os_version.len + 1 + strlen(uninfo.machine));
                    573:        pos = version->ptr;
                    574:        memcpy(pos, os_version.ptr, os_version.len);
                    575:        pos += os_version.len;
                    576:        *pos++ = ' ';
                    577:        memcpy(pos, uninfo.machine, strlen(uninfo.machine));
                    578: 
                    579:        return TRUE;
                    580: }
                    581: 
                    582: #endif /* !WIN32 */
                    583: 
                    584: METHOD(imc_os_info_t, destroy, void,
                    585:        private_imc_os_info_t *this)
                    586: {
                    587:        free(this->name.ptr);
                    588:        free(this->version.ptr);
                    589:        free(this);
                    590: }
                    591: 
                    592: /**
                    593:  * See header
                    594:  */
                    595: imc_os_info_t *imc_os_info_create(void)
                    596: {
                    597:        private_imc_os_info_t *this;
                    598:        chunk_t name, version;
                    599:        os_type_t type;
                    600: 
                    601:        /* As an option OS name and OS version can be configured manually */
                    602:        name.ptr = lib->settings->get_str(lib->settings,
                    603:                                                                          "%s.imcv.os_info.name", NULL, lib->ns);
                    604:        version.ptr = lib->settings->get_str(lib->settings,
                    605:                                                                          "%s.imcv.os_info.version", NULL, lib->ns);
                    606:        if (name.ptr && version.ptr)
                    607:        {
                    608:                name.len = strlen(name.ptr);
                    609:                name = chunk_clone(name);
                    610: 
                    611:                version.len = strlen(version.ptr);
                    612:                version = chunk_clone(version);
                    613: 
                    614:                type = os_type_from_name(name);
                    615:        }
                    616:        else
                    617:        {
                    618:                if (!extract_platform_info(&type, &name, &version))
                    619:                {
                    620:                        return NULL;
                    621:                }
                    622:        }
                    623:        DBG1(DBG_IMC, "operating system name is '%.*s'",
                    624:                                   name.len, name.ptr);
                    625:        DBG1(DBG_IMC, "operating system version is '%.*s'",
                    626:                                   version.len, version.ptr);
                    627: 
                    628:        INIT(this,
                    629:                .public = {
                    630:                        .get_type = _get_type,
                    631:                        .get_name = _get_name,
                    632:                        .get_numeric_version = _get_numeric_version,
                    633:                        .get_version = _get_version,
                    634:                        .get_fwd_status = _get_fwd_status,
                    635:                        .get_default_pwd_status = _get_default_pwd_status,
                    636:                        .get_uptime = _get_uptime,
                    637:                        .get_setting = _get_setting,
                    638:                        .create_package_enumerator = _create_package_enumerator,
                    639:                        .destroy = _destroy,
                    640:                },
                    641:                .type = type,
                    642:                .name = name,
                    643:                .version = version,
                    644:        );
                    645: 
                    646:        return &this->public;
                    647: }

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