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>