1 /* Copyright (C) 2009 Trend Micro Inc.
4 * This program is a free software; you can redistribute it
5 * and/or modify it under the terms of the GNU General Public
6 * License (version 2) as published by the FSF - Free Software
11 #include "os_crypto/md5/md5_op.h"
12 #include "agentlessd.h"
15 static int save_agentless_entry(const char *host, const char *script, const char *agttype);
16 static int send_intcheck_msg(const char *script, const char *host, const char *msg);
17 static int send_log_msg(const char *script, const char *host, const char *msg);
18 static int gen_diff_alert(const char *host, const char *script, time_t alert_diff_time);
19 static int check_diff_file(const char *host, const char *script);
20 static FILE *open_diff_file(const char *host, const char *script);
21 static int run_periodic_cmd(agentlessd_entries *entry, int test_it);
23 /* Global variables */
24 agentlessd_config lessdc;
27 /* Save agentless entry for the control tools to gather */
28 static int save_agentless_entry(const char *host, const char *script, const char *agttype)
31 char sys_location[1024 + 1];
33 sys_location[1024] = '\0';
34 snprintf(sys_location, 1024, "%s/(%s) %s",
35 AGENTLESS_ENTRYDIRPATH, script, host);
37 fp = fopen(sys_location, "w");
39 fprintf(fp, "type: %s\n", agttype);
42 merror(FOPEN_ERROR, ARGV0, sys_location, errno, strerror(errno));
48 /* Send integrity checking message */
49 static int send_intcheck_msg(const char *script, const char *host, const char *msg)
51 char sys_location[1024 + 1];
53 sys_location[1024] = '\0';
54 snprintf(sys_location, 1024, "(%s) %s->%s", script, host, SYSCHECK);
56 if (SendMSG(lessdc.queue, msg, sys_location, SYSCHECK_MQ) < 0) {
57 merror(QUEUE_SEND, ARGV0);
59 if ((lessdc.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
60 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
63 /* If we reach here, we can try to send it again */
64 SendMSG(lessdc.queue, msg, sys_location, SYSCHECK_MQ);
70 /* Send generic log message */
71 static int send_log_msg(const char *script, const char *host, const char *msg)
73 char sys_location[1024 + 1];
75 sys_location[1024] = '\0';
76 snprintf(sys_location, 1024, "(%s) %s->%s", script, host, SYSCHECK);
78 if (SendMSG(lessdc.queue, msg, sys_location, LOCALFILE_MQ) < 0) {
79 merror(QUEUE_SEND, ARGV0);
80 if ((lessdc.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
81 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
84 /* If we reach here, we can try to send it again */
85 SendMSG(lessdc.queue, msg, sys_location, LOCALFILE_MQ);
90 /* Generate diffs alert */
91 static int gen_diff_alert(const char *host, const char *script, time_t alert_diff_time)
97 char diff_alert[4096 + 1];
100 diff_alert[4096] = '\0';
102 snprintf(buf, 2048, "%s/%s->%s/diff.%d",
103 DIFF_DIR_PATH, host, script, (int)alert_diff_time);
105 fp = fopen(buf, "r");
107 merror("%s: ERROR: Unable to generate diff alert.", ARGV0);
111 n = fread(buf, 1, 2048 - 1, fp);
113 merror("%s: ERROR: Unable to generate diff alert (fread).", ARGV0);
116 } else if (n >= 2040) {
117 /* We need to clear the last newline */
119 tmp_str = strrchr(buf, '\n');
123 /* Weird diff with only one large line */
132 /* Get up to 8 line changes */
135 while (tmp_str && (*tmp_str != '\0')) {
136 tmp_str = strchr(tmp_str, '\n');
148 snprintf(diff_alert, 4096 - 1, "ossec: agentless: Change detected:\n%s%s",
153 snprintf(buf, 1024, "(%s) %s->agentless", script, host);
155 if (SendMSG(lessdc.queue, diff_alert, buf, LOCALFILE_MQ) < 0) {
156 merror(QUEUE_SEND, ARGV0);
158 if ((lessdc.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
159 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
162 /* If we reach here, we can try to send it again */
163 SendMSG(lessdc.queue, diff_alert, buf, LOCALFILE_MQ);
166 save_agentless_entry(host, script, "diff");
172 /* Check if the file has changed */
173 static int check_diff_file(const char *host, const char *script)
175 time_t date_of_change;
176 char old_location[1024 + 1];
177 char new_location[1024 + 1];
178 char tmp_location[1024 + 1];
179 char diff_cmd[2048 + 1];
184 old_location[1024] = '\0';
185 new_location[1024] = '\0';
186 tmp_location[1024] = '\0';
187 diff_cmd[2048] = '\0';
189 snprintf(new_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host, script,
191 snprintf(old_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host, script,
194 /* If the file is not there, rename new location to last location */
195 if (OS_MD5_File(old_location, md5sum_old, OS_TEXT) != 0) {
196 if (rename(new_location, old_location) != 0) {
197 merror(RENAME_ERROR, ARGV0, new_location, old_location, errno, strerror(errno));
202 /* Get md5sum of the new file */
203 if (OS_MD5_File(new_location, md5sum_new, OS_TEXT) != 0) {
204 merror("%s: ERROR: Invalid internal state (missing '%s').",
205 ARGV0, new_location);
209 /* If they match, keep the old file and remove the new */
210 if (strcmp(md5sum_new, md5sum_old) == 0) {
211 unlink(new_location);
215 /* Save the old file at timestamp and rename new to last */
216 date_of_change = File_DateofChange(old_location);
217 snprintf(tmp_location, 1024, "%s/%s->%s/state.%d", DIFF_DIR_PATH, host, script,
218 (int)date_of_change);
220 if (rename(old_location, tmp_location) != 0) {
221 merror(RENAME_ERROR, ARGV0, old_location, tmp_location, errno, strerror(errno));
224 if (rename(new_location, old_location) != 0) {
225 merror(RENAME_ERROR, ARGV0, new_location, old_location, errno, strerror(errno));
230 date_of_change = File_DateofChange(old_location);
231 snprintf(diff_cmd, 2048, "diff \"%s\" \"%s\" > \"%s/%s->%s/diff.%d\" "
233 tmp_location, old_location,
234 DIFF_DIR_PATH, host, script, (int)date_of_change);
235 if (system(diff_cmd) != 256) {
236 merror("%s: ERROR: Unable to run diff for %s->%s",
237 ARGV0, host, script);
242 gen_diff_alert(host, script, date_of_change);
247 /* Get the diff file */
248 static FILE *open_diff_file(const char *host, const char *script)
251 char sys_location[1024 + 1];
253 sys_location[1024] = '\0';
254 snprintf(sys_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host, script,
257 fp = fopen(sys_location, "w");
259 /* If we can't open, try creating the directory */
261 snprintf(sys_location, 1024, "%s/%s->%s", DIFF_DIR_PATH, host, script);
262 if (IsDir(sys_location) == -1) {
263 if (mkdir(sys_location, 0770) == -1) {
264 merror(MKDIR_ERROR, ARGV0, sys_location, errno, strerror(errno));
269 snprintf(sys_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host,
270 script, DIFF_NEW_FILE);
271 fp = fopen(sys_location, "w");
273 merror(FOPEN_ERROR, ARGV0, sys_location, errno, strerror(errno));
281 /* Run periodic commands */
282 static int run_periodic_cmd(agentlessd_entries *entry, int test_it)
286 char buf[OS_SIZE_2048 + 1];
287 char command[OS_SIZE_1024 + 1];
289 FILE *fp_store = NULL;
293 command[OS_SIZE_1024] = '\0';
295 while (entry->server[i]) {
297 if (entry->server[i][0] == '\0') {
302 /* We only test for the first server entry */
305 snprintf(command, OS_SIZE_1024,
306 "%s/%s test test >/dev/null 2>&1",
307 AGENTLESSDIRPATH, entry->type);
308 ret_code = system(command);
310 /* Check if the test worked */
312 if (ret_code == 32512) {
313 merror("%s: ERROR: Expect command not found (or bad "
314 "arguments) for '%s'.",
317 merror("%s: ERROR: Test failed for '%s' (%d). Ignoring.",
318 ARGV0, entry->type, ret_code / 256);
319 entry->error_flag = 99;
323 verbose("%s: INFO: Test passed for '%s'.", ARGV0, entry->type);
327 if (entry->server[i][0] == 's') {
328 snprintf(command, OS_SIZE_1024, "%s/%s \"use_su\" \"%s\" %s 2>&1",
329 AGENTLESSDIRPATH, entry->type, entry->server[i] + 1,
331 } else if (entry->server[i][0] == 'o') {
332 snprintf(command, OS_SIZE_1024, "%s/%s \"use_sudo\" \"%s\" %s 2>&1",
333 AGENTLESSDIRPATH, entry->type, entry->server[i] + 1,
336 snprintf(command, OS_SIZE_1024, "%s/%s \"%s\" %s 2>&1",
337 AGENTLESSDIRPATH, entry->type, entry->server[i] + 1,
341 fp = popen(command, "r");
343 while (fgets(buf, OS_SIZE_2048, fp) != NULL) {
344 /* Remove newlines and carriage returns */
345 tmp_str = strchr(buf, '\r');
349 tmp_str = strchr(buf, '\n');
354 if (strncmp(buf, "ERROR: ", 7) == 0) {
355 merror("%s: ERROR: %s: %s: %s", ARGV0,
356 entry->type, entry->server[i] + 1, buf + 7);
359 } else if (strncmp(buf, "INFO: ", 6) == 0) {
360 verbose("%s: INFO: %s: %s: %s", ARGV0,
361 entry->type, entry->server[i] + 1, buf + 6);
362 } else if (strncmp(buf, "FWD: ", 4) == 0) {
364 send_intcheck_msg(entry->type, entry->server[i] + 1,
366 } else if (strncmp(buf, "LOG: ", 4) == 0) {
368 send_log_msg(entry->type, entry->server[i] + 1,
370 } else if ((entry->state & LESSD_STATE_DIFF) &&
371 (strncmp(buf, "STORE: ", 7) == 0)) {
375 fp_store = open_diff_file(entry->server[i] + 1,
377 } else if (fp_store) {
378 fprintf(fp_store, "%s\n", buf);
380 debug1("%s: DEBUG: buffer: %s", ARGV0, buf);
388 check_diff_file(entry->server[i] + 1, entry->type);
390 save_agentless_entry(entry->server[i] + 1,
391 entry->type, "syscheck");
395 merror("%s: ERROR: popen failed on '%s' for '%s'.", ARGV0,
396 entry->type, entry->server[i] + 1);
410 /* Main agentlessd */
419 char str[OS_SIZE_1024 + 1];
421 /* Wait a few seconds to settle */
423 memset(str, '\0', OS_SIZE_1024 + 1);
425 /* Get current time before starting */
431 /* Connect to the message queue. Exit if it fails. */
432 if ((lessdc.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0) {
433 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQUEUE);
436 /* Main monitor loop */
442 /* Day changed, deal with log files */
443 if (today != p->tm_mday) {
447 while (lessdc.entries[i]) {
448 if (lessdc.entries[i]->error_flag >= 10) {
449 if (lessdc.entries[i]->error_flag != 99) {
450 merror("%s: ERROR: Too many failures for '%s'. Ignoring it.",
451 ARGV0, lessdc.entries[i]->type);
452 lessdc.entries[i]->error_flag = 99;
460 /* Run the check again if the frequency has elapsed */
461 if ((lessdc.entries[i]->state & LESSD_STATE_PERIODIC) &&
462 ((lessdc.entries[i]->current_state +
463 lessdc.entries[i]->frequency) < tm)) {
464 run_periodic_cmd(lessdc.entries[i], test_it);
466 lessdc.entries[i]->current_state = tm;
475 /* We only check every minute */