Annotation of embedaddon/strongswan/src/libimcv/imc/imc_os_info.c, revision 1.1
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;
! 490: pos = strchr(buf, '\n');
! 491: if (!pos)
! 492: {
! 493: DBG1(DBG_PTS, "failed to find end of release string");
! 494: return FALSE;
! 495: }
! 496:
! 497: os_version.len = pos - os_version.ptr;
! 498:
! 499: break;
! 500: }
! 501: default:
! 502: {
! 503: const char str_release[] = " release ";
! 504:
! 505: os_name.ptr = buf;
! 506:
! 507: pos = strstr(buf, str_release);
! 508: if (!pos)
! 509: {
! 510: DBG1(DBG_IMC, "failed to find release keyword");
! 511: return FALSE;
! 512: }
! 513:
! 514: os_name.len = pos - os_name.ptr;
! 515:
! 516: pos += strlen(str_release);
! 517: os_version.ptr = pos;
! 518:
! 519: pos = strchr(pos, '\n');
! 520: if (!pos)
! 521: {
! 522: DBG1(DBG_IMC, "failed to find end of release string");
! 523: return FALSE;
! 524: }
! 525:
! 526: os_version.len = pos - os_version.ptr;
! 527:
! 528: break;
! 529: }
! 530: }
! 531: break;
! 532: }
! 533:
! 534: if (!os_version.ptr)
! 535: {
! 536: DBG1(DBG_IMC, "no distribution release file found");
! 537: return FALSE;
! 538: }
! 539:
! 540: if (uname(&uninfo) < 0)
! 541: {
! 542: DBG1(DBG_IMC, "could not retrieve machine architecture");
! 543: return FALSE;
! 544: }
! 545:
! 546: /* Try to find a matching OS type based on the OS name */
! 547: if (os_type == OS_TYPE_UNKNOWN)
! 548: {
! 549: os_type = os_type_from_name(os_name);
! 550: }
! 551:
! 552: /* If known use the official OS name */
! 553: if (os_type != OS_TYPE_UNKNOWN)
! 554: {
! 555: os_str = enum_to_name(os_type_names, os_type);
! 556: os_name = chunk_create(os_str, strlen(os_str));
! 557: }
! 558:
! 559: /* copy OS type */
! 560: *type = os_type;
! 561:
! 562: /* copy OS name */
! 563: *name = chunk_clone(os_name);
! 564:
! 565: /* copy OS version and machine architecture */
! 566: *version = chunk_alloc(os_version.len + 1 + strlen(uninfo.machine));
! 567: pos = version->ptr;
! 568: memcpy(pos, os_version.ptr, os_version.len);
! 569: pos += os_version.len;
! 570: *pos++ = ' ';
! 571: memcpy(pos, uninfo.machine, strlen(uninfo.machine));
! 572:
! 573: return TRUE;
! 574: }
! 575:
! 576: #endif /* !WIN32 */
! 577:
! 578: METHOD(imc_os_info_t, destroy, void,
! 579: private_imc_os_info_t *this)
! 580: {
! 581: free(this->name.ptr);
! 582: free(this->version.ptr);
! 583: free(this);
! 584: }
! 585:
! 586: /**
! 587: * See header
! 588: */
! 589: imc_os_info_t *imc_os_info_create(void)
! 590: {
! 591: private_imc_os_info_t *this;
! 592: chunk_t name, version;
! 593: os_type_t type;
! 594:
! 595: /* As an option OS name and OS version can be configured manually */
! 596: name.ptr = lib->settings->get_str(lib->settings,
! 597: "%s.imcv.os_info.name", NULL, lib->ns);
! 598: version.ptr = lib->settings->get_str(lib->settings,
! 599: "%s.imcv.os_info.version", NULL, lib->ns);
! 600: if (name.ptr && version.ptr)
! 601: {
! 602: name.len = strlen(name.ptr);
! 603: name = chunk_clone(name);
! 604:
! 605: version.len = strlen(version.ptr);
! 606: version = chunk_clone(version);
! 607:
! 608: type = os_type_from_name(name);
! 609: }
! 610: else
! 611: {
! 612: if (!extract_platform_info(&type, &name, &version))
! 613: {
! 614: return NULL;
! 615: }
! 616: }
! 617: DBG1(DBG_IMC, "operating system name is '%.*s'",
! 618: name.len, name.ptr);
! 619: DBG1(DBG_IMC, "operating system version is '%.*s'",
! 620: version.len, version.ptr);
! 621:
! 622: INIT(this,
! 623: .public = {
! 624: .get_type = _get_type,
! 625: .get_name = _get_name,
! 626: .get_numeric_version = _get_numeric_version,
! 627: .get_version = _get_version,
! 628: .get_fwd_status = _get_fwd_status,
! 629: .get_default_pwd_status = _get_default_pwd_status,
! 630: .get_uptime = _get_uptime,
! 631: .get_setting = _get_setting,
! 632: .create_package_enumerator = _create_package_enumerator,
! 633: .destroy = _destroy,
! 634: },
! 635: .type = type,
! 636: .name = name,
! 637: .version = version,
! 638: );
! 639:
! 640: return &this->public;
! 641: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>