1 /* @(#) $Id: ./src/agentlessd/agentlessd.c, 2011/09/08 dcid Exp $
4 /* Copyright (C) 2009 Trend Micro Inc.
7 * This program is a free software; you can redistribute it
8 * and/or modify it under the terms of the GNU General Public
9 * License (version 2) as published by the FSF - Free Software
16 #include "os_crypto/md5/md5_op.h"
17 #include "agentlessd.h"
21 /* Saves agentless entry for the control tools to gather. */
22 int save_agentless_entry(char *host, char *script, char *agttype)
25 char sys_location[1024 +1];
27 sys_location[1024] = '\0';
28 snprintf(sys_location, 1024, "%s/(%s) %s",
29 AGENTLESS_ENTRYDIRPATH, script, host);
31 fp = fopen(sys_location, "w");
34 fprintf(fp, "type: %s\n", agttype);
39 merror(FOPEN_ERROR, ARGV0, sys_location);
47 /* send integrity checking message. */
48 int send_intcheck_msg(char *script, char *host, char *msg)
50 char sys_location[1024 +1];
52 sys_location[1024] = '\0';
53 snprintf(sys_location, 1024, "(%s) %s->%s", script, host, SYSCHECK);
55 if(SendMSG(lessdc.queue, msg, sys_location, SYSCHECK_MQ) < 0)
57 merror(QUEUE_SEND, ARGV0);
59 if((lessdc.queue = StartMQ(DEFAULTQPATH,WRITE)) < 0)
61 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
64 /* If we reach here, we can try to send it again */
65 SendMSG(lessdc.queue, msg, sys_location, SYSCHECK_MQ);
73 /* Send generic log message. */
74 int send_log_msg(char *script, char *host, char *msg)
76 char sys_location[1024 +1];
78 sys_location[1024] = '\0';
79 snprintf(sys_location, 1024, "(%s) %s->%s", script, host, SYSCHECK);
81 if(SendMSG(lessdc.queue, msg, sys_location, LOCALFILE_MQ) < 0)
83 merror(QUEUE_SEND, ARGV0);
84 if((lessdc.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0)
86 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
89 /* If we reach here, we can try to send it again */
90 SendMSG(lessdc.queue, msg, sys_location, LOCALFILE_MQ);
97 /* Generate diffs alerts. */
98 int gen_diff_alert(char *host, char *script, int alert_diff_time)
104 char diff_alert[4096 +1];
107 diff_alert[4096] = '\0';
109 snprintf(buf, 2048, "%s/%s->%s/diff.%d",
110 DIFF_DIR_PATH, host, script, alert_diff_time);
112 fp = fopen(buf, "r");
115 merror("%s: ERROR: Unable to generate diff alert.", ARGV0);
119 n = fread(buf, 1, 2048 -1, fp);
122 merror("%s: ERROR: Unable to generate diff alert (fread).", ARGV0);
128 /* We need to clear the last new line. */
130 tmp_str = strrchr(buf, '\n');
135 /* Weird diff with only one large line. */
147 /* Getting up to 8 line changes. */
150 while(tmp_str && (*tmp_str != '\0'))
152 tmp_str = strchr(tmp_str, '\n');
165 /* Creating alert. */
166 snprintf(diff_alert, 4096 -1, "ossec: agentless: Change detected:\n%s%s",
172 snprintf(buf, 1024, "(%s) %s->agentless", script, host);
174 if(SendMSG(lessdc.queue, diff_alert, buf, LOCALFILE_MQ) < 0)
176 merror(QUEUE_SEND, ARGV0);
178 if((lessdc.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0)
180 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
183 /* If we reach here, we can try to send it again */
184 SendMSG(lessdc.queue, diff_alert, buf, LOCALFILE_MQ);
187 save_agentless_entry(host, script, "diff");
195 /* Checks if the file has changed */
196 int check_diff_file(char *host, char *script)
199 char old_location[1024 +1];
200 char new_location[1024 +1];
201 char tmp_location[1024 +1];
202 char diff_cmd[2048 +1];
207 old_location[1024] = '\0';
208 new_location[1024] = '\0';
209 tmp_location[1024] = '\0';
210 diff_cmd[2048] = '\0';
212 snprintf(new_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host, script,
214 snprintf(old_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host, script,
218 /* If the file is not there, rename new location to last location. */
219 if(OS_MD5_File(old_location, md5sum_old) != 0)
221 if(rename(new_location, old_location) != 0)
223 merror(RENAME_ERROR, ARGV0, new_location);
228 /* Get md5sum of the new file. */
229 if(OS_MD5_File(new_location, md5sum_new) != 0)
231 merror("%s: ERROR: Invalid internal state (missing '%s').",
232 ARGV0, new_location);
236 /* If they match, keep the old file and remove the new. */
237 if(strcmp(md5sum_new, md5sum_old) == 0)
239 unlink(new_location);
244 /* Saving the old file at timestamp and renaming new to last. */
245 date_of_change = File_DateofChange(old_location);
246 snprintf(tmp_location, 1024, "%s/%s->%s/state.%d", DIFF_DIR_PATH, host, script,
248 rename(old_location, tmp_location);
249 rename(new_location, old_location);
253 date_of_change = File_DateofChange(old_location);
254 snprintf(diff_cmd, 2048, "diff \"%s\" \"%s\" > \"%s/%s->%s/diff.%d\" "
256 tmp_location, old_location,
257 DIFF_DIR_PATH, host, script, date_of_change);
258 if(system(diff_cmd) != 256)
260 merror("%s: ERROR: Unable to run diff for %s->%s",
261 ARGV0, host, script);
266 /* Generate alert. */
267 gen_diff_alert(host, script, date_of_change);
275 /* get the diff file. */
276 FILE *open_diff_file(char *host, char *script)
279 char sys_location[1024 +1];
281 sys_location[1024] = '\0';
282 snprintf(sys_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host, script,
286 fp = fopen(sys_location, "w");
288 /* If we can't open, try creating the directory. */
291 snprintf(sys_location, 1024, "%s/%s->%s", DIFF_DIR_PATH, host, script);
292 if(IsDir(sys_location) == -1)
294 if(mkdir(sys_location, 0770) == -1)
296 merror(MKDIR_ERROR, ARGV0, sys_location);
301 snprintf(sys_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host,
302 script, DIFF_NEW_FILE);
303 fp = fopen(sys_location, "w");
306 merror(FOPEN_ERROR, ARGV0, sys_location);
316 /* Run periodic commands. */
317 int run_periodic_cmd(agentlessd_entries *entry, int test_it)
321 char buf[OS_SIZE_2048 +1];
322 char command[OS_SIZE_1024 +1];
324 FILE *fp_store = NULL;
329 command[OS_SIZE_1024] = '\0';
332 while(entry->server[i])
335 if(entry->server[i][0] == '\0')
342 /* We only test for the first server entry. */
346 snprintf(command, OS_SIZE_1024,
347 "%s/%s test test >/dev/null 2>&1",
348 AGENTLESSDIRPATH, entry->type);
349 ret_code = system(command);
351 /* Checking if the test worked. */
354 if(ret_code == 32512)
356 merror("%s: ERROR: Expect command not found (or bad "
357 "arguments) for '%s'.",
360 merror("%s: ERROR: Test failed for '%s' (%d). Ignoring.",
361 ARGV0, entry->type, ret_code/256);
362 entry->error_flag = 99;
366 verbose("%s: INFO: Test passed for '%s'.", ARGV0, entry->type);
370 if(entry->server[i][0] == 's')
372 snprintf(command, OS_SIZE_1024, "%s/%s \"use_su\" \"%s\" %s 2>&1",
373 AGENTLESSDIRPATH, entry->type, entry->server[i] +1,
376 else if(entry->server[i][0] == 'o')
378 snprintf(command, OS_SIZE_1024, "%s/%s \"use_sudo\" \"%s\" %s 2>&1",
379 AGENTLESSDIRPATH, entry->type, entry->server[i] +1,
384 snprintf(command, OS_SIZE_1024, "%s/%s \"%s\" %s 2>&1",
385 AGENTLESSDIRPATH, entry->type, entry->server[i] +1,
389 fp = popen(command, "r");
392 while(fgets(buf, OS_SIZE_2048, fp) != NULL)
394 /* Removing new lines or carriage returns. */
395 tmp_str = strchr(buf, '\r');
398 tmp_str = strchr(buf, '\n');
402 if(strncmp(buf, "ERROR: ", 7) == 0)
404 merror("%s: ERROR: %s: %s: %s", ARGV0,
405 entry->type, entry->server[i] +1, buf +7);
409 else if(strncmp(buf, "INFO: ", 6) == 0)
411 verbose("%s: INFO: %s: %s: %s", ARGV0,
412 entry->type, entry->server[i] +1, buf +6);
414 else if(strncmp(buf, "FWD: ", 4) == 0)
417 send_intcheck_msg(entry->type, entry->server[i]+1,
420 else if(strncmp(buf, "LOG: ", 4) == 0)
423 send_log_msg(entry->type, entry->server[i]+1,
426 else if((entry->state & LESSD_STATE_DIFF) &&
427 (strncmp(buf, "STORE: ", 7) == 0))
429 fp_store = open_diff_file(entry->server[i]+1,
434 fprintf(fp_store, "%s\n", buf);
438 debug1("%s: DEBUG: buffer: %s", ARGV0, buf);
447 check_diff_file(entry->server[i] +1, entry->type);
451 save_agentless_entry(entry->server[i] +1,
452 entry->type, "syscheck");
458 merror("%s: ERROR: popen failed on '%s' for '%s'.", ARGV0,
459 entry->type, entry->server[i] +1);
476 /* Main agentlessd */
485 char str[OS_SIZE_1024 +1];
488 /* Waiting a few seconds to settle */
490 memset(str, '\0', OS_SIZE_1024 +1);
493 /* Getting currently time before starting */
500 /* Connecting to the message queue
503 if((lessdc.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0)
505 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQUEUE);
510 /* Main monitor loop */
518 /* Day changed, deal with log files */
519 if(today != p->tm_mday)
525 while(lessdc.entries[i])
527 if(lessdc.entries[i]->error_flag >= 10)
529 if(lessdc.entries[i]->error_flag != 99)
531 merror("%s: ERROR: Too many failures for '%s'. Ignoring it.",
532 ARGV0, lessdc.entries[i]->type);
533 lessdc.entries[i]->error_flag = 99;
542 /* Run the check again if the frequency has elapsed. */
543 if((lessdc.entries[i]->state & LESSD_STATE_PERIODIC) &&
544 ((lessdc.entries[i]->current_state +
545 lessdc.entries[i]->frequency) < tm))
547 run_periodic_cmd(lessdc.entries[i], test_it);
549 lessdc.entries[i]->current_state = tm;
557 /* We only check every minute */