1 /*
2 Copyright 2020 Northern.tech AS
3
4 This file is part of CFEngine 3 - written and maintained by Northern.tech AS.
5
6 This program is free software; you can redistribute it and/or modify it
7 under the terms of the GNU General Public License as published by the
8 Free Software Foundation; version 3.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
18
19 To the extent this program is licensed as part of the Enterprise
20 versions of CFEngine, the applicable Commercial Open Source License
21 (COSL) may apply to this file if you as a licensee so wish it. See
22 included file COSL.txt.
23 */
24
25 #include <platform.h>
26
27 #include <sysinfo.h>
28 #include <sysinfo_priv.h>
29 #include <cf3.extern.h>
30 #include <eval_context.h>
31 #include <files_names.h>
32 #include <files_interfaces.h>
33 #include <hash.h>
34 #include <scope.h>
35 #include <item_lib.h>
36 #include <matching.h>
37 #include <systype.h>
38 #include <unix.h>
39 #include <string_lib.h>
40 #include <regex.h> /* StringMatchFull */
41 #include <misc_lib.h>
42 #include <file_lib.h>
43 #include <rlist.h>
44 #include <audit.h>
45 #include <pipes.h>
46 #include <known_dirs.h>
47 #include <files_lib.h>
48 #include <printsize.h>
49 #include <cf-windows-functions.h>
50 #include <ornaments.h>
51 #include <feature.h>
52 #include <evalfunction.h>
53 #include <json-utils.h>
54
55 #ifdef HAVE_ZONE_H
56 # include <zone.h>
57 #endif
58
59 // HP-UX mpctl() for $(sys.cpus) on HP-UX - Mantis #1069
60 #ifdef HAVE_SYS_MPCTL_H
61 # include <sys/mpctl.h>
62 #endif
63
64 /* Linux.
65 WARNING keep this before the #include <sys/sysctl.h> because of glibc bug:
66 https://sourceware.org/bugzilla/show_bug.cgi?id=140 */
67 #ifdef HAVE_STRUCT_SYSINFO_UPTIME
68 # include <sys/sysinfo.h>
69 #endif
70
71 /* BSD, MAC OS X uptime calculation use KERN_BOOTTIME sysctl. */
72 #ifdef HAVE_SYS_SYSCTL_H
73 # ifdef HAVE_SYS_PARAM_H
74 # include <sys/param.h>
75 # endif
76 # ifdef __linux__
77 # include <linux/sysctl.h>
78 # else
79 # include <sys/sysctl.h>
80 # endif
81 #endif
82
83
84 /*****************************************************/
85 // Uptime calculation settings for GetUptimeSeconds() - Mantis #1134
86
87 /* Listed here in priority order, i.e. first come the platform-specific
88 * ways. If nothing works, one of the last, most generic ways should. */
89
90 #ifndef __MINGW32__ /* Windows is implemented in Enterprise */
91
92 // HP-UX: pstat_getproc(2) on init (pid 1)
93 #if defined(__hpux)
94 # include <sys/param.h>
95 # include <sys/pstat.h>
96 # define BOOT_TIME_WITH_PSTAT_GETPROC
97
98 // Solaris: kstat() for kernel statistics
99 // See http://dsc.sun.com/solaris/articles/kstatc.html
100 // BSD also has a kstat.h (albeit in sys), so check __sun just to be paranoid
101
102 /**
103 * @WARNING: Commented out because inside a Solaris 10 zone this gives the
104 * uptime of the host machine (the hypervisor). We thus choose to
105 * use UTMP for Solaris.
106 */
107 /*
108 #elif defined(__sun) && defined(HAVE_KSTAT_H)
109 # include <kstat.h>
110 # define BOOT_TIME_WITH_KSTAT
111 */
112
113 // BSD: sysctl(3) to get kern.boottime, CPU count, etc.
114 // See http://www.unix.com/man-page/FreeBSD/3/sysctl/
115 // Linux also has sys/sysctl.h, so we check KERN_BOOTTIME to make sure it's BSD
116 #elif defined(HAVE_SYS_SYSCTL_H) && defined(KERN_BOOTTIME)
117 # define BOOT_TIME_WITH_SYSCTL
118
119 // GNU/Linux: struct sysinfo.uptime
120 #elif defined(HAVE_STRUCT_SYSINFO_UPTIME)
121 # define BOOT_TIME_WITH_SYSINFO
122
123 /* Generic System V way, available in most platforms. */
124 #elif defined(HAVE_UTMP_H)
125 # include <utmp.h>
126 # define BOOT_TIME_WITH_UTMP
127
128 /* POSIX alternative (utmp.h does not exist on BSDs). */
129 #elif defined(HAVE_UTMPX_H)
130 # include <utmpx.h>
131 # define BOOT_TIME_WITH_UTMPX
132
133 #else
134 // Most generic way: {stat("/proc/1")}.st_ctime
135 // TODO in Solaris zones init is not guaranteed to be PID 1!
136 #define BOOT_TIME_WITH_PROCFS
137
138 #endif
139
140 /* Fallback uptime calculation: Parse the "uptime" command in case the
141 * platform-specific way fails or returns absurd number. */
142 static time_t GetBootTimeFromUptimeCommand(time_t now);
143
144 #endif /* ifndef __MINGW32__ */
145
146 #define LSB_RELEASE_FILENAME "/etc/lsb-release"
147 #define DEBIAN_VERSION_FILENAME "/etc/debian_version"
148 #define DEBIAN_ISSUE_FILENAME "/etc/issue"
149
150
151 /*****************************************************/
152
153 void CalculateDomainName(const char *nodename, const char *dnsname,
154 char *fqname, size_t fqname_size,
155 char *uqname, size_t uqname_size,
156 char *domain, size_t domain_size);
157
158 #ifdef __linux__
159 static int Linux_Fedora_Version(EvalContext *ctx);
160 static int Linux_Redhat_Version(EvalContext *ctx);
161 static void Linux_Amazon_Version(EvalContext *ctx);
162 static void Linux_Alpine_Version(EvalContext *ctx);
163 static void Linux_Oracle_VM_Server_Version(EvalContext *ctx);
164 static void Linux_Oracle_Version(EvalContext *ctx);
165 static int Linux_Suse_Version(EvalContext *ctx);
166 static int Linux_Slackware_Version(EvalContext *ctx, char *filename);
167 static int Linux_Debian_Version(EvalContext *ctx);
168 static int Linux_Misc_Version(EvalContext *ctx);
169 static int Linux_Mandrake_Version(EvalContext *ctx);
170 static int Linux_Mandriva_Version(EvalContext *ctx);
171 static int Linux_Mandriva_Version_Real(EvalContext *ctx, char *filename, char *relstring, char *vendor);
172 static int VM_Version(EvalContext *ctx);
173 static int Xen_Domain(EvalContext *ctx);
174 static int EOS_Version(EvalContext *ctx);
175 static int MiscOS(EvalContext *ctx);
176 static void OpenVZ_Detect(EvalContext *ctx);
177
178 static bool ReadLine(const char *filename, char *buf, int bufsize);
179 static FILE *ReadFirstLine(const char *filename, char *buf, int bufsize);
180 #endif
181
182 #ifdef XEN_CPUID_SUPPORT
183 static void Xen_Cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx);
184 static bool Xen_Hv_Check(void);
185 #endif
186
187 static void GetCPUInfo(EvalContext *ctx);
188
189 static const char *const CLASSATTRIBUTES[][3] =
190 {
191 [PLATFORM_CONTEXT_UNKNOWN] = {"-", "-", "-"}, /* as appear here are matched. The fields are sysname and machine */
192 [PLATFORM_CONTEXT_OPENVZ] = {"virt_host_vz_vzps", ".*", ".*"}, /* VZ with vzps */
193 [PLATFORM_CONTEXT_HP] = {"hp-ux", ".*", ".*"}, /* hpux */
194 [PLATFORM_CONTEXT_AIX] = {"aix", ".*", ".*"}, /* aix */
195 [PLATFORM_CONTEXT_LINUX] = {"linux", ".*", ".*"}, /* linux */
196 [PLATFORM_CONTEXT_BUSYBOX] = {"busybox", ".*", ".*"}, /* linux w/ busybox - warning uname returns linux */
197 [PLATFORM_CONTEXT_SOLARIS] = {"sunos", ".*",
198 "5\\.1[1-9].*"}, /* new solaris, SunOS >= 5.11 */
199 [PLATFORM_CONTEXT_SUN_SOLARIS] = {"sunos", ".*",
200 "5\\.([2-9]|10)(\\..*)?"}, /* old solaris, SunOS < 5.11 */
201 [PLATFORM_CONTEXT_FREEBSD] = {"freebsd", ".*", ".*"}, /* freebsd */
202 [PLATFORM_CONTEXT_NETBSD] = {"netbsd", ".*", ".*"}, /* NetBSD */
203 [PLATFORM_CONTEXT_CRAYOS] = {"sn.*", "cray*", ".*"}, /* cray */
204 [PLATFORM_CONTEXT_WINDOWS_NT] = {"cygwin_nt.*", ".*", ".*"}, /* NT (cygwin) */
205 [PLATFORM_CONTEXT_SYSTEMV] = {"unix_sv", ".*", ".*"}, /* Unixware */
206 [PLATFORM_CONTEXT_OPENBSD] = {"openbsd", ".*", ".*"}, /* OpenBSD */
207 [PLATFORM_CONTEXT_CFSCO] = {"sco_sv", ".*", ".*"}, /* SCO */
208 [PLATFORM_CONTEXT_DARWIN] = {"darwin", ".*", ".*"}, /* Darwin, aka MacOS X */
209 [PLATFORM_CONTEXT_QNX] = {"qnx", ".*", ".*"}, /* qnx */
210 [PLATFORM_CONTEXT_DRAGONFLY] = {"dragonfly", ".*", ".*"}, /* dragonfly */
211 [PLATFORM_CONTEXT_MINGW] = {"windows_nt.*", ".*", ".*"}, /* NT (native) */
212 [PLATFORM_CONTEXT_VMWARE] = {"vmkernel", ".*", ".*"}, /* VMWARE / ESX */
213 [PLATFORM_CONTEXT_ANDROID] = {"android", ".*", ".*"}, /* android: Warning uname returns linux */
214 };
215
216 static const char *const VRESOLVCONF[] =
217 {
218 [PLATFORM_CONTEXT_UNKNOWN] = "-",
219 [PLATFORM_CONTEXT_OPENVZ] = "/etc/resolv.conf", /* virt_host_vz_vzps */
220 [PLATFORM_CONTEXT_HP] = "/etc/resolv.conf", /* hpux */
221 [PLATFORM_CONTEXT_AIX] = "/etc/resolv.conf", /* aix */
222 [PLATFORM_CONTEXT_LINUX] = "/etc/resolv.conf", /* linux */
223 [PLATFORM_CONTEXT_BUSYBOX] = "/etc/resolv.conf", /* linux */
224 [PLATFORM_CONTEXT_SOLARIS] = "/etc/resolv.conf", /* new solaris */
225 [PLATFORM_CONTEXT_SUN_SOLARIS] = "/etc/resolv.conf", /* old solaris */
226 [PLATFORM_CONTEXT_FREEBSD] = "/etc/resolv.conf", /* freebsd */
227 [PLATFORM_CONTEXT_NETBSD] = "/etc/resolv.conf", /* netbsd */
228 [PLATFORM_CONTEXT_CRAYOS] = "/etc/resolv.conf", /* cray */
229 [PLATFORM_CONTEXT_WINDOWS_NT] = "/etc/resolv.conf", /* NT */
230 [PLATFORM_CONTEXT_SYSTEMV] = "/etc/resolv.conf", /* Unixware */
231 [PLATFORM_CONTEXT_OPENBSD] = "/etc/resolv.conf", /* openbsd */
232 [PLATFORM_CONTEXT_CFSCO] = "/etc/resolv.conf", /* sco */
233 [PLATFORM_CONTEXT_DARWIN] = "/etc/resolv.conf", /* darwin */
234 [PLATFORM_CONTEXT_QNX] = "/etc/resolv.conf", /* qnx */
235 [PLATFORM_CONTEXT_DRAGONFLY] = "/etc/resolv.conf", /* dragonfly */
236 [PLATFORM_CONTEXT_MINGW] = "", /* mingw */
237 [PLATFORM_CONTEXT_VMWARE] = "/etc/resolv.conf", /* vmware */
238 [PLATFORM_CONTEXT_ANDROID] = "", /* android */
239 };
240
241 static const char *const VMAILDIR[] =
242 {
243 [PLATFORM_CONTEXT_UNKNOWN] = "-",
244 [PLATFORM_CONTEXT_OPENVZ] = "/var/spool/mail", /* virt_host_vz_vzps */
245 [PLATFORM_CONTEXT_HP] = "/var/mail", /* hpux */
246 [PLATFORM_CONTEXT_AIX] = "/var/spool/mail", /* aix */
247 [PLATFORM_CONTEXT_LINUX] = "/var/spool/mail", /* linux */
248 [PLATFORM_CONTEXT_BUSYBOX] = "", /* linux */
249 [PLATFORM_CONTEXT_SOLARIS] = "/var/mail", /* new solaris */
250 [PLATFORM_CONTEXT_SUN_SOLARIS] = "/var/mail", /* old solaris */
251 [PLATFORM_CONTEXT_FREEBSD] = "/var/mail", /* freebsd */
252 [PLATFORM_CONTEXT_NETBSD] = "/var/mail", /* netbsd */
253 [PLATFORM_CONTEXT_CRAYOS] = "/usr/mail", /* cray */
254 [PLATFORM_CONTEXT_WINDOWS_NT] = "N/A", /* NT */
255 [PLATFORM_CONTEXT_SYSTEMV] = "/var/mail", /* Unixware */
256 [PLATFORM_CONTEXT_OPENBSD] = "/var/mail", /* openbsd */
257 [PLATFORM_CONTEXT_CFSCO] = "/var/spool/mail", /* sco */
258 [PLATFORM_CONTEXT_DARWIN] = "/var/mail", /* darwin */
259 [PLATFORM_CONTEXT_QNX] = "/var/spool/mail", /* qnx */
260 [PLATFORM_CONTEXT_DRAGONFLY] = "/var/mail", /* dragonfly */
261 [PLATFORM_CONTEXT_MINGW] = "", /* mingw */
262 [PLATFORM_CONTEXT_VMWARE] = "/var/spool/mail", /* vmware */
263 [PLATFORM_CONTEXT_ANDROID] = "", /* android */
264 };
265
266 static const char *const VEXPORTS[] =
267 {
268 [PLATFORM_CONTEXT_UNKNOWN] = "-",
269 [PLATFORM_CONTEXT_OPENVZ] = "/etc/exports", /* virt_host_vz_vzps */
270 [PLATFORM_CONTEXT_HP] = "/etc/exports", /* hpux */
271 [PLATFORM_CONTEXT_AIX] = "/etc/exports", /* aix */
272 [PLATFORM_CONTEXT_LINUX] = "/etc/exports", /* linux */
273 [PLATFORM_CONTEXT_BUSYBOX] = "", /* linux */
274 [PLATFORM_CONTEXT_SOLARIS] = "/etc/dfs/dfstab", /* new solaris */
275 [PLATFORM_CONTEXT_SUN_SOLARIS] = "/etc/dfs/dfstab", /* old solaris */
276 [PLATFORM_CONTEXT_FREEBSD] = "/etc/exports", /* freebsd */
277 [PLATFORM_CONTEXT_NETBSD] = "/etc/exports", /* netbsd */
278 [PLATFORM_CONTEXT_CRAYOS] = "/etc/exports", /* cray */
279 [PLATFORM_CONTEXT_WINDOWS_NT] = "/etc/exports", /* NT */
280 [PLATFORM_CONTEXT_SYSTEMV] = "/etc/dfs/dfstab", /* Unixware */
281 [PLATFORM_CONTEXT_OPENBSD] = "/etc/exports", /* openbsd */
282 [PLATFORM_CONTEXT_CFSCO] = "/etc/dfs/dfstab", /* sco */
283 [PLATFORM_CONTEXT_DARWIN] = "/etc/exports", /* darwin */
284 [PLATFORM_CONTEXT_QNX] = "/etc/exports", /* qnx */
285 [PLATFORM_CONTEXT_DRAGONFLY] = "/etc/exports", /* dragonfly */
286 [PLATFORM_CONTEXT_MINGW] = "", /* mingw */
287 [PLATFORM_CONTEXT_VMWARE] = "none", /* vmware */
288 [PLATFORM_CONTEXT_ANDROID] = "" , /* android */
289 };
290
291
292 /*******************************************************************/
293
CalculateDomainName(const char * nodename,const char * dnsname,char * fqname,size_t fqname_size,char * uqname,size_t uqname_size,char * domain,size_t domain_size)294 void CalculateDomainName(const char *nodename, const char *dnsname,
295 char *fqname, size_t fqname_size,
296 char *uqname, size_t uqname_size,
297 char *domain, size_t domain_size)
298 {
299 if (strstr(dnsname, "."))
300 {
301 strlcpy(fqname, dnsname, fqname_size);
302 }
303 else
304 {
305 strlcpy(fqname, nodename, fqname_size);
306 }
307
308 if ((strncmp(nodename, fqname, strlen(nodename)) == 0) && (fqname[strlen(nodename)] == '.'))
309 {
310 /* If hostname is not qualified */
311 strlcpy(domain, fqname + strlen(nodename) + 1, domain_size);
312 strlcpy(uqname, nodename, uqname_size);
313 }
314 else
315 {
316 /* If hostname is qualified */
317
318 char *p = strchr(nodename, '.');
319
320 if (p != NULL)
321 {
322 strlcpy(uqname, nodename, MIN(uqname_size, p - nodename + 1));
323 strlcpy(domain, p + 1, domain_size);
324 }
325 else
326 {
327 strlcpy(uqname, nodename, uqname_size);
328 strlcpy(domain, "", domain_size);
329 }
330 }
331 }
332
333 /*******************************************************************/
334
DetectDomainName(EvalContext * ctx,const char * orig_nodename)335 void DetectDomainName(EvalContext *ctx, const char *orig_nodename)
336 {
337 char nodename[CF_BUFSIZE];
338
339 strlcpy(nodename, orig_nodename, sizeof(nodename));
340 ToLowerStrInplace(nodename);
341
342 char dnsname[CF_BUFSIZE] = "";
343 char fqn[CF_BUFSIZE];
344
345 if (gethostname(fqn, sizeof(fqn)) != -1)
346 {
347 struct hostent *hp;
348
349 if ((hp = gethostbyname(fqn)))
350 {
351 strlcpy(dnsname, hp->h_name, sizeof(dnsname));
352 ToLowerStrInplace(dnsname);
353 }
354 }
355
356 CalculateDomainName(nodename, dnsname, VFQNAME, CF_MAXVARSIZE,
357 VUQNAME, CF_MAXVARSIZE, VDOMAIN, CF_MAXVARSIZE);
358
359 /*
360 * VFQNAME = a.b.c.d ->
361 * NewClass("a.b.c.d")
362 * NewClass("b.c.d")
363 * NewClass("c.d")
364 * NewClass("d")
365 */
366 char *ptr = VFQNAME;
367
368 do
369 {
370 EvalContextClassPutHard(ctx, ptr, "inventory,attribute_name=none,source=agent,derived-from=sys.fqhost");
371
372 ptr = strchr(ptr, '.');
373 if (ptr != NULL)
374 {
375 ptr++;
376 }
377 } while (ptr != NULL);
378
379 EvalContextClassPutHard(ctx, VUQNAME, "source=agent,derived-from=sys.uqhost");
380 EvalContextClassPutHard(ctx, VDOMAIN, "source=agent,derived-from=sys.domain");
381
382 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "host", nodename, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=none");
383 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "uqhost", VUQNAME, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=none");
384 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "fqhost", VFQNAME, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=Host name");
385 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "domain", VDOMAIN, CF_DATA_TYPE_STRING, "source=agent");
386 }
387
388 /*******************************************************************/
389
DiscoverVersion(EvalContext * ctx)390 void DiscoverVersion(EvalContext *ctx)
391 {
392 int major = 0;
393 int minor = 0;
394 int patch = 0;
395 char workbuf[CF_BUFSIZE];
396 if (sscanf(Version(), "%d.%d.%d", &major, &minor, &patch) == 3)
397 {
398 snprintf(workbuf, CF_MAXVARSIZE, "%d", major);
399 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_major", workbuf, CF_DATA_TYPE_STRING, "source=agent");
400 snprintf(workbuf, CF_MAXVARSIZE, "%d", minor);
401 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_minor", workbuf, CF_DATA_TYPE_STRING, "source=agent");
402 snprintf(workbuf, CF_MAXVARSIZE, "%d", patch);
403 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_patch", workbuf, CF_DATA_TYPE_STRING, "source=agent");
404 }
405 else
406 {
407 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_major", "BAD VERSION " VERSION, CF_DATA_TYPE_STRING, "source=agent");
408 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_minor", "BAD VERSION " VERSION, CF_DATA_TYPE_STRING, "source=agent");
409 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_patch", "BAD VERSION " VERSION, CF_DATA_TYPE_STRING, "source=agent");
410 }
411
412 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version_release", RELEASE, CF_DATA_TYPE_STRING, "source=agent");
413
414 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "local_libdir", "lib", CF_DATA_TYPE_STRING, "source=agent");
415
416 snprintf(workbuf, CF_BUFSIZE, "%s%cinputs%clib", GetWorkDir(), FILE_SEPARATOR, FILE_SEPARATOR);
417 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "libdir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
418 }
419
GetNameInfo3(EvalContext * ctx)420 static void GetNameInfo3(EvalContext *ctx)
421 {
422 int i, found = false;
423 char *sp, workbuf[CF_BUFSIZE];
424 time_t tloc;
425 struct hostent *hp;
426 struct sockaddr_in cin;
427 unsigned char digest[EVP_MAX_MD_SIZE + 1];
428 const char* const workdir = GetWorkDir();
429 const char* const bindir = GetBinDir();
430
431 #ifdef _AIX
432 char real_version[_SYS_NMLN];
433 #endif
434 #if defined(HAVE_SYSINFO) && (defined(SI_ARCHITECTURE) || defined(SI_PLATFORM))
435 long sz;
436 #endif
437
438 #define COMPONENTS_SIZE 16
439 // This is used for $(sys.cf_agent), $(sys.cf_serverd) ... :
440 char *components[COMPONENTS_SIZE] = { "cf-twin", "cf-agent", "cf-serverd", "cf-monitord", "cf-know",
441 "cf-report", "cf-key", "cf-runagent", "cf-execd", "cf-hub",
442 "cf-promises", "cf-upgrade", "cf-net", "cf-check", "cf-secret",
443 NULL
444 };
445 int have_component[COMPONENTS_SIZE];
446 struct stat sb;
447 char name[CF_MAXVARSIZE], quoteName[CF_MAXVARSIZE], shortname[CF_MAXVARSIZE];
448
449 if (uname(&VSYSNAME) == -1)
450 {
451 Log(LOG_LEVEL_ERR, "Couldn't get kernel name info!. (uname: %s)", GetErrorStr());
452 memset(&VSYSNAME, 0, sizeof(VSYSNAME));
453 }
454
455 #ifdef _AIX
456 snprintf(real_version, _SYS_NMLN, "%.80s.%.80s", VSYSNAME.version, VSYSNAME.release);
457 strlcpy(VSYSNAME.release, real_version, _SYS_NMLN);
458 #endif
459 #ifdef __ANDROID__
460 /*
461 * uname cannot differentiate android from linux
462 */
463 strcpy(VSYSNAME.sysname, "android");
464 #endif
465 #ifdef __BUSYBOX__
466 /*
467 * uname cannot differentiate a busybox toolset from a normal GNU linux toolset
468 */
469 strcpy(VSYSNAME.sysname, "busybox");
470 #endif
471
472 ToLowerStrInplace(VSYSNAME.sysname);
473 ToLowerStrInplace(VSYSNAME.machine);
474
475 #ifdef _AIX
476 switch (_system_configuration.architecture)
477 {
478 case POWER_RS:
479 strlcpy(VSYSNAME.machine, "power", _SYS_NMLN);
480 break;
481 case POWER_PC:
482 strlcpy(VSYSNAME.machine, "powerpc", _SYS_NMLN);
483 break;
484 case IA64:
485 strlcpy(VSYSNAME.machine, "ia64", _SYS_NMLN);
486 break;
487 }
488 #endif
489
490 /*
491 * solarisx86 is a historically defined class for Solaris on x86. We have to
492 * define it manually now.
493 */
494 #ifdef __sun
495 if (strcmp(VSYSNAME.machine, "i86pc") == 0)
496 {
497 EvalContextClassPutHard(ctx, "solarisx86", "inventory,attribute_name=none,source=agent");
498 }
499 #endif
500
501 DetectDomainName(ctx, VSYSNAME.nodename);
502
503 if ((tloc = time((time_t *) NULL)) == -1)
504 {
505 Log(LOG_LEVEL_ERR, "Couldn't read system clock");
506 }
507 else
508 {
509 snprintf(workbuf, CF_BUFSIZE, "%jd", (intmax_t) tloc);
510 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "systime", workbuf, CF_DATA_TYPE_INT, "time_based,source=agent");
511 snprintf(workbuf, CF_BUFSIZE, "%jd", (intmax_t) tloc / SECONDS_PER_DAY);
512 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "sysday", workbuf, CF_DATA_TYPE_INT, "time_based,source=agent");
513 i = GetUptimeMinutes(tloc);
514 if (i != -1)
515 {
516 snprintf(workbuf, CF_BUFSIZE, "%d", i);
517 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "uptime", workbuf, CF_DATA_TYPE_INT, "inventory,time_based,source=agent,attribute_name=Uptime minutes");
518 }
519 }
520
521 for (i = 0; i < PLATFORM_CONTEXT_MAX; i++)
522 {
523 char sysname[CF_BUFSIZE];
524 strlcpy(sysname, VSYSNAME.sysname, CF_BUFSIZE);
525 ToLowerStrInplace(sysname);
526
527 /* FIXME: review those strcmps. Moved out from StringMatch */
528 if (!strcmp(CLASSATTRIBUTES[i][0], sysname)
529 || StringMatchFull(CLASSATTRIBUTES[i][0], sysname))
530 {
531 if (!strcmp(CLASSATTRIBUTES[i][1], VSYSNAME.machine)
532 || StringMatchFull(CLASSATTRIBUTES[i][1], VSYSNAME.machine))
533 {
534 if (!strcmp(CLASSATTRIBUTES[i][2], VSYSNAME.release)
535 || StringMatchFull(CLASSATTRIBUTES[i][2], VSYSNAME.release))
536 {
537 EvalContextClassPutHard(ctx, CLASSTEXT[i], "inventory,attribute_name=none,source=agent,derived-from=sys.class");
538
539 found = true;
540
541 VSYSTEMHARDCLASS = (PlatformContext) i;
542 VPSHARDCLASS = (PlatformContext) i; /* this one can be overriden at vz detection */
543 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "class", CLASSTEXT[i], CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=OS type");
544 break;
545 }
546 }
547 else
548 {
549 Log(LOG_LEVEL_DEBUG, "I recognize '%s' but not '%s'", VSYSNAME.sysname, VSYSNAME.machine);
550 continue;
551 }
552 }
553 }
554
555 if (!found)
556 {
557 i = 0;
558 }
559
560 Log(LOG_LEVEL_VERBOSE, "%s - ready", NameVersion());
561 Banner("Environment discovery");
562
563 snprintf(workbuf, CF_BUFSIZE, "%s", CLASSTEXT[i]);
564
565
566 Log(LOG_LEVEL_VERBOSE, "Host name is: %s", VSYSNAME.nodename);
567 Log(LOG_LEVEL_VERBOSE, "Operating System Type is %s", VSYSNAME.sysname);
568 Log(LOG_LEVEL_VERBOSE, "Operating System Release is %s", VSYSNAME.release);
569 Log(LOG_LEVEL_VERBOSE, "Architecture = %s", VSYSNAME.machine);
570 Log(LOG_LEVEL_VERBOSE, "CFEngine detected operating system description is %s", workbuf);
571 Log(LOG_LEVEL_VERBOSE, "The time is now %s", ctime(&tloc));
572
573 snprintf(workbuf, CF_MAXVARSIZE, "%s", ctime(&tloc));
574 Chop(workbuf, CF_EXPANDSIZE);
575
576 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "date", workbuf, CF_DATA_TYPE_STRING, "time_based,source=agent");
577 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cdate", CanonifyName(workbuf), CF_DATA_TYPE_STRING, "time_based,source=agent");
578 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "os", VSYSNAME.sysname, CF_DATA_TYPE_STRING, "source=agent");
579 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "release", VSYSNAME.release, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=OS kernel");
580 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "version", VSYSNAME.version, CF_DATA_TYPE_STRING, "source=agent");
581 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "arch", VSYSNAME.machine, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=Architecture");
582 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "workdir", workdir, CF_DATA_TYPE_STRING, "source=agent");
583 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "fstab", VFSTAB[VSYSTEMHARDCLASS], CF_DATA_TYPE_STRING, "source=agent");
584 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "resolv", VRESOLVCONF[VSYSTEMHARDCLASS], CF_DATA_TYPE_STRING, "source=agent");
585 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "maildir", VMAILDIR[VSYSTEMHARDCLASS], CF_DATA_TYPE_STRING, "source=agent");
586 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "exports", VEXPORTS[VSYSTEMHARDCLASS], CF_DATA_TYPE_STRING, "source=agent");
587 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "logdir", GetLogDir(), CF_DATA_TYPE_STRING, "source=agent");
588 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "piddir", GetPidDir(), CF_DATA_TYPE_STRING, "source=agent");
589 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "statedir", GetStateDir(), CF_DATA_TYPE_STRING, "source=agent");
590 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "masterdir", GetMasterDir(), CF_DATA_TYPE_STRING, "source=agent");
591 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "inputdir", GetInputDir(), CF_DATA_TYPE_STRING, "source=agent");
592
593 snprintf(workbuf, CF_BUFSIZE, "%s", bindir);
594 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "bindir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
595
596 snprintf(workbuf, CF_BUFSIZE, "%s%cpromises.cf", GetInputDir(), FILE_SEPARATOR);
597 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "default_policy_path", workbuf, CF_DATA_TYPE_STRING, "source=agent");
598
599 snprintf(workbuf, CF_BUFSIZE, "%s%cfailsafe.cf", GetInputDir(), FILE_SEPARATOR);
600 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "failsafe_policy_path", workbuf, CF_DATA_TYPE_STRING, "source=agent");
601
602 snprintf(workbuf, CF_BUFSIZE, "%s%cupdate.cf", GetInputDir(), FILE_SEPARATOR);
603 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "update_policy_path", workbuf, CF_DATA_TYPE_STRING, "source=agent");
604
605 /* FIXME: type conversion */
606 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cf_version", (char *) Version(), CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=CFEngine version");
607
608 DiscoverVersion(ctx);
609
610 if (PUBKEY)
611 {
612 char pubkey_digest[CF_HOSTKEY_STRING_SIZE] = { 0 };
613
614 HashPubKey(PUBKEY, digest, CF_DEFAULT_DIGEST);
615 HashPrintSafe(pubkey_digest, sizeof(pubkey_digest), digest,
616 CF_DEFAULT_DIGEST, true);
617
618 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "key_digest", pubkey_digest, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=CFEngine ID");
619
620 snprintf(workbuf, CF_MAXVARSIZE - 1, "PK_%s", pubkey_digest);
621 CanonifyNameInPlace(workbuf);
622 EvalContextClassPutHard(ctx, workbuf, "inventory,attribute_name=none,source=agent,derived-from=sys.key_digest");
623 }
624
625 for (i = 0; components[i] != NULL; i++)
626 {
627 snprintf(shortname, CF_MAXVARSIZE - 1, "%s", CanonifyName(components[i]));
628
629 #if defined(_WIN32)
630 // twin has own dir, and is named agent
631 if (i == 0)
632 {
633 snprintf(name, CF_MAXVARSIZE - 1, "%s-twin%ccf-agent.exe", bindir, FILE_SEPARATOR);
634 }
635 else
636 {
637 snprintf(name, CF_MAXVARSIZE - 1, "%s%c%s.exe", bindir, FILE_SEPARATOR, components[i]);
638 }
639 #else
640 snprintf(name, CF_MAXVARSIZE - 1, "%s%c%s", bindir, FILE_SEPARATOR, components[i]);
641 #endif
642
643 have_component[i] = false;
644
645 if (stat(name, &sb) != -1)
646 {
647 snprintf(quoteName, sizeof(quoteName), "\"%s\"", name);
648 // Sets $(sys.cf_agent), $(sys.cf_serverd) $(sys.cf_execd) etc.
649 // to their respective /bin paths
650 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, shortname, quoteName, CF_DATA_TYPE_STRING, "cfe_internal,source=agent");
651 have_component[i] = true;
652 }
653 }
654
655 // If no twin, fail over the agent
656
657 if (!have_component[0])
658 {
659 snprintf(shortname, CF_MAXVARSIZE - 1, "%s", CanonifyName(components[0]));
660
661 #if defined(_WIN32)
662 snprintf(name, CF_MAXVARSIZE - 1, "%s%c%s.exe", bindir, FILE_SEPARATOR,
663 components[1]);
664 #else
665 snprintf(name, CF_MAXVARSIZE - 1, "%s%c%s", bindir, FILE_SEPARATOR, components[1]);
666 #endif
667
668 if (stat(name, &sb) != -1)
669 {
670 snprintf(quoteName, sizeof(quoteName), "\"%s\"", name);
671 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, shortname, quoteName, CF_DATA_TYPE_STRING, "cfe_internal,source=agent");
672 }
673 }
674
675 /* Windows special directories and tools */
676
677 #ifdef __MINGW32__
678 if (NovaWin_GetWinDir(workbuf, sizeof(workbuf)))
679 {
680 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "windir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
681 }
682
683 if (NovaWin_GetSysDir(workbuf, sizeof(workbuf)))
684 {
685 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "winsysdir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
686
687 char filename[CF_BUFSIZE];
688 if (snprintf(filename, sizeof(filename), "%s%s", workbuf, "\\WindowsPowerShell\\v1.0\\powershell.exe") < sizeof(filename))
689 {
690 if (NovaWin_FileExists(filename))
691 {
692 EvalContextClassPutHard(ctx, "powershell", "inventory,attribute_name=none,source=agent");
693 Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", "powershell");
694 }
695 }
696 }
697
698 if (NovaWin_GetProgDir(workbuf, sizeof(workbuf)))
699 {
700 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "winprogdir", workbuf, CF_DATA_TYPE_STRING, "source=agent");
701 }
702
703 # ifdef _WIN64
704 // only available on 64 bit windows systems
705 if (NovaWin_GetEnv("PROGRAMFILES(x86)", workbuf, sizeof(workbuf)))
706 {
707 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "winprogdir86", workbuf, CF_DATA_TYPE_STRING, "source=agent");
708 }
709
710 # else/* NOT _WIN64 */
711
712 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "winprogdir86", "", CF_DATA_TYPE_STRING, "source=agent");
713
714 # endif
715 #endif /* !__MINGW32__ */
716
717 EnterpriseContext(ctx);
718
719 snprintf(workbuf, sizeof(workbuf), "%u_bit", (unsigned) sizeof(void*) * 8);
720 EvalContextClassPutHard(ctx, workbuf, "source=agent");
721 Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", CanonifyName(workbuf));
722
723 snprintf(workbuf, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, VSYSNAME.release);
724 EvalContextClassPutHard(ctx, workbuf, "inventory,attribute_name=none,source=agent,derived-from=sys.sysname,derived-from=sys.release");
725
726 EvalContextClassPutHard(ctx, VSYSNAME.machine, "source=agent,derived-from=sys.machine");
727 Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", CanonifyName(workbuf));
728
729 snprintf(workbuf, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, VSYSNAME.machine);
730 EvalContextClassPutHard(ctx, workbuf, "source=agent,derived-from=sys.sysname,derived-from=sys.machine");
731 Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", CanonifyName(workbuf));
732
733 snprintf(workbuf, CF_BUFSIZE, "%s_%s_%s", VSYSNAME.sysname, VSYSNAME.machine, VSYSNAME.release);
734 EvalContextClassPutHard(ctx, workbuf, "source=agent,derived-from=sys.sysname,derived-from=sys.machine,derived-from=sys.release");
735 Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", CanonifyName(workbuf));
736
737 #ifdef HAVE_SYSINFO
738 # ifdef SI_ARCHITECTURE
739 sz = sysinfo(SI_ARCHITECTURE, workbuf, CF_BUFSIZE);
740 if (sz == -1)
741 {
742 Log(LOG_LEVEL_VERBOSE, "cfengine internal: sysinfo returned -1");
743 }
744 else
745 {
746 EvalContextClassPutHard(ctx, workbuf, "inventory,attribute_name=none,source=agent");
747 Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", workbuf);
748 }
749 # endif
750 # ifdef SI_PLATFORM
751 sz = sysinfo(SI_PLATFORM, workbuf, CF_BUFSIZE);
752 if (sz == -1)
753 {
754 Log(LOG_LEVEL_VERBOSE, "cfengine internal: sysinfo returned -1");
755 }
756 else
757 {
758 EvalContextClassPutHard(ctx, workbuf, "inventory,attribute_name=none,source=agent");
759 Log(LOG_LEVEL_VERBOSE, "Additional hard class defined as: %s", workbuf);
760 }
761 # endif
762 #endif
763
764 snprintf(workbuf, CF_BUFSIZE, "%s_%s_%s_%s", VSYSNAME.sysname, VSYSNAME.machine, VSYSNAME.release,
765 VSYSNAME.version);
766
767 if (strlen(workbuf) > CF_MAXVARSIZE - 2)
768 {
769 Log(LOG_LEVEL_VERBOSE, "cfengine internal: $(arch) overflows CF_MAXVARSIZE! Truncating");
770 }
771
772 sp = xstrdup(CanonifyName(workbuf));
773 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "long_arch", sp, CF_DATA_TYPE_STRING, "source=agent");
774 EvalContextClassPutHard(ctx, sp, "source=agent,derived-from=sys.long_arch");
775 free(sp);
776
777 snprintf(workbuf, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, VSYSNAME.machine);
778 sp = xstrdup(CanonifyName(workbuf));
779 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "ostype", sp, CF_DATA_TYPE_STRING, "source=agent");
780 EvalContextClassPutHard(ctx, sp, "inventory,attribute_name=none,source=agent,derived-from=sys.ostype");
781 free(sp);
782
783 if (!found)
784 {
785 Log(LOG_LEVEL_ERR, "I don't understand what architecture this is");
786 }
787
788 char compile_str[] = "compiled_on_";
789 size_t compile_str_len = sizeof(compile_str);
790 strcpy(workbuf, compile_str);
791
792 strlcat(workbuf, CanonifyName(AUTOCONF_SYSNAME),
793 CF_BUFSIZE - compile_str_len);
794 EvalContextClassPutHard(ctx, workbuf, "source=agent");
795 Log(LOG_LEVEL_VERBOSE, "GNU autoconf class from compile time: %s", workbuf);
796
797 /* Get IP address from nameserver */
798
799 if ((hp = gethostbyname(VFQNAME)) == NULL)
800 {
801 Log(LOG_LEVEL_VERBOSE, "Hostname lookup failed on node name '%s'", VSYSNAME.nodename);
802 return;
803 }
804 else
805 {
806 memset(&cin, 0, sizeof(cin));
807 cin.sin_addr.s_addr = ((struct in_addr *) (hp->h_addr))->s_addr;
808 Log(LOG_LEVEL_VERBOSE, "Address given by nameserver: %s", inet_ntoa(cin.sin_addr));
809 strcpy(VIPADDRESS, inet_ntoa(cin.sin_addr));
810
811 for (i = 0; hp->h_aliases[i] != NULL; i++)
812 {
813 Log(LOG_LEVEL_DEBUG, "Adding alias '%s'", hp->h_aliases[i]);
814 EvalContextClassPutHard(ctx, hp->h_aliases[i], "inventory,attribute_name=none,source=agent,based-on=sys.fqhost");
815 }
816 }
817
818 #ifdef HAVE_GETZONEID
819 zoneid_t zid;
820 char zone[ZONENAME_MAX];
821 char vbuff[CF_BUFSIZE];
822
823 zid = getzoneid();
824 getzonenamebyid(zid, zone, ZONENAME_MAX);
825
826 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "zone", zone, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=Solaris zone");
827 snprintf(vbuff, CF_BUFSIZE - 1, "zone_%s", zone);
828 EvalContextClassPutHard(ctx, vbuff, "source=agent,derived-from=sys.zone");
829
830 if (strcmp(zone, "global") == 0)
831 {
832 Log(LOG_LEVEL_VERBOSE, "CFEngine seems to be running inside a global solaris zone of name '%s'", zone);
833 }
834 else
835 {
836 Log(LOG_LEVEL_VERBOSE, "CFEngine seems to be running inside a local solaris zone of name '%s'", zone);
837 }
838 #endif
839 }
840
841 /*******************************************************************/
842
LoadSlowlyVaryingObservations(EvalContext * ctx)843 void LoadSlowlyVaryingObservations(EvalContext *ctx)
844 {
845 CF_DB *dbp;
846 CF_DBC *dbcp;
847 char *key;
848 void *stored;
849 int ksize, vsize;
850
851 if (!OpenDB(&dbp, dbid_static))
852 {
853 return;
854 }
855
856 /* Acquire a cursor for the database. */
857 if (!NewDBCursor(dbp, &dbcp))
858 {
859 Log(LOG_LEVEL_INFO, "Unable to scan class db");
860 CloseDB(dbp);
861 return;
862 }
863
864 while (NextDB(dbcp, &key, &ksize, &stored, &vsize))
865 {
866 if (key == NULL || stored == NULL)
867 {
868 continue;
869 }
870
871 char lval[1024];
872 int type_i;
873 int ret = sscanf(key, "%1023[^:]:%d", lval, &type_i);
874 if (ret == 2)
875 {
876 DataType type = type_i;
877 switch (type)
878 {
879 case CF_DATA_TYPE_STRING:
880 case CF_DATA_TYPE_INT:
881 case CF_DATA_TYPE_REAL:
882 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_MON,
883 lval, stored, type,
884 "monitoring,source=observation");
885 break;
886
887 case CF_DATA_TYPE_STRING_LIST:
888 {
889 Rlist *list = RlistFromSplitString(stored, ',');
890 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_MON,
891 lval, list, CF_DATA_TYPE_STRING_LIST,
892 "monitoring,source=observation");
893 RlistDestroy(list);
894 break;
895 }
896 case CF_DATA_TYPE_COUNTER:
897 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_MON,
898 lval, stored, CF_DATA_TYPE_STRING,
899 "monitoring,source=observation");
900 break;
901
902 default:
903 Log(LOG_LEVEL_ERR,
904 "Unexpected monitoring type %d found in dbid_static database",
905 (int) type);
906 }
907 }
908 }
909
910 DeleteDBCursor(dbcp);
911 CloseDB(dbp);
912 }
913
Get3Environment(EvalContext * ctx)914 static void Get3Environment(EvalContext *ctx)
915 {
916 char env[CF_BUFSIZE], context[CF_BUFSIZE], name[CF_MAXVARSIZE], value[CF_BUFSIZE];
917 struct stat statbuf;
918 time_t now = time(NULL);
919
920 Log(LOG_LEVEL_VERBOSE, "Looking for environment from cf-monitord...");
921
922 snprintf(env, CF_BUFSIZE, "%s/%s", GetStateDir(), CF_ENV_FILE);
923 MapName(env);
924
925 FILE *fp = safe_fopen(env, "r");
926 if (fp == NULL)
927 {
928 Log(LOG_LEVEL_VERBOSE, "Unable to detect environment from cf-monitord");
929 return;
930 }
931
932 int fd = fileno(fp);
933 if (fstat(fd, &statbuf) == -1)
934 {
935 Log(LOG_LEVEL_VERBOSE, "Unable to detect environment from cf-monitord");
936 fclose(fp);
937 return;
938 }
939
940 if (statbuf.st_mtime < (now - 60 * 60))
941 {
942 Log(LOG_LEVEL_VERBOSE, "Environment data are too old - discarding");
943 unlink(env);
944 fclose(fp);
945 return;
946 }
947
948 snprintf(value, CF_MAXVARSIZE - 1, "%s", ctime(&statbuf.st_mtime));
949 if (Chop(value, CF_EXPANDSIZE) == -1)
950 {
951 Log(LOG_LEVEL_ERR, "Chop was called on a string that seemed to have no terminator");
952 }
953
954 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_MON, "env_time", value, CF_DATA_TYPE_STRING, "time_based,source=agent");
955
956 Log(LOG_LEVEL_VERBOSE, "Loading environment...");
957
958 for(;;)
959 {
960 name[0] = '\0';
961 value[0] = '\0';
962
963 if (fgets(context, sizeof(context), fp) == NULL)
964 {
965 if (ferror(fp))
966 {
967 UnexpectedError("Failed to read line from stream");
968 break;
969 }
970 else /* feof */
971 {
972 break;
973 }
974 }
975
976
977 if (*context == '@')
978 {
979 assert((sizeof(name)) > 255); // TODO: static_assert()
980 assert((sizeof(value)) > 255); // TODO: static_assert()
981 if (sscanf(context + 1, "%255[^=]=%255[^\n]", name, value) == 2)
982 {
983 Log(LOG_LEVEL_DEBUG,
984 "Setting new monitoring list '%s' => '%s'",
985 name, value);
986 Rlist *list = RlistParseShown(value);
987 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_MON,
988 name, list,
989 CF_DATA_TYPE_STRING_LIST,
990 "monitoring,source=environment");
991
992 RlistDestroy(list);
993 }
994 else
995 {
996 Log(LOG_LEVEL_ERR,
997 "Failed to parse '%s' as '@variable=list' monitoring list",
998 context);
999 }
1000 }
1001 else if (strchr(context, '='))
1002 {
1003 assert((sizeof(name)) > 255); // TODO: static_assert()
1004 assert((sizeof(value)) > 255); // TODO: static_assert()
1005 if (sscanf(context, "%255[^=]=%255[^\n]", name, value) == 2)
1006 {
1007 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_MON,
1008 name, value,
1009 CF_DATA_TYPE_STRING,
1010 "monitoring,source=environment");
1011 Log(LOG_LEVEL_DEBUG,
1012 "Setting new monitoring scalar '%s' => '%s'",
1013 name, value);
1014 }
1015 else
1016 {
1017 Log(LOG_LEVEL_ERR,
1018 "Failed to parse '%s' as 'variable=value' monitoring scalar",
1019 context);
1020 }
1021 }
1022 else
1023 {
1024 StripTrailingNewline(context, CF_BUFSIZE);
1025 EvalContextClassPutHard(ctx, context, "monitoring,source=environment");
1026 }
1027 }
1028
1029 fclose(fp);
1030 Log(LOG_LEVEL_VERBOSE, "Environment data loaded");
1031
1032 LoadSlowlyVaryingObservations(ctx);
1033 }
1034
BuiltinClasses(EvalContext * ctx)1035 static void BuiltinClasses(EvalContext *ctx)
1036 {
1037 char vbuff[CF_BUFSIZE];
1038
1039 EvalContextClassPutHard(ctx, "any", "source=agent"); /* This is a reserved word / wildcard */
1040
1041 snprintf(vbuff, CF_BUFSIZE, "cfengine_%s", CanonifyName(Version()));
1042 CreateHardClassesFromCanonification(ctx, vbuff, "inventory,attribute_name=none,source=agent");
1043
1044 CreateHardClassesFromFeatures(ctx, "source=agent");
1045 }
1046
1047 /*******************************************************************/
1048
CreateHardClassesFromCanonification(EvalContext * ctx,const char * canonified,char * tags)1049 void CreateHardClassesFromCanonification(EvalContext *ctx, const char *canonified, char *tags)
1050 {
1051 char buf[CF_MAXVARSIZE];
1052
1053 strlcpy(buf, canonified, sizeof(buf));
1054
1055 EvalContextClassPutHard(ctx, buf, tags);
1056
1057 char *sp;
1058
1059 while ((sp = strrchr(buf, '_')))
1060 {
1061 *sp = 0;
1062 EvalContextClassPutHard(ctx, buf, tags);
1063 }
1064 }
1065
SetFlavor(EvalContext * ctx,const char * flavor)1066 static void SetFlavor(EvalContext *ctx, const char *flavor)
1067 {
1068 EvalContextClassPutHard(ctx, flavor, "inventory,attribute_name=none,source=agent,derived-from=sys.flavor");
1069 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "flavour", flavor, CF_DATA_TYPE_STRING, "source=agent");
1070 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "flavor", flavor, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=none");
1071 }
1072
1073 #ifdef __linux__
1074
1075 /**
1076 * @brief Combines OS and version string to define flavor variable and class
1077 *
1078 * @note Input strings should be canonified before calling
1079 */
SetFlavor2(EvalContext * const ctx,const char * const id,const char * const major_version)1080 static void SetFlavor2(
1081 EvalContext *const ctx,
1082 const char *const id,
1083 const char *const major_version)
1084 {
1085 assert(ctx != NULL);
1086 assert(id != NULL);
1087 assert(major_version != NULL);
1088
1089 char *flavor;
1090 xasprintf(&flavor, "%s_%s", id, major_version);
1091 SetFlavor(ctx, flavor);
1092 free(flavor);
1093 }
1094
1095 /**
1096 * @brief Combines OS and version string to define multiple hard classes
1097 *
1098 * @note Input strings should be canonified before calling
1099 */
DefineVersionedHardClasses(EvalContext * const ctx,const char * const tags,const char * const id,const char * const version)1100 static void DefineVersionedHardClasses(
1101 EvalContext *const ctx,
1102 const char *const tags,
1103 const char *const id,
1104 const char *const version)
1105 {
1106 assert(ctx != NULL);
1107 assert(id != NULL);
1108 assert(version != NULL);
1109
1110 char *class;
1111 xasprintf(&class, "%s_%s", id, version);
1112
1113 // Strip away version number to define multiple hard classes
1114 // Example: coreos_1185_3_0 -> coreos_1185_3 -> coreos_1185 -> coreos
1115 char *last_underscore = strrchr(class, '_');
1116 while ( last_underscore != NULL )
1117 {
1118 EvalContextClassPutHard(ctx, class, tags);
1119 *last_underscore = '\0';
1120 last_underscore = strrchr(class, '_');
1121 }
1122 EvalContextClassPutHard(ctx, class, tags);
1123 free(class);
1124 }
1125
OSReleaseParse(EvalContext * ctx,const char * file_path)1126 static void OSReleaseParse(EvalContext *ctx, const char *file_path)
1127 {
1128 JsonElement *os_release_json = JsonReadDataFile("system info discovery",
1129 file_path, DATAFILETYPE_ENV,
1130 100 * 1024);
1131 if (os_release_json != NULL)
1132 {
1133 char *tags;
1134 xasprintf(&tags,
1135 "inventory,attribute_name=none,source=agent,derived-from-file=%s",
1136 file_path);
1137 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "os_release",
1138 os_release_json, CF_DATA_TYPE_CONTAINER,
1139 tags);
1140 const char *const_os_release_id = JsonObjectGetAsString(os_release_json, "ID");
1141 const char *const_os_release_version_id = JsonObjectGetAsString(os_release_json, "VERSION_ID");
1142 char *os_release_id = SafeStringDuplicate(const_os_release_id);
1143 char *os_release_version_id = SafeStringDuplicate(const_os_release_version_id);
1144
1145 if (os_release_id != NULL)
1146 {
1147 CanonifyNameInPlace(os_release_id);
1148
1149 const char *alias = NULL;
1150 if (StringEqual(os_release_id, "rhel"))
1151 {
1152 alias = "redhat";
1153 }
1154
1155 if (os_release_version_id == NULL)
1156 {
1157 // if VERSION_ID doesn't exist, define only one hard class:
1158 EvalContextClassPutHard(ctx, os_release_id, tags);
1159 if (alias != NULL)
1160 {
1161 EvalContextClassPutHard(ctx, alias, tags);
1162 }
1163 }
1164 else // if VERSION_ID exists set flavor and multiple hard classes:
1165 {
1166 CanonifyNameInPlace(os_release_version_id);
1167
1168 // Set the flavor to be ID + major version (derived from VERSION_ID)
1169 char *first_underscore = strchr(os_release_version_id, '_');
1170 if (first_underscore != NULL)
1171 {
1172 // Temporarily modify os_release_version_id to be major version
1173 *first_underscore = '\0';
1174 SetFlavor2(ctx, os_release_id, os_release_version_id);
1175 *first_underscore = '_';
1176 }
1177 else
1178 {
1179 SetFlavor2(ctx, os_release_id, os_release_version_id);
1180 }
1181
1182 // One of the hard classes is already set by SetFlavor
1183 // but it seems excessive to try to skip this:
1184 DefineVersionedHardClasses(ctx, tags, os_release_id, os_release_version_id);
1185 if (alias != NULL)
1186 {
1187 DefineVersionedHardClasses(ctx, tags, alias, os_release_version_id);
1188 }
1189 }
1190 }
1191 free(os_release_version_id);
1192 free(os_release_id);
1193 free(tags);
1194 JsonDestroy(os_release_json);
1195 }
1196 }
1197 #endif
1198
OSClasses(EvalContext * ctx)1199 static void OSClasses(EvalContext *ctx)
1200 {
1201 #ifdef __linux__
1202
1203 /* First we check if init process is systemd, and set "systemd" hard class. */
1204
1205 {
1206 char init_path[CF_BUFSIZE];
1207 if (ReadLine("/proc/1/cmdline", init_path, sizeof(init_path)))
1208 {
1209 /* Follow possible symlinks. */
1210
1211 char resolved_path[PATH_MAX]; /* realpath() needs PATH_MAX */
1212 if (realpath(init_path, resolved_path) != NULL &&
1213 strlen(resolved_path) < sizeof(init_path))
1214 {
1215 strcpy(init_path, resolved_path);
1216 }
1217
1218 /* Check if string ends with "/systemd". */
1219 char *p;
1220 char *next_p = NULL;
1221 const char *term = "/systemd";
1222 do
1223 {
1224 p = next_p;
1225 next_p = strstr(next_p ? next_p+strlen(term) : init_path, term);
1226 }
1227 while (next_p);
1228
1229 if (p != NULL &&
1230 p[strlen("/systemd")] == '\0')
1231 {
1232 EvalContextClassPutHard(ctx, "systemd",
1233 "inventory,attribute_name=none,source=agent");
1234 }
1235 }
1236 }
1237
1238
1239 struct stat statbuf;
1240
1241 // os-release is used to set sys.os_release, sys.flavor and hard classes
1242 if (access("/etc/os-release", R_OK) != -1)
1243 {
1244 OSReleaseParse(ctx, "/etc/os-release");
1245 }
1246 else if (access("/usr/lib/os-release", R_OK) != -1)
1247 {
1248 OSReleaseParse(ctx, "/usr/lib/os-release");
1249 }
1250
1251 /* Mandrake/Mandriva, Fedora and Oracle VM Server supply /etc/redhat-release, so
1252 we test for those distributions first */
1253
1254 if (stat("/etc/mandriva-release", &statbuf) != -1)
1255 {
1256 Linux_Mandriva_Version(ctx);
1257 }
1258 else if (stat("/etc/mandrake-release", &statbuf) != -1)
1259 {
1260 Linux_Mandrake_Version(ctx);
1261 }
1262 else if (stat("/etc/fedora-release", &statbuf) != -1)
1263 {
1264 Linux_Fedora_Version(ctx);
1265 }
1266 else if (stat("/etc/ovs-release", &statbuf) != -1)
1267 {
1268 Linux_Oracle_VM_Server_Version(ctx);
1269 }
1270 else if (stat("/etc/redhat-release", &statbuf) != -1)
1271 {
1272 Linux_Redhat_Version(ctx);
1273 }
1274
1275 /* Oracle Linux >= 6 supplies separate /etc/oracle-release alongside
1276 /etc/redhat-release, use it to precisely identify version */
1277
1278 if (stat("/etc/oracle-release", &statbuf) != -1)
1279 {
1280 Linux_Oracle_Version(ctx);
1281 }
1282
1283 if (stat("/etc/generic-release", &statbuf) != -1)
1284 {
1285 Log(LOG_LEVEL_VERBOSE, "This appears to be a sun cobalt system.");
1286 SetFlavor(ctx, "SunCobalt");
1287 }
1288
1289 if (stat("/etc/SuSE-release", &statbuf) != -1)
1290 {
1291 Linux_Suse_Version(ctx);
1292 }
1293
1294 if (stat("/etc/system-release", &statbuf) != -1)
1295 {
1296 Linux_Amazon_Version(ctx);
1297 }
1298
1299 # define SLACKWARE_ANCIENT_VERSION_FILENAME "/etc/slackware-release"
1300 # define SLACKWARE_VERSION_FILENAME "/etc/slackware-version"
1301 if (stat(SLACKWARE_VERSION_FILENAME, &statbuf) != -1)
1302 {
1303 Linux_Slackware_Version(ctx, SLACKWARE_VERSION_FILENAME);
1304 }
1305 else if (stat(SLACKWARE_ANCIENT_VERSION_FILENAME, &statbuf) != -1)
1306 {
1307 Linux_Slackware_Version(ctx, SLACKWARE_ANCIENT_VERSION_FILENAME);
1308 }
1309
1310 if (stat(DEBIAN_VERSION_FILENAME, &statbuf) != -1)
1311 {
1312 Linux_Debian_Version(ctx);
1313 }
1314
1315 if (stat(LSB_RELEASE_FILENAME, &statbuf) != -1)
1316 {
1317 Linux_Misc_Version(ctx);
1318 }
1319
1320 if (stat("/usr/bin/aptitude", &statbuf) != -1)
1321 {
1322 Log(LOG_LEVEL_VERBOSE, "This system seems to have the aptitude package system");
1323 EvalContextClassPutHard(ctx, "have_aptitude", "inventory,attribute_name=none,source=agent");
1324 }
1325
1326 if (stat("/etc/UnitedLinux-release", &statbuf) != -1)
1327 {
1328 Log(LOG_LEVEL_VERBOSE, "This appears to be a UnitedLinux system.");
1329 SetFlavor(ctx, "UnitedLinux");
1330 }
1331
1332 if (stat("/etc/alpine-release", &statbuf) != -1)
1333 {
1334 Linux_Alpine_Version(ctx);
1335 }
1336
1337 if (stat("/etc/gentoo-release", &statbuf) != -1)
1338 {
1339 Log(LOG_LEVEL_VERBOSE, "This appears to be a gentoo system.");
1340 SetFlavor(ctx, "gentoo");
1341 }
1342
1343 if (stat("/etc/arch-release", &statbuf) != -1)
1344 {
1345 Log(LOG_LEVEL_VERBOSE, "This appears to be an Arch Linux system.");
1346 SetFlavor(ctx, "archlinux");
1347 }
1348
1349 if (stat("/proc/vmware/version", &statbuf) != -1 || stat("/etc/vmware-release", &statbuf) != -1)
1350 {
1351 VM_Version(ctx);
1352 }
1353 else if (stat("/etc/vmware", &statbuf) != -1 && S_ISDIR(statbuf.st_mode))
1354 {
1355 VM_Version(ctx);
1356 }
1357
1358 if (stat("/proc/xen/capabilities", &statbuf) != -1)
1359 {
1360 Xen_Domain(ctx);
1361 }
1362 if (stat("/etc/Eos-release", &statbuf) != -1)
1363 {
1364 EOS_Version(ctx);
1365 SetFlavor(ctx, "Eos");
1366 }
1367
1368 if (stat("/etc/issue", &statbuf) != -1)
1369 {
1370 MiscOS(ctx);
1371 }
1372
1373 if (stat("/proc/self/status", &statbuf) != -1)
1374 {
1375 OpenVZ_Detect(ctx);
1376 }
1377
1378 #else
1379
1380 char vbuff[CF_MAXVARSIZE];
1381
1382 #ifdef _AIX
1383 strlcpy(vbuff, VSYSNAME.version, CF_MAXVARSIZE);
1384 #else
1385 strlcpy(vbuff, VSYSNAME.release, CF_MAXVARSIZE);
1386 #endif
1387
1388
1389 for (char *sp = vbuff; *sp != '\0'; sp++)
1390 {
1391 if (*sp == '-')
1392 {
1393 *sp = '\0';
1394 break;
1395 }
1396 }
1397
1398 char context[CF_BUFSIZE];
1399 snprintf(context, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, vbuff);
1400 SetFlavor(ctx, context);
1401
1402 #ifdef __FreeBSD__
1403 /*
1404 * Define a hard class with just the version major number on FreeBSD
1405 *
1406 * For example, when being run on either FreeBSD 10.0 or 10.1 a class
1407 * called freebsd_10 will be defined
1408 */
1409 for (char *sp = vbuff; *sp != '\0'; sp++)
1410 {
1411 if (*sp == '.')
1412 {
1413 *sp = '\0';
1414 break;
1415 }
1416 }
1417
1418 snprintf(context, CF_BUFSIZE, "%s_%s", VSYSNAME.sysname, vbuff);
1419 EvalContextClassPutHard(ctx, context, "source=agent,derived-from=sys.flavor");
1420 #endif
1421
1422 #endif
1423
1424 #ifdef XEN_CPUID_SUPPORT
1425 if (Xen_Hv_Check())
1426 {
1427 Log(LOG_LEVEL_VERBOSE, "This appears to be a xen hv system.");
1428 EvalContextClassPutHard(ctx, "xen", "inventory,attribute_name=Virtual host,source=agent");
1429 EvalContextClassPutHard(ctx, "xen_domu_hv", "source=agent");
1430 }
1431 #endif /* XEN_CPUID_SUPPORT */
1432
1433 GetCPUInfo(ctx);
1434
1435 #ifdef __CYGWIN__
1436
1437 for (char *sp = VSYSNAME.sysname; *sp != '\0'; sp++)
1438 {
1439 if (*sp == '-')
1440 {
1441 sp++;
1442 if (strncmp(sp, "5.0", 3) == 0)
1443 {
1444 Log(LOG_LEVEL_VERBOSE, "This appears to be Windows 2000");
1445 EvalContextClassPutHard(ctx, "Win2000", "inventory,attribute_name=none,source=agent");
1446 }
1447
1448 if (strncmp(sp, "5.1", 3) == 0)
1449 {
1450 Log(LOG_LEVEL_VERBOSE, "This appears to be Windows XP");
1451 EvalContextClassPutHard(ctx, "WinXP", "inventory,attribute_name=none,source=agent");
1452 }
1453
1454 if (strncmp(sp, "5.2", 3) == 0)
1455 {
1456 Log(LOG_LEVEL_VERBOSE, "This appears to be Windows Server 2003");
1457 EvalContextClassPutHard(ctx, "WinServer2003", "inventory,attribute_name=none,source=agent");
1458 }
1459
1460 if (strncmp(sp, "6.1", 3) == 0)
1461 {
1462 Log(LOG_LEVEL_VERBOSE, "This appears to be Windows Vista");
1463 EvalContextClassPutHard(ctx, "WinVista", "inventory,attribute_name=none,source=agent");
1464 }
1465
1466 if (strncmp(sp, "6.3", 3) == 0)
1467 {
1468 Log(LOG_LEVEL_VERBOSE, "This appears to be Windows Server 2008");
1469 EvalContextClassPutHard(ctx, "WinServer2008", "inventory,attribute_name=none,source=agent");
1470 }
1471 }
1472 }
1473
1474 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "crontab", "", CF_DATA_TYPE_STRING, "source=agent");
1475
1476 #endif /* __CYGWIN__ */
1477
1478 #ifdef __MINGW32__
1479 EvalContextClassPutHard(ctx, VSYSNAME.release, "inventory,attribute_name=none,source=agent,derived-from=sys.release"); // code name - e.g. Windows Vista
1480 EvalContextClassPutHard(ctx, VSYSNAME.version, "inventory,attribute_name=none,source=agent,derived-from=sys.version"); // service pack number - e.g. Service Pack 3
1481
1482 if (strstr(VSYSNAME.sysname, "workstation"))
1483 {
1484 EvalContextClassPutHard(ctx, "WinWorkstation", "inventory,attribute_name=Windows roles,source=agent,derived-from=sys.sysname");
1485 }
1486 else if (strstr(VSYSNAME.sysname, "server"))
1487 {
1488 EvalContextClassPutHard(ctx, "WinServer", "inventory,attribute_name=Windows roles,source=agent,derived-from=sys.sysname");
1489 }
1490 else if (strstr(VSYSNAME.sysname, "domain controller"))
1491 {
1492 EvalContextClassPutHard(ctx, "DomainController", "inventory,attribute_name=Windows roles,source=agent,derived-from=sys.sysname");
1493 EvalContextClassPutHard(ctx, "WinServer", "inventory,attribute_name=Windows roles,source=agent,derived-from=sys.sysname");
1494 }
1495 else
1496 {
1497 EvalContextClassPutHard(ctx, "unknown_ostype", "source=agent,derived-from=sys.sysname");
1498 }
1499
1500 SetFlavor(ctx, "windows");
1501
1502 #endif /* __MINGW32__ */
1503
1504 #ifndef _WIN32
1505 struct passwd *pw;
1506 if ((pw = getpwuid(getuid())) == NULL)
1507 {
1508 Log(LOG_LEVEL_ERR, "Unable to get username for uid '%ju'. (getpwuid: %s)", (uintmax_t)getuid(), GetErrorStr());
1509 }
1510 else
1511 {
1512 char vbuff[CF_BUFSIZE];
1513
1514 if (EvalContextClassGet(ctx, NULL, "SUSE"))
1515 {
1516 snprintf(vbuff, CF_BUFSIZE, "/var/spool/cron/tabs/%s", pw->pw_name);
1517 }
1518 else if (EvalContextClassGet(ctx, NULL, "redhat"))
1519 {
1520 snprintf(vbuff, CF_BUFSIZE, "/var/spool/cron/%s", pw->pw_name);
1521 }
1522 else if (EvalContextClassGet(ctx, NULL, "freebsd"))
1523 {
1524 snprintf(vbuff, CF_BUFSIZE, "/var/cron/tabs/%s", pw->pw_name);
1525 }
1526 else
1527 {
1528 snprintf(vbuff, CF_BUFSIZE, "/var/spool/cron/crontabs/%s", pw->pw_name);
1529 }
1530
1531 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "crontab", vbuff, CF_DATA_TYPE_STRING, "source=agent");
1532 }
1533
1534 #endif
1535
1536 #if defined(__ANDROID__)
1537 SetFlavor(ctx, "android");
1538 #endif
1539
1540 #ifdef __sun
1541 if (StringMatchFull("joyent.*", VSYSNAME.version))
1542 {
1543 EvalContextClassPutHard(ctx, "smartos", "inventory,attribute_name=none,source=agent,derived-from=sys.version");
1544 EvalContextClassPutHard(ctx, "smartmachine", "source=agent,derived-from=sys.version");
1545 }
1546 #endif
1547
1548 /* FIXME: this variable needs redhat/SUSE/debian classes to be defined and
1549 * hence can't be initialized earlier */
1550
1551 if (EvalContextClassGet(ctx, NULL, "redhat"))
1552 {
1553 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "doc_root", "/var/www/html", CF_DATA_TYPE_STRING, "source=agent");
1554 }
1555
1556 if (EvalContextClassGet(ctx, NULL, "SUSE"))
1557 {
1558 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "doc_root", "/srv/www/htdocs", CF_DATA_TYPE_STRING, "source=agent");
1559 }
1560
1561 if (EvalContextClassGet(ctx, NULL, "debian"))
1562 {
1563 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "doc_root", "/var/www", CF_DATA_TYPE_STRING, "source=agent");
1564 }
1565 }
1566
1567 /*********************************************************************************/
1568
1569 #ifdef __linux__
Linux_Oracle_VM_Server_Version(EvalContext * ctx)1570 static void Linux_Oracle_VM_Server_Version(EvalContext *ctx)
1571 {
1572 char relstring[CF_MAXVARSIZE];
1573 char *r;
1574 int major, minor, patch;
1575 int revcomps;
1576
1577 #define ORACLE_VM_SERVER_REL_FILENAME "/etc/ovs-release"
1578 #define ORACLE_VM_SERVER_ID "Oracle VM server"
1579
1580 Log(LOG_LEVEL_VERBOSE, "This appears to be Oracle VM Server");
1581 EvalContextClassPutHard(ctx, "redhat", "inventory,attribute_name=none,source=agent");
1582 EvalContextClassPutHard(ctx, "oraclevmserver", "inventory,attribute_name=Virtual host,source=agent");
1583
1584 if (!ReadLine(ORACLE_VM_SERVER_REL_FILENAME, relstring, sizeof(relstring)))
1585 {
1586 return;
1587 }
1588
1589 if (strncmp(relstring, ORACLE_VM_SERVER_ID, strlen(ORACLE_VM_SERVER_ID)))
1590 {
1591 Log(LOG_LEVEL_VERBOSE, "Could not identify distribution from %s", ORACLE_VM_SERVER_REL_FILENAME);
1592 return;
1593 }
1594
1595 if ((r = strstr(relstring, "release ")) == NULL)
1596 {
1597 Log(LOG_LEVEL_VERBOSE, "Could not find distribution version in %s", ORACLE_VM_SERVER_REL_FILENAME);
1598 return;
1599 }
1600
1601 revcomps = sscanf(r + strlen("release "), "%d.%d.%d", &major, &minor, &patch);
1602
1603 if (revcomps > 0)
1604 {
1605 char buf[CF_BUFSIZE];
1606
1607 snprintf(buf, CF_BUFSIZE, "oraclevmserver_%d", major);
1608 SetFlavor(ctx, buf);
1609 }
1610
1611 if (revcomps > 1)
1612 {
1613 char buf[CF_BUFSIZE];
1614
1615 snprintf(buf, CF_BUFSIZE, "oraclevmserver_%d_%d", major, minor);
1616 EvalContextClassPutHard(ctx, buf, "inventory,attribute_name=none,source=agent");
1617 }
1618
1619 if (revcomps > 2)
1620 {
1621 char buf[CF_BUFSIZE];
1622
1623 snprintf(buf, CF_BUFSIZE, "oraclevmserver_%d_%d_%d", major, minor, patch);
1624 EvalContextClassPutHard(ctx, buf, "inventory,attribute_name=none,source=agent");
1625 }
1626 }
1627
1628 /*********************************************************************************/
1629
Linux_Oracle_Version(EvalContext * ctx)1630 static void Linux_Oracle_Version(EvalContext *ctx)
1631 {
1632 char relstring[CF_MAXVARSIZE];
1633 char *r;
1634 int major, minor;
1635
1636 #define ORACLE_REL_FILENAME "/etc/oracle-release"
1637 #define ORACLE_ID "Oracle Linux Server"
1638
1639 Log(LOG_LEVEL_VERBOSE, "This appears to be Oracle Linux");
1640 EvalContextClassPutHard(ctx, "oracle", "inventory,attribute_name=none,source=agent");
1641
1642 if (!ReadLine(ORACLE_REL_FILENAME, relstring, sizeof(relstring)))
1643 {
1644 return;
1645 }
1646
1647 if (strncmp(relstring, ORACLE_ID, strlen(ORACLE_ID)))
1648 {
1649 Log(LOG_LEVEL_VERBOSE, "Could not identify distribution from %s", ORACLE_REL_FILENAME);
1650 return;
1651 }
1652
1653 if ((r = strstr(relstring, "release ")) == NULL)
1654 {
1655 Log(LOG_LEVEL_VERBOSE, "Could not find distribution version in %s", ORACLE_REL_FILENAME);
1656 return;
1657 }
1658
1659 if (sscanf(r + strlen("release "), "%d.%d", &major, &minor) == 2)
1660 {
1661 char buf[CF_BUFSIZE];
1662
1663 snprintf(buf, CF_BUFSIZE, "oracle_%d", major);
1664 SetFlavor(ctx, buf);
1665
1666 snprintf(buf, CF_BUFSIZE, "oracle_%d_%d", major, minor);
1667 EvalContextClassPutHard(ctx, buf, "inventory,attribute_name=none,source=agent");
1668 }
1669 }
1670
1671 /*********************************************************************************/
1672
Linux_Fedora_Version(EvalContext * ctx)1673 static int Linux_Fedora_Version(EvalContext *ctx)
1674 {
1675 #define FEDORA_ID "Fedora"
1676 #define RELEASE_FLAG "release "
1677
1678 /* We are looking for one of the following strings...
1679 *
1680 * Fedora Core release 1 (Yarrow)
1681 * Fedora release 7 (Zodfoobar)
1682 */
1683
1684 #define FEDORA_REL_FILENAME "/etc/fedora-release"
1685
1686 /* The full string read in from fedora-release */
1687 char relstring[CF_MAXVARSIZE];
1688
1689 Log(LOG_LEVEL_VERBOSE, "This appears to be a fedora system.");
1690 EvalContextClassPutHard(ctx, "redhat", "inventory,attribute_name=none,source=agent");
1691 EvalContextClassPutHard(ctx, "fedora", "inventory,attribute_name=none,source=agent");
1692
1693 /* Grab the first line from the file and then close it. */
1694
1695 if (!ReadLine(FEDORA_REL_FILENAME, relstring, sizeof(relstring)))
1696 {
1697 return 1;
1698 }
1699
1700 Log(LOG_LEVEL_VERBOSE, "Looking for fedora core linux info...");
1701
1702 char *vendor = "";
1703 if (!strncmp(relstring, FEDORA_ID, strlen(FEDORA_ID)))
1704 {
1705 vendor = "fedora";
1706 }
1707 else
1708 {
1709 Log(LOG_LEVEL_VERBOSE, "Could not identify OS distro from %s", FEDORA_REL_FILENAME);
1710 return 2;
1711 }
1712
1713 /* Now, grok the release. We assume that all the strings will
1714 * have the word 'release' before the numerical release.
1715 */
1716 int major = -1;
1717 char strmajor[PRINTSIZE(major)];
1718 char *release = strstr(relstring, RELEASE_FLAG);
1719
1720 if (release == NULL)
1721 {
1722 Log(LOG_LEVEL_VERBOSE, "Could not find a numeric OS release in %s", FEDORA_REL_FILENAME);
1723 return 2;
1724 }
1725 else
1726 {
1727 release += strlen(RELEASE_FLAG);
1728
1729 strmajor[0] = '\0';
1730 if (sscanf(release, "%d", &major) != 0)
1731 {
1732 xsnprintf(strmajor, sizeof(strmajor), "%d", major);
1733 }
1734 }
1735
1736 if (major != -1 && vendor[0] != '\0')
1737 {
1738 char classbuf[CF_MAXVARSIZE];
1739 classbuf[0] = '\0';
1740 strcat(classbuf, vendor);
1741 EvalContextClassPutHard(ctx,classbuf, "inventory,attribute_name=none,source=agent");
1742 strcat(classbuf, "_");
1743 strcat(classbuf, strmajor);
1744 SetFlavor(ctx, classbuf);
1745 }
1746
1747 return 0;
1748 }
1749
1750 /*********************************************************************************/
1751
Linux_Redhat_Version(EvalContext * ctx)1752 static int Linux_Redhat_Version(EvalContext *ctx)
1753 {
1754 #define REDHAT_ID "Red Hat Linux"
1755 #define REDHAT_ENT_ID "Red Hat Enterprise Linux"
1756 #define REDHAT_AS_ID "Red Hat Enterprise Linux AS"
1757 #define REDHAT_AS21_ID "Red Hat Linux Advanced Server"
1758 #define REDHAT_ES_ID "Red Hat Enterprise Linux ES"
1759 #define REDHAT_WS_ID "Red Hat Enterprise Linux WS"
1760 #define REDHAT_C_ID "Red Hat Enterprise Linux Client"
1761 #define REDHAT_S_ID "Red Hat Enterprise Linux Server"
1762 #define REDHAT_W_ID "Red Hat Enterprise Linux Workstation"
1763 #define REDHAT_CN_ID "Red Hat Enterprise Linux ComputeNode"
1764 #define MANDRAKE_ID "Linux Mandrake"
1765 #define MANDRAKE_10_1_ID "Mandrakelinux"
1766 #define WHITEBOX_ID "White Box Enterprise Linux"
1767 #define CENTOS_ID "CentOS"
1768 #define SCIENTIFIC_SL_ID "Scientific Linux SL"
1769 #define SCIENTIFIC_SL6_ID "Scientific Linux"
1770 #define SCIENTIFIC_CERN_ID "Scientific Linux CERN"
1771 #define RELEASE_FLAG "release "
1772 #define ORACLE_4_5_ID "Enterprise Linux Enterprise Linux Server"
1773
1774 /* We are looking for one of the following strings...
1775 *
1776 * Red Hat Linux release 6.2 (Zoot)
1777 * Red Hat Enterprise Linux release 8.0 (Ootpa)
1778 * Red Hat Linux Advanced Server release 2.1AS (Pensacola)
1779 * Red Hat Enterprise Linux AS release 3 (Taroon)
1780 * Red Hat Enterprise Linux WS release 3 (Taroon)
1781 * Red Hat Enterprise Linux Client release 5 (Tikanga)
1782 * Red Hat Enterprise Linux Server release 5 (Tikanga)
1783 * Linux Mandrake release 7.1 (helium)
1784 * Red Hat Enterprise Linux ES release 2.1 (Panama)
1785 * White Box Enterprise linux release 3.0 (Liberation)
1786 * Scientific Linux SL Release 4.0 (Beryllium)
1787 * CentOS release 4.0 (Final)
1788 */
1789
1790 #define RH_REL_FILENAME "/etc/redhat-release"
1791
1792 Log(LOG_LEVEL_VERBOSE, "This appears to be a redhat (or redhat-based) system.");
1793 EvalContextClassPutHard(ctx, "redhat", "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1794
1795 /* Grab the first line from the file and then close it. */
1796 char relstring[CF_MAXVARSIZE];
1797 if (!ReadLine(RH_REL_FILENAME, relstring, sizeof(relstring)))
1798 {
1799 return 1;
1800 }
1801
1802 Log(LOG_LEVEL_VERBOSE, "Looking for redhat linux info in '%s'", relstring);
1803
1804 /* First, try to grok the vendor and edition (if any) */
1805 char *edition = ""; /* as (Advanced Server, Enterprise) */
1806 char *vendor = ""; /* Red Hat, Mandrake */
1807 if (!strncmp(relstring, REDHAT_ES_ID, strlen(REDHAT_ES_ID)))
1808 {
1809 vendor = "redhat";
1810 edition = "es";
1811 }
1812 else if (!strncmp(relstring, REDHAT_WS_ID, strlen(REDHAT_WS_ID)))
1813 {
1814 vendor = "redhat";
1815 edition = "ws";
1816 }
1817 else if (!strncmp(relstring, REDHAT_WS_ID, strlen(REDHAT_WS_ID)))
1818 {
1819 vendor = "redhat";
1820 edition = "ws";
1821 }
1822 else if (!strncmp(relstring, REDHAT_AS_ID, strlen(REDHAT_AS_ID)) ||
1823 !strncmp(relstring, REDHAT_AS21_ID, strlen(REDHAT_AS21_ID)))
1824 {
1825 vendor = "redhat";
1826 edition = "as";
1827 }
1828 else if (!strncmp(relstring, REDHAT_S_ID, strlen(REDHAT_S_ID)))
1829 {
1830 vendor = "redhat";
1831 edition = "s";
1832 }
1833 else if (!strncmp(relstring, REDHAT_C_ID, strlen(REDHAT_C_ID))
1834 || !strncmp(relstring, REDHAT_W_ID, strlen(REDHAT_W_ID)))
1835 {
1836 vendor = "redhat";
1837 edition = "c";
1838 }
1839 else if (!strncmp(relstring, REDHAT_CN_ID, strlen(REDHAT_CN_ID)))
1840 {
1841 vendor = "redhat";
1842 edition = "cn";
1843 }
1844 else if (!strncmp(relstring, REDHAT_ID, strlen(REDHAT_ID)))
1845 {
1846 vendor = "redhat";
1847 }
1848 else if (!strncmp(relstring, REDHAT_ENT_ID, strlen(REDHAT_ENT_ID)))
1849 {
1850 vendor = "redhat";
1851 }
1852 else if (!strncmp(relstring, MANDRAKE_ID, strlen(MANDRAKE_ID)))
1853 {
1854 vendor = "mandrake";
1855 }
1856 else if (!strncmp(relstring, MANDRAKE_10_1_ID, strlen(MANDRAKE_10_1_ID)))
1857 {
1858 vendor = "mandrake";
1859 }
1860 else if (!strncmp(relstring, WHITEBOX_ID, strlen(WHITEBOX_ID)))
1861 {
1862 vendor = "whitebox";
1863 }
1864 else if (!strncmp(relstring, SCIENTIFIC_SL_ID, strlen(SCIENTIFIC_SL_ID)))
1865 {
1866 vendor = "scientific";
1867 edition = "sl";
1868 }
1869 else if (!strncmp(relstring, SCIENTIFIC_CERN_ID, strlen(SCIENTIFIC_CERN_ID)))
1870 {
1871 vendor = "scientific";
1872 edition = "cern";
1873 }
1874 else if (!strncmp(relstring, SCIENTIFIC_SL6_ID, strlen(SCIENTIFIC_SL6_ID)))
1875 {
1876 vendor = "scientific";
1877 edition = "sl";
1878 }
1879 else if (!strncmp(relstring, CENTOS_ID, strlen(CENTOS_ID)))
1880 {
1881 vendor = "centos";
1882 }
1883 else if (!strncmp(relstring, ORACLE_4_5_ID, strlen(ORACLE_4_5_ID)))
1884 {
1885 vendor = "oracle";
1886 edition = "s";
1887 }
1888 else
1889 {
1890 Log(LOG_LEVEL_VERBOSE, "Could not identify OS distro from %s", RH_REL_FILENAME);
1891 return 2;
1892 }
1893
1894 /* Now, grok the release. For AS, we neglect the AS at the end of the
1895 * numerical release because we already figured out that it *is* AS
1896 * from the information above. We assume that all the strings will
1897 * have the word 'release' before the numerical release.
1898 */
1899
1900 /* Convert relstring to lowercase so that vendors like
1901 Scientific Linux don't fall through the cracks.
1902 */
1903
1904 for (int i = 0; i < strlen(relstring); i++)
1905 {
1906 relstring[i] = tolower(relstring[i]);
1907 }
1908
1909 /* Where the numerical release will be found */
1910 int major = -1, minor = -1;
1911 char strmajor[PRINTSIZE(major)], strminor[PRINTSIZE(minor)];
1912
1913 char *release = strstr(relstring, RELEASE_FLAG);
1914 if (release == NULL)
1915 {
1916 Log(LOG_LEVEL_VERBOSE, "Could not find a numeric OS release in %s", RH_REL_FILENAME);
1917 return 2;
1918 }
1919 else
1920 {
1921 release += strlen(RELEASE_FLAG);
1922 if (sscanf(release, "%d.%d", &major, &minor) == 2)
1923 {
1924 xsnprintf(strmajor, sizeof(strmajor), "%d", major);
1925 xsnprintf(strminor, sizeof(strminor), "%d", minor);
1926 }
1927 /* red hat 9 is *not* red hat 9.0.
1928 * and same thing with RHEL AS 3
1929 */
1930 else if (sscanf(release, "%d", &major) == 1)
1931 {
1932 xsnprintf(strmajor, sizeof(strmajor), "%d", major);
1933 minor = -2;
1934 }
1935 }
1936
1937 char classbuf[CF_MAXVARSIZE];
1938 if (major != -1 && minor != -1 && (strcmp(vendor, "") != 0))
1939 {
1940 classbuf[0] = '\0';
1941 strcat(classbuf, vendor);
1942 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1943 strcat(classbuf, "_");
1944
1945 if (strcmp(edition, "") != 0)
1946 {
1947 strcat(classbuf, edition);
1948 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1949 strcat(classbuf, "_");
1950 }
1951
1952 strcat(classbuf, strmajor);
1953 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1954
1955 if (minor != -2)
1956 {
1957 strcat(classbuf, "_");
1958 strcat(classbuf, strminor);
1959 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1960 }
1961 }
1962
1963 // Now a version without the edition
1964 if (major != -1 && minor != -1 && vendor[0] != '\0')
1965 {
1966 classbuf[0] = '\0';
1967 strcat(classbuf, vendor);
1968 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1969 strcat(classbuf, "_");
1970
1971 strcat(classbuf, strmajor);
1972
1973 SetFlavor(ctx, classbuf);
1974
1975 if (minor != -2)
1976 {
1977 strcat(classbuf, "_");
1978 strcat(classbuf, strminor);
1979 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent,derived-from-file="RH_REL_FILENAME);
1980 }
1981 }
1982
1983 return 0;
1984 }
1985
1986 /******************************************************************/
1987
Linux_Suse_Version(EvalContext * ctx)1988 static int Linux_Suse_Version(EvalContext *ctx)
1989 {
1990 #define SUSE_REL_FILENAME "/etc/SuSE-release"
1991 /* Check if it's a SUSE Enterprise version (all in lowercase) */
1992 #define SUSE_SLES8_ID "suse sles-8"
1993 #define SUSE_SLES_ID "suse linux enterprise server"
1994 #define SUSE_SLED_ID "suse linux enterprise desktop"
1995 #define SUSE_RELEASE_FLAG "linux "
1996
1997 char classbuf[CF_MAXVARSIZE];
1998
1999 Log(LOG_LEVEL_VERBOSE, "This appears to be a SUSE system.");
2000 EvalContextClassPutHard(ctx, "SUSE", "inventory,attribute_name=none,source=agent");
2001 EvalContextClassPutHard(ctx, "suse", "inventory,attribute_name=none,source=agent");
2002
2003 /* The correct spelling for SUSE is "SUSE" but CFEngine used to use "SuSE".
2004 * Keep this for backwards compatibility until CFEngine 3.7
2005 */
2006 EvalContextClassPutHard(ctx, "SuSE", "inventory,attribute_name=none,source=agent");
2007
2008 /* Grab the first line from the SuSE-release file and then close it. */
2009 char relstring[CF_MAXVARSIZE];
2010
2011 FILE *fp = ReadFirstLine(SUSE_REL_FILENAME, relstring, sizeof(relstring));
2012 if (fp == NULL)
2013 {
2014 return 1;
2015 }
2016
2017 char vbuf[CF_BUFSIZE], strversion[CF_MAXVARSIZE], strpatch[CF_MAXVARSIZE];
2018 strversion[0] = '\0';
2019 strpatch[0] = '\0';
2020
2021 int major = -1, minor = -1;
2022 while (fgets(vbuf, sizeof(vbuf), fp) != NULL)
2023 {
2024 if (strncmp(vbuf, "VERSION", strlen("version")) == 0)
2025 {
2026 strlcpy(strversion, vbuf, sizeof(strversion));
2027 sscanf(vbuf, "VERSION = %d", &major);
2028 }
2029
2030 if (strncmp(vbuf, "PATCH", strlen("PATCH")) == 0)
2031 {
2032 strlcpy(strpatch, vbuf, sizeof(strpatch));
2033 sscanf(vbuf, "PATCHLEVEL = %d", &minor);
2034 }
2035 }
2036 if (ferror(fp))
2037 {
2038 UnexpectedError("Failed to read line from stream");
2039 }
2040 else
2041 {
2042 assert(feof(fp));
2043 }
2044
2045 fclose(fp);
2046
2047 /* Check if it's a SUSE Enterprise version */
2048
2049 Log(LOG_LEVEL_VERBOSE, "Looking for SUSE enterprise info in '%s'", relstring);
2050
2051 /* Convert relstring to lowercase to handle rename of SuSE to
2052 * SUSE with SUSE 10.0.
2053 */
2054
2055 for (int i = 0; i < strlen(relstring); i++)
2056 {
2057 relstring[i] = tolower(relstring[i]);
2058 }
2059
2060 /* Check if it's a SUSE Enterprise version (all in lowercase) */
2061
2062 if (!strncmp(relstring, SUSE_SLES8_ID, strlen(SUSE_SLES8_ID)))
2063 {
2064 classbuf[0] = '\0';
2065 strcat(classbuf, "SLES8");
2066 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2067 }
2068 else if (strncmp(relstring, "sles", 4) == 0)
2069 {
2070 Item *list, *ip;
2071
2072 assert((sizeof(vbuf)) > 255); // TODO: static_assert()
2073 sscanf(relstring, "%255[-_a-zA-Z0-9]", vbuf);
2074 EvalContextClassPutHard(ctx, vbuf, "inventory,attribute_name=none,source=agent");
2075
2076 list = SplitString(vbuf, '-');
2077
2078 for (ip = list; ip != NULL; ip = ip->next)
2079 {
2080 EvalContextClassPutHard(ctx, ip->name, "inventory,attribute_name=none,source=agent");
2081 }
2082
2083 DeleteItemList(list);
2084 }
2085 else
2086 {
2087 for (int version = 9; version < 13; version++)
2088 {
2089 snprintf(vbuf, CF_BUFSIZE, "%s %d ", SUSE_SLES_ID, version);
2090 Log(LOG_LEVEL_DEBUG, "Checking for SUSE [%s]", vbuf);
2091
2092 if (!strncmp(relstring, vbuf, strlen(vbuf)))
2093 {
2094 snprintf(classbuf, CF_MAXVARSIZE, "SLES%d", version);
2095 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2096 }
2097 else
2098 {
2099 snprintf(vbuf, CF_BUFSIZE, "%s %d ", SUSE_SLED_ID, version);
2100 Log(LOG_LEVEL_DEBUG, "Checking for SUSE [%s]", vbuf);
2101
2102 if (!strncmp(relstring, vbuf, strlen(vbuf)))
2103 {
2104 snprintf(classbuf, CF_MAXVARSIZE, "SLED%d", version);
2105 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2106 }
2107 }
2108 }
2109 }
2110
2111 /* Determine release version. We assume that the version follows
2112 * the string "SuSE Linux" or "SUSE LINUX".
2113 */
2114
2115 char *release = strstr(relstring, SUSE_RELEASE_FLAG);
2116 if (release == NULL)
2117 {
2118 release = strstr(relstring, "opensuse");
2119 if (release == NULL)
2120 {
2121 release = strversion;
2122 }
2123 }
2124
2125 if (release == NULL)
2126 {
2127 Log(LOG_LEVEL_VERBOSE,
2128 "Could not find a numeric OS release in %s",
2129 SUSE_REL_FILENAME);
2130 return 2;
2131 }
2132 else
2133 {
2134 char strmajor[CF_MAXVARSIZE], strminor[CF_MAXVARSIZE];
2135 if (strchr(release, '.'))
2136 {
2137 sscanf(release, "%*s %d.%d", &major, &minor);
2138 xsnprintf(strmajor, sizeof(strmajor), "%d", major);
2139 xsnprintf(strminor, sizeof(strminor), "%d", minor);
2140
2141 if (major != -1 && minor != -1)
2142 {
2143 strcpy(classbuf, "SUSE");
2144 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2145 strcat(classbuf, "_");
2146 strcat(classbuf, strmajor);
2147 SetFlavor(ctx, classbuf);
2148 strcat(classbuf, "_");
2149 strcat(classbuf, strminor);
2150 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2151
2152 /* The correct spelling for SUSE is "SUSE" but CFEngine used to use "SuSE".
2153 * Keep this for backwards compatibility until CFEngine 3.7
2154 */
2155 strcpy(classbuf, "SuSE");
2156 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2157 strcat(classbuf, "_");
2158 strcat(classbuf, strmajor);
2159 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2160 strcat(classbuf, "_");
2161 strcat(classbuf, strminor);
2162 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2163
2164 Log(LOG_LEVEL_VERBOSE, "Discovered SUSE version %s", classbuf);
2165 return 0;
2166 }
2167 }
2168 else
2169 {
2170 assert((sizeof(strmajor)) > 255); // TODO: static_assert()
2171 assert((sizeof(strminor)) > 255); // TODO: static_assert()
2172 sscanf(strversion, "VERSION = %255s", strmajor);
2173 sscanf(strpatch, "PATCHLEVEL = %255s", strminor);
2174
2175 if (major != -1 && minor != -1)
2176 {
2177 strcpy(classbuf, "SLES");
2178 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2179 strcat(classbuf, "_");
2180 strcat(classbuf, strmajor);
2181 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2182 strcat(classbuf, "_");
2183 strcat(classbuf, strminor);
2184 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2185
2186 snprintf(classbuf, CF_MAXVARSIZE, "SUSE_%d", major);
2187 SetFlavor(ctx, classbuf);
2188
2189 /* The correct spelling for SUSE is "SUSE" but CFEngine used to use "SuSE".
2190 * Keep this for backwards compatibility until CFEngine 3.7
2191 */
2192 snprintf(classbuf, CF_MAXVARSIZE, "SuSE_%d", major);
2193 EvalContextClassPutHard(ctx, classbuf, "source=agent");
2194
2195 Log(LOG_LEVEL_VERBOSE, "Discovered SUSE version %s", classbuf);
2196 return 0;
2197 }
2198 }
2199 }
2200
2201 Log(LOG_LEVEL_VERBOSE, "Could not find a numeric OS release in %s", SUSE_REL_FILENAME);
2202
2203 return 0;
2204 }
2205
2206 /******************************************************************/
2207
Linux_Slackware_Version(EvalContext * ctx,char * filename)2208 static int Linux_Slackware_Version(EvalContext *ctx, char *filename)
2209 {
2210 int major = -1;
2211 int minor = -1;
2212 int release = -1;
2213 char classname[CF_MAXVARSIZE] = "";
2214 char buffer[CF_MAXVARSIZE];
2215
2216 Log(LOG_LEVEL_VERBOSE, "This appears to be a slackware system.");
2217 EvalContextClassPutHard(ctx, "slackware", "inventory,attribute_name=none,source=agent");
2218
2219 if (!ReadLine(filename, buffer, sizeof(buffer)))
2220 {
2221 return 1;
2222 }
2223
2224 Log(LOG_LEVEL_VERBOSE, "Looking for Slackware version...");
2225 switch (sscanf(buffer, "Slackware %d.%d.%d", &major, &minor, &release))
2226 {
2227 case 3:
2228 Log(LOG_LEVEL_VERBOSE, "This appears to be a Slackware %u.%u.%u system.", major, minor, release);
2229 snprintf(classname, CF_MAXVARSIZE, "slackware_%u_%u_%u", major, minor, release);
2230 EvalContextClassPutHard(ctx, classname, "inventory,attribute_name=none,source=agent");
2231 /* Fall-through */
2232 case 2:
2233 Log(LOG_LEVEL_VERBOSE, "This appears to be a Slackware %u.%u system.", major, minor);
2234 snprintf(classname, CF_MAXVARSIZE, "slackware_%u_%u", major, minor);
2235 EvalContextClassPutHard(ctx, classname, "inventory,attribute_name=none,source=agent");
2236 /* Fall-through */
2237 case 1:
2238 Log(LOG_LEVEL_VERBOSE, "This appears to be a Slackware %u system.", major);
2239 snprintf(classname, CF_MAXVARSIZE, "slackware_%u", major);
2240 EvalContextClassPutHard(ctx, classname, "inventory,attribute_name=none,source=agent");
2241 break;
2242 case 0:
2243 Log(LOG_LEVEL_VERBOSE, "No Slackware version number found.");
2244 return 2;
2245 }
2246 return 0;
2247 }
2248
2249 /*
2250 * @brief Purge /etc/issue escapes on debian
2251 *
2252 * On debian, /etc/issue can include special characters escaped with
2253 * '\\' or '@'. This function removes such escape sequences.
2254 *
2255 * @param[in,out] buffer: string to be sanitized
2256 */
LinuxDebianSanitizeIssue(char * buffer)2257 static void LinuxDebianSanitizeIssue(char *buffer)
2258 {
2259 bool escaped = false;
2260 char *dst = buffer, *src = buffer, *tail = dst;
2261 while (*src != '\0')
2262 {
2263 char here = *src;
2264 src++;
2265 if (here == '\\' || here == '@' || escaped)
2266 {
2267 /* Skip over escapes and the character each acts on. */
2268 escaped = !escaped;
2269 }
2270 else
2271 {
2272 /* Copy everything else verbatim: */
2273 *dst = here;
2274 dst++;
2275 /* Keep track of (just after) last non-space: */
2276 if (!isspace(here))
2277 {
2278 tail = dst;
2279 }
2280 }
2281 }
2282
2283 assert(tail == dst || isspace(*tail));
2284 *tail = '\0';
2285 }
2286
2287 /******************************************************************/
2288
Linux_Misc_Version(EvalContext * ctx)2289 static int Linux_Misc_Version(EvalContext *ctx)
2290 {
2291 char flavor[CF_MAXVARSIZE];
2292 char version[CF_MAXVARSIZE];
2293 char os[CF_MAXVARSIZE];
2294 char buffer[CF_BUFSIZE];
2295
2296 *os = '\0';
2297 *version = '\0';
2298
2299 FILE *fp = safe_fopen(LSB_RELEASE_FILENAME, "r");
2300 if (fp != NULL)
2301 {
2302 while (!feof(fp))
2303 {
2304 if (fgets(buffer, CF_BUFSIZE, fp) == NULL)
2305 {
2306 if (ferror(fp))
2307 {
2308 break;
2309 }
2310 continue;
2311 }
2312
2313 if (strstr(buffer, "Cumulus"))
2314 {
2315 EvalContextClassPutHard(ctx, "cumulus", "inventory,attribute_name=none,source=agent");
2316 strcpy(os, "cumulus");
2317 }
2318
2319 char *sp = strstr(buffer, "DISTRIB_RELEASE=");
2320 if (sp)
2321 {
2322 version[0] = '\0';
2323 assert((sizeof(version)) > 255); // TODO: static_assert()
2324 sscanf(sp + strlen("DISTRIB_RELEASE="), "%255[^\n]", version);
2325 CanonifyNameInPlace(version);
2326 }
2327 }
2328 fclose(fp);
2329 }
2330
2331 if (*os && *version)
2332 {
2333 snprintf(flavor, CF_MAXVARSIZE, "%s_%s", os, version);
2334 SetFlavor(ctx, flavor);
2335 return 1;
2336 }
2337
2338 return 0;
2339 }
2340
2341 /******************************************************************/
2342
Linux_Debian_Version(EvalContext * ctx)2343 static int Linux_Debian_Version(EvalContext *ctx)
2344 {
2345 int major = -1;
2346 int release = -1;
2347 int result;
2348 char classname[CF_MAXVARSIZE], buffer[CF_MAXVARSIZE], os[CF_MAXVARSIZE], version[CF_MAXVARSIZE];
2349
2350 Log(LOG_LEVEL_VERBOSE, "This appears to be a debian system.");
2351 EvalContextClassPutHard(
2352 ctx,
2353 "debian",
2354 "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_VERSION_FILENAME);
2355
2356 buffer[0] = classname[0] = '\0';
2357
2358 Log(LOG_LEVEL_VERBOSE, "Looking for Debian version...");
2359
2360 if (!ReadLine(DEBIAN_VERSION_FILENAME, buffer, sizeof(buffer)))
2361 {
2362 return 1;
2363 }
2364
2365 result = sscanf(buffer, "%d.%d", &major, &release);
2366
2367 switch (result)
2368 {
2369 case 2:
2370 Log(LOG_LEVEL_VERBOSE, "This appears to be a Debian %u.%u system.", major, release);
2371 snprintf(classname, CF_MAXVARSIZE, "debian_%u_%u", major, release);
2372 EvalContextClassPutHard(
2373 ctx,
2374 classname,
2375 "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_VERSION_FILENAME);
2376 snprintf(classname, CF_MAXVARSIZE, "debian_%u", major);
2377 SetFlavor(ctx, classname);
2378 break;
2379
2380 case 1:
2381 Log(LOG_LEVEL_VERBOSE, "This appears to be a Debian %u system.", major);
2382 snprintf(classname, CF_MAXVARSIZE, "debian_%u", major);
2383 SetFlavor(ctx, classname);
2384 break;
2385
2386 default:
2387 version[0] = '\0';
2388 assert((sizeof(version)) > 25); // TODO: static_assert()
2389 sscanf(buffer, "%25[^/]", version);
2390 if (strlen(version) > 0)
2391 {
2392 snprintf(classname, CF_MAXVARSIZE, "debian_%s", version);
2393 EvalContextClassPutHard(
2394 ctx,
2395 classname,
2396 "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_VERSION_FILENAME);
2397 }
2398 break;
2399 }
2400
2401 if (!ReadLine(DEBIAN_ISSUE_FILENAME, buffer, sizeof(buffer)))
2402 {
2403 return 1;
2404 }
2405
2406 os[0] = '\0';
2407 assert((sizeof(os)) > 250); // TODO: static_assert()
2408 sscanf(buffer, "%250s", os);
2409
2410 if (strcmp(os, "Debian") == 0)
2411 {
2412 LinuxDebianSanitizeIssue(buffer);
2413 assert((sizeof(version)) > 255); // TODO: static_assert()
2414 sscanf(buffer, "%*s %*s %255[^./]", version);
2415 snprintf(buffer, CF_MAXVARSIZE, "debian_%s", version);
2416 EvalContextClassPutHard(
2417 ctx,
2418 "debian",
2419 "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_ISSUE_FILENAME);
2420 SetFlavor(ctx, buffer);
2421 }
2422 else if (strcmp(os, "Ubuntu") == 0)
2423 {
2424 LinuxDebianSanitizeIssue(buffer);
2425 char minor[CF_MAXVARSIZE] = {0};
2426 assert((sizeof(version)) > 255); // TODO: static_assert()
2427 assert((sizeof(minor)) > 255); // TODO: static_assert()
2428 sscanf(buffer, "%*s %255[^.].%255s", version, minor);
2429 snprintf(buffer, CF_MAXVARSIZE, "ubuntu_%s", version);
2430 SetFlavor(ctx, buffer);
2431 EvalContextClassPutHard(
2432 ctx,
2433 "ubuntu",
2434 "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_ISSUE_FILENAME);
2435 if (release >= 0)
2436 {
2437 snprintf(buffer, CF_MAXVARSIZE, "ubuntu_%s_%s", version, minor);
2438 EvalContextClassPutHard(
2439 ctx,
2440 buffer,
2441 "inventory,attribute_name=none,source=agent,derived-from-file="DEBIAN_ISSUE_FILENAME);
2442 }
2443 }
2444
2445 return 0;
2446 }
2447
2448 /******************************************************************/
2449
Linux_Mandrake_Version(EvalContext * ctx)2450 static int Linux_Mandrake_Version(EvalContext *ctx)
2451 {
2452 /* We are looking for one of the following strings... */
2453 #define MANDRAKE_ID "Linux Mandrake"
2454 #define MANDRAKE_REV_ID "Mandrake Linux"
2455 #define MANDRAKE_10_1_ID "Mandrakelinux"
2456
2457 #define MANDRAKE_REL_FILENAME "/etc/mandrake-release"
2458
2459 char relstring[CF_MAXVARSIZE];
2460 char *vendor = NULL;
2461
2462 Log(LOG_LEVEL_VERBOSE, "This appears to be a mandrake system.");
2463 EvalContextClassPutHard(ctx, "Mandrake", "inventory,attribute_name=none,source=agent");
2464
2465 if (!ReadLine(MANDRAKE_REL_FILENAME, relstring, sizeof(relstring)))
2466 {
2467 return 1;
2468 }
2469
2470 Log(LOG_LEVEL_VERBOSE, "Looking for Mandrake linux info in '%s'", relstring);
2471
2472 /* Older Mandrakes had the 'Mandrake Linux' string in reverse order */
2473
2474 if (!strncmp(relstring, MANDRAKE_ID, strlen(MANDRAKE_ID)))
2475 {
2476 vendor = "mandrake";
2477 }
2478 else if (!strncmp(relstring, MANDRAKE_REV_ID, strlen(MANDRAKE_REV_ID)))
2479 {
2480 vendor = "mandrake";
2481 }
2482
2483 else if (!strncmp(relstring, MANDRAKE_10_1_ID, strlen(MANDRAKE_10_1_ID)))
2484 {
2485 vendor = "mandrake";
2486 }
2487 else
2488 {
2489 Log(LOG_LEVEL_VERBOSE, "Could not identify OS distro from %s", MANDRAKE_REL_FILENAME);
2490 return 2;
2491 }
2492
2493 return Linux_Mandriva_Version_Real(ctx, MANDRAKE_REL_FILENAME, relstring, vendor);
2494 }
2495
2496 /******************************************************************/
2497
Linux_Mandriva_Version(EvalContext * ctx)2498 static int Linux_Mandriva_Version(EvalContext *ctx)
2499 {
2500 /* We are looking for the following strings... */
2501 #define MANDRIVA_ID "Mandriva Linux"
2502
2503 #define MANDRIVA_REL_FILENAME "/etc/mandriva-release"
2504
2505 char relstring[CF_MAXVARSIZE];
2506 char *vendor = NULL;
2507
2508 Log(LOG_LEVEL_VERBOSE, "This appears to be a mandriva system.");
2509 EvalContextClassPutHard(ctx, "Mandrake", "inventory,attribute_name=none,source=agent");
2510 EvalContextClassPutHard(ctx, "Mandriva", "inventory,attribute_name=none,source=agent");
2511
2512 if (!ReadLine(MANDRIVA_REL_FILENAME, relstring, sizeof(relstring)))
2513 {
2514 return 1;
2515 }
2516
2517 Log(LOG_LEVEL_VERBOSE, "Looking for Mandriva linux info in '%s'", relstring);
2518
2519 if (!strncmp(relstring, MANDRIVA_ID, strlen(MANDRIVA_ID)))
2520 {
2521 vendor = "mandriva";
2522 }
2523 else
2524 {
2525 Log(LOG_LEVEL_VERBOSE, "Could not identify OS distro from '%s'", MANDRIVA_REL_FILENAME);
2526 return 2;
2527 }
2528
2529 return Linux_Mandriva_Version_Real(ctx, MANDRIVA_REL_FILENAME, relstring, vendor);
2530
2531 }
2532
2533 /******************************************************************/
2534
Linux_Mandriva_Version_Real(EvalContext * ctx,char * filename,char * relstring,char * vendor)2535 static int Linux_Mandriva_Version_Real(EvalContext *ctx, char *filename, char *relstring, char *vendor)
2536 {
2537 int major = -1, minor = -1;
2538 char strmajor[PRINTSIZE(major)], strminor[PRINTSIZE(minor)];
2539
2540 #define RELEASE_FLAG "release "
2541 char *release = strstr(relstring, RELEASE_FLAG);
2542 if (release == NULL)
2543 {
2544 Log(LOG_LEVEL_VERBOSE, "Could not find a numeric OS release in %s", filename);
2545 return 2;
2546 }
2547 else
2548 {
2549 release += strlen(RELEASE_FLAG);
2550 if (sscanf(release, "%d.%d", &major, &minor) == 2)
2551 {
2552 xsnprintf(strmajor, sizeof(strmajor), "%d", major);
2553 xsnprintf(strminor, sizeof(strminor), "%d", minor);
2554 }
2555 else
2556 {
2557 Log(LOG_LEVEL_VERBOSE, "Could not break down release version numbers in %s", filename);
2558 }
2559 }
2560
2561 if (major != -1 && minor != -1 && strcmp(vendor, ""))
2562 {
2563 char classbuf[CF_MAXVARSIZE];
2564 classbuf[0] = '\0';
2565 strcat(classbuf, vendor);
2566 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2567 strcat(classbuf, "_");
2568 strcat(classbuf, strmajor);
2569 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2570 if (minor != -2)
2571 {
2572 strcat(classbuf, "_");
2573 strcat(classbuf, strminor);
2574 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2575 }
2576 }
2577
2578 return 0;
2579 }
2580
2581 /******************************************************************/
2582
Linux_Amazon_Version(EvalContext * ctx)2583 static void Linux_Amazon_Version(EvalContext *ctx)
2584 {
2585 char buffer[CF_BUFSIZE];
2586
2587 // Amazon Linux AMI release 2016.09
2588
2589 if (ReadLine("/etc/system-release", buffer, sizeof(buffer)))
2590 {
2591 if (strstr(buffer, "Amazon") != NULL)
2592 {
2593 EvalContextClassPutHard(ctx, "amazon_linux",
2594 "inventory,attribute_name=none,source=agent"
2595 ",derived-from-file=/etc/system-release");
2596
2597 char version[128];
2598 if (sscanf(buffer, "%*s %*s %*s %*s %127s", version) == 1)
2599 {
2600 char class[CF_MAXVARSIZE];
2601
2602 CanonifyNameInPlace(version);
2603 snprintf(class, sizeof(class), "amazon_linux_%s", version);
2604 EvalContextClassPutHard(ctx, class,
2605 "inventory,attribute_name=none,source=agent"
2606 ",derived-from-file=/etc/system-release");
2607 }
2608 SetFlavor(ctx, "AmazonLinux");
2609 }
2610 }
2611 }
2612
2613 /******************************************************************/
2614
Linux_Alpine_Version(EvalContext * ctx)2615 static void Linux_Alpine_Version(EvalContext *ctx)
2616 {
2617 char buffer[CF_BUFSIZE];
2618
2619 Log(LOG_LEVEL_VERBOSE, "This appears to be an AlpineLinux system.");
2620
2621 EvalContextClassPutHard(ctx, "alpine_linux",
2622 "inventory,attribute_name=none,source=agent"
2623 ",derived-from-file=/etc/alpine-release");
2624
2625 if (ReadLine("/etc/alpine-release", buffer, sizeof(buffer)))
2626 {
2627 char version[128];
2628 if (sscanf(buffer, "%127s", version) == 1)
2629 {
2630 char class[CF_MAXVARSIZE];
2631 CanonifyNameInPlace(version);
2632 snprintf(class, sizeof(class), "alpine_linux_%s", version);
2633 EvalContextClassPutHard(ctx, class,
2634 "inventory,attribute_name=none,source=agent"
2635 ",derived-from-file=/etc/alpine-release");
2636 }
2637 }
2638 SetFlavor(ctx, "alpinelinux");
2639 }
2640
2641 /******************************************************************/
2642
EOS_Version(EvalContext * ctx)2643 static int EOS_Version(EvalContext *ctx)
2644
2645 {
2646 char buffer[CF_BUFSIZE];
2647
2648 // e.g. Arista Networks EOS 4.10.2
2649
2650 if (ReadLine("/etc/Eos-release", buffer, sizeof(buffer)))
2651 {
2652 if (strstr(buffer, "EOS"))
2653 {
2654 char version[CF_MAXVARSIZE], class[CF_MAXVARSIZE];
2655 EvalContextClassPutHard(ctx, "eos", "inventory,attribute_name=none,source=agent");
2656 EvalContextClassPutHard(ctx, "arista", "source=agent");
2657 version[0] = '\0';
2658 assert((sizeof(version)) > 255); // TODO: static_assert()
2659 sscanf(buffer, "%*s %*s %*s %255s", version);
2660 CanonifyNameInPlace(version);
2661 snprintf(class, CF_MAXVARSIZE, "eos_%s", version);
2662 EvalContextClassPutHard(ctx, class, "inventory,attribute_name=none,source=agent");
2663 }
2664 }
2665
2666 return 0;
2667 }
2668
2669 /******************************************************************/
2670
MiscOS(EvalContext * ctx)2671 static int MiscOS(EvalContext *ctx)
2672
2673 { char buffer[CF_BUFSIZE];
2674
2675 // e.g. BIG-IP 10.1.0 Build 3341.1084
2676
2677 if (ReadLine("/etc/issue", buffer, sizeof(buffer)))
2678 {
2679 if (strstr(buffer, "BIG-IP"))
2680 {
2681 char version[CF_MAXVARSIZE], build[CF_MAXVARSIZE], class[CF_MAXVARSIZE];
2682 EvalContextClassPutHard(ctx, "big_ip", "inventory,attribute_name=none,source=agent");
2683 assert((sizeof(version)) > 255); // TODO: static_assert()
2684 assert((sizeof(build)) > 255); // TODO: static_assert()
2685 sscanf(buffer, "%*s %255s %*s %255s", version, build);
2686 CanonifyNameInPlace(version);
2687 CanonifyNameInPlace(build);
2688 snprintf(class, CF_MAXVARSIZE, "big_ip_%s", version);
2689 EvalContextClassPutHard(ctx, class, "inventory,attribute_name=none,source=agent");
2690 snprintf(class, CF_MAXVARSIZE, "big_ip_%s_%s", version, build);
2691 EvalContextClassPutHard(ctx, class, "inventory,attribute_name=none,source=agent");
2692 SetFlavor(ctx, "BIG-IP");
2693 }
2694 }
2695
2696 return 0;
2697 }
2698
2699 /******************************************************************/
2700
VM_Version(EvalContext * ctx)2701 static int VM_Version(EvalContext *ctx)
2702 {
2703 char *sp, buffer[CF_BUFSIZE], classbuf[CF_BUFSIZE], version[CF_BUFSIZE];
2704 int major, minor, bug;
2705 int sufficient = 0;
2706
2707 Log(LOG_LEVEL_VERBOSE, "This appears to be a VMware Server ESX/xSX system.");
2708 EvalContextClassPutHard(ctx, "VMware", "inventory,attribute_name=Virtual host,source=agent");
2709
2710 /* VMware Server ESX >= 3 has version info in /proc */
2711 if (ReadLine("/proc/vmware/version", buffer, sizeof(buffer)))
2712 {
2713 if (sscanf(buffer, "VMware ESX Server %d.%d.%d", &major, &minor, &bug) > 0)
2714 {
2715 snprintf(classbuf, CF_BUFSIZE, "VMware ESX Server %d", major);
2716 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2717 snprintf(classbuf, CF_BUFSIZE, "VMware ESX Server %d.%d", major, minor);
2718 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2719 snprintf(classbuf, CF_BUFSIZE, "VMware ESX Server %d.%d.%d", major, minor, bug);
2720 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2721 sufficient = 1;
2722 }
2723 else if (sscanf(buffer, "VMware ESX Server %255s", version) > 0)
2724 {
2725 snprintf(classbuf, CF_BUFSIZE, "VMware ESX Server %s", version);
2726 EvalContextClassPutHard(ctx, classbuf, "inventory,attribute_name=none,source=agent");
2727 sufficient = 1;
2728 }
2729 }
2730
2731 /* Fall back to checking for other files */
2732
2733 if (sufficient < 1 && (ReadLine("/etc/vmware-release", buffer, sizeof(buffer))
2734 || ReadLine("/etc/issue", buffer, sizeof(buffer))))
2735 {
2736 EvalContextClassPutHard(ctx, buffer, "inventory,attribute_name=none,source=agent");
2737
2738 /* Strip off the release code name e.g. "(Dali)" */
2739 if ((sp = strchr(buffer, '(')) != NULL)
2740 {
2741 *sp = 0;
2742 Chop(buffer, CF_EXPANDSIZE);
2743 EvalContextClassPutHard(ctx, buffer, "inventory,attribute_name=none,source=agent");
2744 }
2745 sufficient = 1;
2746 }
2747
2748 return sufficient < 1 ? 1 : 0;
2749 }
2750
2751 /******************************************************************/
2752
Xen_Domain(EvalContext * ctx)2753 static int Xen_Domain(EvalContext *ctx)
2754 {
2755 int sufficient = 0;
2756
2757 Log(LOG_LEVEL_VERBOSE, "This appears to be a xen pv system.");
2758 EvalContextClassPutHard(ctx, "xen", "inventory,attribute_name=Virtual host,source=agent");
2759
2760 /* xen host will have "control_d" in /proc/xen/capabilities, xen guest will not */
2761
2762 FILE *fp = safe_fopen("/proc/xen/capabilities", "r");
2763 if (fp != NULL)
2764 {
2765 size_t buffer_size = CF_BUFSIZE;
2766 char *buffer = xmalloc(buffer_size);
2767
2768 for (;;)
2769 {
2770 ssize_t res = CfReadLine(&buffer, &buffer_size, fp);
2771 if (res == -1)
2772 {
2773 if (!feof(fp))
2774 {
2775 /* Failure reading Xen capabilites. Do we care? */
2776 fclose(fp);
2777 free(buffer);
2778 return 1;
2779 }
2780 else
2781 {
2782 break;
2783 }
2784 }
2785
2786 if (strstr(buffer, "control_d"))
2787 {
2788 EvalContextClassPutHard(ctx, "xen_dom0", "inventory,attribute_name=Virtual host,source=agent");
2789 sufficient = 1;
2790 }
2791 }
2792
2793 if (!sufficient)
2794 {
2795 EvalContextClassPutHard(ctx, "xen_domu_pv", "inventory,attribute_name=Virtual host,source=agent");
2796 sufficient = 1;
2797 }
2798
2799 fclose(fp);
2800 free(buffer);
2801 }
2802
2803 return sufficient < 1 ? 1 : 0;
2804 }
2805
2806 /******************************************************************/
OpenVZ_Detect(EvalContext * ctx)2807 static void OpenVZ_Detect(EvalContext *ctx)
2808 {
2809 /* paths to file defining the type of vm (guest or host) */
2810 #define OPENVZ_HOST_FILENAME "/proc/bc/0"
2811 #define OPENVZ_GUEST_FILENAME "/proc/vz"
2812 /* path to the vzps binary */
2813 #define OPENVZ_VZPS_FILE "/bin/vzps"
2814 struct stat statbuf;
2815
2816 /* The file /proc/bc/0 is present on host
2817 The file /proc/vz is present on guest
2818 If the host has /bin/vzps, we should use it for checking processes
2819 */
2820
2821 if (stat(OPENVZ_HOST_FILENAME, &statbuf) != -1)
2822 {
2823 Log(LOG_LEVEL_VERBOSE, "This appears to be an OpenVZ/Virtuozzo/Parallels Cloud Server host system.\n");
2824 EvalContextClassPutHard(ctx, "virt_host_vz", "inventory,attribute_name=Virtual host,source=agent");
2825 /* if the file /bin/vzps is there, it is safe to use the processes promise type */
2826 if (stat(OPENVZ_VZPS_FILE, &statbuf) != -1)
2827 {
2828 EvalContextClassPutHard(ctx, "virt_host_vz_vzps", "inventory,attribute_name=Virtual host,source=agent");
2829 /* here we must redefine the value of VPSHARDCLASS */
2830 for (int i = 0; i < PLATFORM_CONTEXT_MAX; i++)
2831 {
2832 if (!strcmp(CLASSATTRIBUTES[i][0], "virt_host_vz_vzps"))
2833 {
2834 VPSHARDCLASS = (PlatformContext) i;
2835 break;
2836 }
2837 }
2838 }
2839 else
2840 {
2841 Log(LOG_LEVEL_NOTICE, "This OpenVZ/Virtuozzo/Parallels Cloud Server host system does not have vzps installed; the processes promise type may not work as expected.\n");
2842 }
2843 }
2844 else if (stat(OPENVZ_GUEST_FILENAME, &statbuf) != -1)
2845 {
2846 Log(LOG_LEVEL_VERBOSE, "This appears to be an OpenVZ/Virtuozzo/Parallels Cloud Server guest system.\n");
2847 EvalContextClassPutHard(ctx, "virt_guest_vz", "inventory,attribute_name=Virtual host,source=agent");
2848 }
2849 }
2850
2851 /******************************************************************/
2852
ReadLine(const char * filename,char * buf,int bufsize)2853 static bool ReadLine(const char *filename, char *buf, int bufsize)
2854 {
2855 FILE *fp = ReadFirstLine(filename, buf, bufsize);
2856
2857 if (fp == NULL)
2858 {
2859 return false;
2860 }
2861 else
2862 {
2863 fclose(fp);
2864 return true;
2865 }
2866 }
2867
ReadFirstLine(const char * filename,char * buf,int bufsize)2868 static FILE *ReadFirstLine(const char *filename, char *buf, int bufsize)
2869 {
2870 FILE *fp = safe_fopen(filename, "r");
2871
2872 if (fp == NULL)
2873 {
2874 return NULL;
2875 }
2876
2877 if (fgets(buf, bufsize, fp) == NULL)
2878 {
2879 fclose(fp);
2880 return NULL;
2881 }
2882
2883 StripTrailingNewline(buf, CF_EXPANDSIZE);
2884
2885 return fp;
2886 }
2887 #endif /* __linux__ */
2888
2889 /******************************************************************/
2890
2891 #ifdef XEN_CPUID_SUPPORT
2892
2893 /* Borrowed and modified from Xen source/tools/libxc/xc_cpuid_x86.c */
2894
Xen_Cpuid(uint32_t idx,uint32_t * eax,uint32_t * ebx,uint32_t * ecx,uint32_t * edx)2895 static void Xen_Cpuid(uint32_t idx, uint32_t *eax, uint32_t *ebx, uint32_t *ecx, uint32_t *edx)
2896 {
2897 # ifdef __i386__
2898 /* On i386, %ebx register needs to be saved before usage and restored
2899 * thereafter for PIC-compliant code on i386. */
2900 asm("push %%ebx; cpuid; mov %%ebx,%1; pop %%ebx"
2901 : "=a"(*eax), "=r"(*ebx), "=c"(*ecx), "=d"(*edx)
2902 : "0" (idx), "2" (0) );
2903 # else
2904 asm("cpuid"
2905 : "=a"(*eax), "=b"(*ebx), "=c"(*ecx), "=d"(*edx)
2906 : "0" (idx), "2" (0) );
2907 # endif
2908 }
2909
2910 /******************************************************************/
2911
Xen_Hv_Check(void)2912 static bool Xen_Hv_Check(void)
2913 {
2914 /* CPUID interface to Xen from arch-x86/cpuid.h:
2915 * Leaf 1 (0x40000000)
2916 * EAX: Largest Xen-information leaf. All leaves up to an including @EAX
2917 * are supported by the Xen host.
2918 * EBX-EDX: "XenVMMXenVMM" signature, allowing positive identification
2919 * of a Xen host.
2920 *
2921 * Additional information can be found in the Hypervisor CPUID
2922 * Interface Proposal (https://lkml.org/lkml/2008/10/1/246)
2923 */
2924
2925 uint32_t eax, base;
2926 union
2927 {
2928 uint32_t u[3];
2929 char s[13];
2930 } sig = {{0}};
2931
2932 /*
2933 * For compatibility with other hypervisor interfaces, the Xen cpuid leaves
2934 * can be found at the first otherwise unused 0x100 aligned boundary starting
2935 * from 0x40000000.
2936 *
2937 * e.g If viridian extensions are enabled for an HVM domain, the Xen cpuid
2938 * leaves will start at 0x40000100
2939 */
2940 for (base = 0x40000000; base < 0x40010000; base += 0x100)
2941 {
2942 Xen_Cpuid(base, &eax, &sig.u[0], &sig.u[1], &sig.u[2]);
2943
2944 if (memcmp("XenVMMXenVMM", &sig.s[0], 12) == 0)
2945 {
2946 /* The highest basic calling parameter (largest value that EAX can
2947 * be set to before calling CPUID) is returned in EAX. */
2948 if ((eax - base) < 2)
2949 {
2950 Log(LOG_LEVEL_DEBUG,
2951 "Insufficient Xen CPUID Leaves (eax=%x at base %x)",
2952 eax, base);
2953 return false;
2954 }
2955 Log(LOG_LEVEL_DEBUG,
2956 "Found Xen CPUID Leaf (eax=%x at base %x)", eax, base);
2957 return true;
2958 }
2959 }
2960
2961 return false;
2962 }
2963
2964 #endif /* XEN_CPUID_SUPPORT */
2965
GetCPUInfo(EvalContext * ctx)2966 static void GetCPUInfo(EvalContext *ctx)
2967 {
2968 #if defined(MINGW) || defined(NT)
2969 Log(LOG_LEVEL_VERBOSE, "!! cpu count not implemented on Windows platform");
2970 return;
2971 #else
2972 int count = 0;
2973
2974 // http://preview.tinyurl.com/c9l2sh - StackOverflow on cross-platform CPU counting
2975 #if defined(HAVE_SYSCONF) && defined(_SC_NPROCESSORS_ONLN)
2976 // Linux, AIX, Solaris, Darwin >= 10.4
2977 count = (int)sysconf(_SC_NPROCESSORS_ONLN);
2978 #endif
2979
2980 #if defined(HAVE_SYS_SYSCTL_H) && defined(HW_NCPU)
2981 // BSD-derived platforms
2982 int mib[2] = { CTL_HW, HW_NCPU };
2983 size_t len;
2984
2985 len = sizeof(count);
2986 if(sysctl(mib, 2, &count, &len, NULL, 0) < 0)
2987 {
2988 Log(LOG_LEVEL_ERR, "!! failed to get cpu count: %s", strerror(errno));
2989 }
2990 #endif
2991
2992 #ifdef HAVE_SYS_MPCTL_H
2993 // Itanium processors have Intel Hyper-Threading virtual-core capability,
2994 // and the MPC_GETNUMCORES_SYS operation counts each HT virtual core,
2995 // which is equivalent to what the /proc/stat scan delivers for Linux.
2996 //
2997 // A build on 11i v3 PA would have the GETNUMCORES define, but if run on an
2998 // 11i v1 system it would fail since that OS release has only GETNUMSPUS.
2999 // So in the presence of GETNUMCORES, we check for an invalid arg error
3000 // and fall back to GETNUMSPUS if necessary. An 11i v1 build would work
3001 // normally on 11i v3, because on PA-RISC cores == spus since there's no
3002 // HT on PA-RISC, and 11i v1 only runs on PA-RISC.
3003 # ifdef MPC_GETNUMCORES_SYS
3004 count = mpctl(MPC_GETNUMCORES_SYS, 0, 0);
3005 if (count == -1 && errno == EINVAL)
3006 {
3007 count = mpctl(MPC_GETNUMSPUS_SYS, 0, 0);
3008 }
3009 # else
3010 count = mpctl(MPC_GETNUMSPUS_SYS, 0, 0); // PA-RISC processor count
3011 # endif
3012 #endif /* HAVE_SYS_MPCTL_H */
3013
3014 if (count < 1)
3015 {
3016 Log(LOG_LEVEL_VERBOSE, "invalid processor count: %d", count);
3017 return;
3018 }
3019 Log(LOG_LEVEL_VERBOSE, "Found %d processor%s", count, count > 1 ? "s" : "");
3020
3021 char buf[CF_SMALLBUF] = "1_cpu";
3022 if (count == 1)
3023 {
3024 EvalContextClassPutHard(ctx, buf, "source=agent,derived-from=sys.cpus"); // "1_cpu" from init - change if buf is ever used above
3025 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cpus", "1", CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=CPU logical cores");
3026 }
3027 else
3028 {
3029 snprintf(buf, CF_SMALLBUF, "%d_cpus", count);
3030 EvalContextClassPutHard(ctx, buf, "source=agent,derived-from=sys.cpus");
3031 snprintf(buf, CF_SMALLBUF, "%d", count);
3032 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "cpus", buf, CF_DATA_TYPE_STRING, "inventory,source=agent,attribute_name=CPU logical cores");
3033 }
3034 #endif /* MINGW || NT */
3035 }
3036
3037 /******************************************************************/
3038
3039 // Implemented in Windows specific section.
3040 #ifndef __MINGW32__
3041
3042 /**
3043 Return the number of seconds the system has been online given the current
3044 time() as an argument, or return -1 if unavailable or unimplemented.
3045 */
GetUptimeSeconds(time_t now)3046 int GetUptimeSeconds(time_t now)
3047 {
3048 time_t boot_time = 0;
3049 errno = 0;
3050
3051 #if defined(BOOT_TIME_WITH_SYSINFO) // Most GNU, Linux platforms
3052
3053 struct sysinfo s;
3054 if (sysinfo(&s) == 0)
3055 {
3056 // Don't return yet, sanity checking below
3057 boot_time = now - s.uptime;
3058 }
3059
3060 #elif defined(BOOT_TIME_WITH_KSTAT) // Solaris platform
3061
3062 /* From command line you can get this with:
3063 kstat -p unix:0:system_misc:boot_time */
3064 kstat_ctl_t *kc = kstat_open();
3065 if(kc != 0)
3066 {
3067 kstat_t *kp = kstat_lookup(kc, "unix", 0, "system_misc");
3068 if(kp != 0)
3069 {
3070 if (kstat_read(kc, kp, NULL) != -1)
3071 {
3072 kstat_named_t *knp = kstat_data_lookup(kp, "boot_time");
3073 if (knp != NULL)
3074 {
3075 boot_time = knp->value.ui32;
3076 }
3077 }
3078 }
3079 kstat_close(kc);
3080 }
3081
3082 #elif defined(BOOT_TIME_WITH_PSTAT_GETPROC) // HP-UX platform only
3083
3084 struct pst_status p;
3085 if (pstat_getproc(&p, sizeof(p), 0, 1) == 1)
3086 {
3087 boot_time = (time_t)p.pst_start;
3088 }
3089
3090 #elif defined(BOOT_TIME_WITH_SYSCTL) // BSD-derived platforms
3091
3092 int mib[2] = { CTL_KERN, KERN_BOOTTIME };
3093 struct timeval boot;
3094 size_t len = sizeof(boot);
3095 if (sysctl(mib, 2, &boot, &len, NULL, 0) == 0)
3096 {
3097 boot_time = boot.tv_sec;
3098 }
3099
3100 #elif defined(BOOT_TIME_WITH_PROCFS)
3101
3102 struct stat p;
3103 if (stat("/proc/1", &p) == 0)
3104 {
3105 boot_time = p.st_ctime;
3106 }
3107
3108 #elif defined(BOOT_TIME_WITH_UTMP) /* SystemV, highly portable way */
3109
3110 struct utmp query = { .ut_type = BOOT_TIME };
3111 struct utmp *result;
3112 setutent();
3113 result = getutid(&query);
3114 if (result != NULL)
3115 {
3116 boot_time = result->ut_time;
3117 }
3118 endutent();
3119
3120 #elif defined(BOOT_TIME_WITH_UTMPX) /* POSIX way */
3121
3122 struct utmpx query = { .ut_type = BOOT_TIME };
3123 struct utmpx *result;
3124 setutxent();
3125 result = getutxid(&query);
3126 if (result != NULL)
3127 {
3128 boot_time = result->ut_tv.tv_sec;
3129 }
3130 endutxent();
3131
3132 #endif
3133
3134 if(errno)
3135 {
3136 Log(LOG_LEVEL_VERBOSE, "boot time discovery error: %s", GetErrorStr());
3137 }
3138
3139 if(boot_time > now || boot_time <= 0)
3140 {
3141 Log(LOG_LEVEL_VERBOSE, "invalid boot time found; trying uptime command");
3142 boot_time = GetBootTimeFromUptimeCommand(now);
3143 }
3144
3145 return boot_time > 0 ? now - boot_time : -1;
3146 }
3147 #endif // !__MINGW32__
3148
GetUptimeMinutes(time_t now)3149 int GetUptimeMinutes(time_t now)
3150 {
3151 return GetUptimeSeconds(now) / SECONDS_PER_MINUTE;
3152 }
3153
3154 /******************************************************************/
3155
3156 // Last resort: parse the output of the uptime command with a PCRE regexp
3157 // and convert the uptime to boot time using "now" argument.
3158 //
3159 // The regexp needs to match all variants of the uptime command's output.
3160 // Solaris 8/9/10: 10:45am up 109 day(s), 19:56, 1 user, load average:
3161 // HP-UX 11.11: 9:24am up 1 min, 1 user, load average:
3162 // 8:23am up 23 hrs, 0 users, load average:
3163 // 9:33am up 2 days, 10 mins, 0 users, load average:
3164 // 11:23am up 2 days, 2 hrs, 0 users, load average:
3165 // Red Hat Linux: 10:51:23 up 5 days, 19:54, 1 user, load average:
3166 //
3167 // UPTIME_BACKREFS must be set to this regexp's maximum backreference
3168 // index number (i.e., the count of left-parentheses):
3169 #define UPTIME_REGEXP " up (\\d+ day[^,]*,|) *(\\d+( ho?u?r|:(\\d+))|(\\d+) min)"
3170 #define UPTIME_BACKREFS 5
3171 #define UPTIME_OVECTOR ((UPTIME_BACKREFS + 1) * 3)
3172
GetBootTimeFromUptimeCommand(time_t now)3173 static time_t GetBootTimeFromUptimeCommand(time_t now)
3174 {
3175 FILE *uptimecmd;
3176 pcre *rx;
3177 int ovector[UPTIME_OVECTOR], i;
3178 char *backref = NULL;
3179 const char *uptimepath = "/usr/bin/uptime";
3180 time_t uptime = 0;
3181 const char *errptr;
3182 int erroffset;
3183
3184 rx = pcre_compile(UPTIME_REGEXP, 0, &errptr, &erroffset, NULL);
3185 if (rx == NULL)
3186 {
3187 Log(LOG_LEVEL_DEBUG, "failed to compile regexp to parse uptime command");
3188 return(-1);
3189 }
3190
3191 // Try "/usr/bin/uptime" first, then "/bin/uptime"
3192 uptimecmd = cf_popen(uptimepath, "r", false);
3193 uptimecmd = uptimecmd ? uptimecmd : cf_popen((uptimepath + 4), "r", false);
3194 if (!uptimecmd)
3195 {
3196 Log(LOG_LEVEL_ERR, "uptime failed: (cf_popen: %s)", GetErrorStr());
3197 return -1;
3198 }
3199
3200 size_t uptime_output_size = CF_SMALLBUF;
3201 char *uptime_output = xmalloc(uptime_output_size);
3202 i = CfReadLine(&uptime_output, &uptime_output_size, uptimecmd);
3203
3204 cf_pclose(uptimecmd);
3205 if (i == -1 && !feof(uptimecmd))
3206 {
3207 Log(LOG_LEVEL_ERR, "Reading uptime output failed. (getline: '%s')", GetErrorStr());
3208 return -1;
3209 }
3210
3211 if ((i > 0) && (pcre_exec(rx, NULL, (const char *)uptime_output, i, 0, 0, ovector, UPTIME_OVECTOR) > 1))
3212 {
3213 for (i = 1; i <= UPTIME_BACKREFS ; i++)
3214 {
3215 if (ovector[i * 2 + 1] - ovector[i * 2] == 0) // strlen(backref)
3216 {
3217 continue;
3218 }
3219 backref = uptime_output + ovector[i * 2];
3220 // atoi() ignores non-digits, so no need to null-terminate backref
3221
3222 time_t seconds;
3223 switch(i)
3224 {
3225 case 1: // Day
3226 seconds = SECONDS_PER_DAY;
3227 break;
3228 case 2: // Hour
3229 seconds = SECONDS_PER_HOUR;
3230 break;
3231 case 4: // Minute
3232 case 5:
3233 seconds = SECONDS_PER_MINUTE;
3234 break;
3235 default:
3236 seconds = 0;
3237 }
3238 uptime += ((time_t) atoi(backref)) * seconds;
3239 }
3240 }
3241 else
3242 {
3243 Log(LOG_LEVEL_ERR, "uptime PCRE match failed: regexp: '%s', uptime: '%s'", UPTIME_REGEXP, uptime_output);
3244 }
3245 pcre_free(rx);
3246 Log(LOG_LEVEL_VERBOSE, "Reading boot time from uptime command successful.");
3247 return(uptime ? (now - uptime) : -1);
3248 }
3249
3250 /*****************************************************************************/
3251
3252 /* TODO accept a const char * and move the ifdefs away from
3253 * evalfunction.c:FnCallGetUserInfo() to here. */
GetUserInfo(const void * passwd)3254 JsonElement* GetUserInfo(const void *passwd)
3255 {
3256 #ifdef __MINGW32__
3257 return NULL;
3258
3259 #else /* !__MINGW32__ */
3260
3261 // we lose the const to set pw if passwd is NULL
3262 struct passwd *pw = (struct passwd*) passwd;
3263
3264 if (pw == NULL)
3265 {
3266 pw = getpwuid(getuid());
3267 }
3268
3269 if (pw == NULL)
3270 {
3271 return NULL;
3272 }
3273
3274 JsonElement *result = JsonObjectCreate(10);
3275 JsonObjectAppendString(result, "username", pw->pw_name);
3276 JsonObjectAppendString(result, "description", pw->pw_gecos);
3277 JsonObjectAppendString(result, "home_dir", pw->pw_dir);
3278 JsonObjectAppendString(result, "shell", pw->pw_shell);
3279 JsonObjectAppendInteger(result, "uid", pw->pw_uid);
3280 JsonObjectAppendInteger(result, "gid", pw->pw_gid);
3281 //JsonObjectAppendBool(result, "locked", IsAccountLocked(pw->pw_name, pw));
3282 // TODO: password: { format: "hash", data: { ...GetPasswordHash()... } }
3283 // TODO: group_primary: name of group
3284 // TODO: groups_secondary: [ names of groups ]
3285 // TODO: gids_secondary: [ gids of groups ]
3286
3287 return result;
3288 #endif
3289 }
3290
3291 /*****************************************************************************/
3292
GetSysVars(EvalContext * ctx)3293 void GetSysVars(EvalContext *ctx)
3294 {
3295 /* Get info for current user. */
3296 JsonElement *info = GetUserInfo(NULL);
3297 if (info != NULL)
3298 {
3299 EvalContextVariablePutSpecial(ctx, SPECIAL_SCOPE_SYS, "user_data",
3300 info, CF_DATA_TYPE_CONTAINER,
3301 "source=agent,user_info");
3302 JsonDestroy(info);
3303 }
3304 }
3305
3306 /*****************************************************************************/
3307
GetDefVars(EvalContext * ctx)3308 void GetDefVars(EvalContext *ctx)
3309 {
3310 EvalContextVariablePutSpecial(
3311 ctx, SPECIAL_SCOPE_DEF, "jq",
3312 "jq --compact-output --monochrome-output --ascii-output --unbuffered --sort-keys",
3313 CF_DATA_TYPE_STRING, "invocation,source=agent,command_name=jq");
3314 }
3315 /*****************************************************************************/
3316
DetectEnvironment(EvalContext * ctx)3317 void DetectEnvironment(EvalContext *ctx)
3318 {
3319 GetNameInfo3(ctx);
3320 GetInterfacesInfo(ctx);
3321 GetNetworkingInfo(ctx);
3322 Get3Environment(ctx);
3323 BuiltinClasses(ctx);
3324 OSClasses(ctx);
3325 GetSysVars(ctx);
3326 GetDefVars(ctx);
3327 }
3328