1 /* @(#) $Id: agentlessd.c,v 1.13 2009/06/24 17:06:20 dcid Exp $ */
3 /* Copyright (C) 2009 Trend Micro Inc.
6 * This program is a free software; you can redistribute it
7 * and/or modify it under the terms of the GNU General Public
8 * License (version 3) as published by the FSF - Free Software
15 #include "os_crypto/md5/md5_op.h"
16 #include "agentlessd.h"
20 /* Saves agentless entry for the control tools to gather. */
21 int save_agentless_entry(char *host, char *script, char *agttype)
24 char sys_location[1024 +1];
26 sys_location[1024] = '\0';
27 snprintf(sys_location, 1024, "%s/(%s) %s",
28 AGENTLESS_ENTRYDIRPATH, script, host);
30 fp = fopen(sys_location, "w");
33 fprintf(fp, "type: %s\n", agttype);
38 merror(FOPEN_ERROR, ARGV0, sys_location);
46 /* send integrity checking message. */
47 int send_intcheck_msg(char *script, char *host, char *msg)
49 char sys_location[1024 +1];
51 sys_location[1024] = '\0';
52 snprintf(sys_location, 1024, "(%s) %s->%s", script, host, SYSCHECK);
54 if(SendMSG(lessdc.queue, msg, sys_location, SYSCHECK_MQ) < 0)
56 merror(QUEUE_SEND, ARGV0);
58 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);
72 /* Generate diffs alerts. */
73 int gen_diff_alert(char *host, char *script, int alert_diff_time)
79 char diff_alert[4096 +1];
82 diff_alert[4096] = '\0';
84 snprintf(buf, 2048, "%s/%s->%s/diff.%d",
85 DIFF_DIR_PATH, host, script, alert_diff_time);
90 merror("%s: ERROR: Unable to generate diff alert.", ARGV0);
94 n = fread(buf, 1, 2048 -1, fp);
97 merror("%s: ERROR: Unable to generate diff alert (fread).", ARGV0);
103 /* We need to clear the last new line. */
105 tmp_str = strrchr(buf, '\n');
110 /* Weird diff with only one large line. */
122 /* Getting up to 8 line changes. */
125 while(tmp_str && (*tmp_str != '\0'))
127 tmp_str = strchr(tmp_str, '\n');
140 /* Creating alert. */
141 snprintf(diff_alert, 4096 -1, "ossec: agentless: Change detected:\n%s%s",
147 snprintf(buf, 1024, "(%s) %s->agentless", script, host);
149 if(SendMSG(lessdc.queue, diff_alert, buf, LOCALFILE_MQ) < 0)
151 merror(QUEUE_SEND, ARGV0);
153 if((lessdc.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0)
155 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQPATH);
158 /* If we reach here, we can try to send it again */
159 SendMSG(lessdc.queue, diff_alert, buf, LOCALFILE_MQ);
162 save_agentless_entry(host, script, "diff");
170 /* Checks if the file has changed */
171 int check_diff_file(char *host, char *script)
174 char old_location[1024 +1];
175 char new_location[1024 +1];
176 char tmp_location[1024 +1];
177 char diff_cmd[2048 +1];
182 old_location[1024] = '\0';
183 new_location[1024] = '\0';
184 tmp_location[1024] = '\0';
185 diff_cmd[2048] = '\0';
187 snprintf(new_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host, script,
189 snprintf(old_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host, script,
193 /* If the file is not there, rename new location to last location. */
194 if(OS_MD5_File(old_location, md5sum_old) != 0)
196 if(rename(new_location, old_location) != 0)
198 merror(RENAME_ERROR, ARGV0, new_location);
203 /* Get md5sum of the new file. */
204 if(OS_MD5_File(new_location, md5sum_new) != 0)
206 merror("%s: ERROR: Invalid internal state (missing '%s').",
207 ARGV0, new_location);
211 /* If they match, keep the old file and remove the new. */
212 if(strcmp(md5sum_new, md5sum_old) == 0)
214 unlink(new_location);
219 /* Saving the old file at timestamp and renaming new to last. */
220 date_of_change = File_DateofChange(old_location);
221 snprintf(tmp_location, 1024, "%s/%s->%s/state.%d", DIFF_DIR_PATH, host, script,
223 rename(old_location, tmp_location);
224 rename(new_location, old_location);
228 date_of_change = File_DateofChange(old_location);
229 snprintf(diff_cmd, 2048, "diff \"%s\" \"%s\" > \"%s/%s->%s/diff.%d\" "
231 tmp_location, old_location,
232 DIFF_DIR_PATH, host, script, date_of_change);
233 if(system(diff_cmd) != 256)
235 merror("%s: ERROR: Unable to run diff for %s->%s",
236 ARGV0, host, script);
241 /* Generate alert. */
242 gen_diff_alert(host, script, date_of_change);
250 /* get the diff file. */
251 FILE *open_diff_file(char *host, char *script)
254 char sys_location[1024 +1];
256 sys_location[1024] = '\0';
257 snprintf(sys_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host, script,
261 fp = fopen(sys_location, "w");
263 /* If we can't open, try creating the directory. */
266 snprintf(sys_location, 1024, "%s/%s->%s", DIFF_DIR_PATH, host, script);
267 if(IsDir(sys_location) == -1)
269 if(mkdir(sys_location, 0770) == -1)
271 merror(MKDIR_ERROR, ARGV0, sys_location);
276 snprintf(sys_location, 1024, "%s/%s->%s/%s", DIFF_DIR_PATH, host,
277 script, DIFF_NEW_FILE);
278 fp = fopen(sys_location, "w");
281 merror(FOPEN_ERROR, ARGV0, sys_location);
291 /* Run periodic commands. */
292 int run_periodic_cmd(agentlessd_entries *entry, int test_it)
296 char buf[OS_SIZE_2048 +1];
297 char command[OS_SIZE_1024 +1];
299 FILE *fp_store = NULL;
304 command[OS_SIZE_1024] = '\0';
307 while(entry->server[i])
310 if(entry->server[i][0] == '\0')
317 /* We only test for the first server entry. */
321 snprintf(command, OS_SIZE_1024,
322 "%s/%s test test >/dev/null 2>&1",
323 AGENTLESSDIRPATH, entry->type);
324 ret_code = system(command);
326 /* Checking if the test worked. */
329 if(ret_code == 32512)
331 merror("%s: ERROR: Expect command not found (or bad "
332 "arguments) for '%s'.",
335 merror("%s: ERROR: Test failed for '%s' (%d). Ignoring.",
336 ARGV0, entry->type, ret_code/256);
337 entry->error_flag = 99;
341 verbose("%s: INFO: Test passed for '%s'.", ARGV0, entry->type);
345 if(entry->server[i][0] == 's')
347 snprintf(command, OS_SIZE_1024, "%s/%s \"use_su\" \"%s\" %s 2>&1",
348 AGENTLESSDIRPATH, entry->type, entry->server[i] +1,
351 else if(entry->server[i][0] == 'o')
353 snprintf(command, OS_SIZE_1024, "%s/%s \"use_sudo\" \"%s\" %s 2>&1",
354 AGENTLESSDIRPATH, entry->type, entry->server[i] +1,
359 snprintf(command, OS_SIZE_1024, "%s/%s \"%s\" %s 2>&1",
360 AGENTLESSDIRPATH, entry->type, entry->server[i] +1,
364 fp = popen(command, "r");
367 while(fgets(buf, OS_SIZE_2048, fp) != NULL)
369 /* Removing new lines or carriage returns. */
370 tmp_str = strchr(buf, '\r');
373 tmp_str = strchr(buf, '\n');
377 if(strncmp(buf, "ERROR: ", 7) == 0)
379 merror("%s: ERROR: %s: %s: %s", ARGV0,
380 entry->type, entry->server[i] +1, buf +7);
384 else if(strncmp(buf, "INFO: ", 6) == 0)
386 verbose("%s: INFO: %s: %s: %s", ARGV0,
387 entry->type, entry->server[i] +1, buf +6);
389 else if(strncmp(buf, "FWD: ", 4) == 0)
392 send_intcheck_msg(entry->type, entry->server[i]+1,
395 else if((entry->state & LESSD_STATE_DIFF) &&
396 (strncmp(buf, "STORE: ", 7) == 0))
398 fp_store = open_diff_file(entry->server[i]+1,
403 fprintf(fp_store, "%s\n", buf);
407 debug1("%s: DEBUG: buffer: %s", ARGV0, buf);
416 check_diff_file(entry->server[i] +1, entry->type);
420 save_agentless_entry(entry->server[i] +1,
421 entry->type, "syscheck");
427 merror("%s: ERROR: popen failed on '%s' for '%s'.", ARGV0,
428 entry->type, entry->server[i] +1);
445 /* Main agentlessd */
456 char str[OS_SIZE_1024 +1];
459 /* Waiting a few seconds to settle */
461 memset(str, '\0', OS_SIZE_1024 +1);
464 /* Getting currently time before starting */
469 thismonth = p->tm_mon;
470 thisyear = p->tm_year+1900;
473 /* Connecting to the message queue
476 if((lessdc.queue = StartMQ(DEFAULTQPATH, WRITE)) < 0)
478 ErrorExit(QUEUE_FATAL, ARGV0, DEFAULTQUEUE);
483 /* Main monitor loop */
491 /* Day changed, deal with log files */
492 if(today != p->tm_mday)
495 thismonth = p->tm_mon;
496 thisyear = p->tm_year+1900;
500 while(lessdc.entries[i])
502 if(lessdc.entries[i]->error_flag >= 10)
504 if(lessdc.entries[i]->error_flag != 99)
506 merror("%s: ERROR: Too many failures for '%s'. Ignoring it.",
507 ARGV0, lessdc.entries[i]->type);
508 lessdc.entries[i]->error_flag = 99;
517 /* Run the check again if the frequency has elapsed. */
518 if((lessdc.entries[i]->state & LESSD_STATE_PERIODIC) &&
519 ((lessdc.entries[i]->current_state +
520 lessdc.entries[i]->frequency) < tm))
522 run_periodic_cmd(lessdc.entries[i], test_it);
524 lessdc.entries[i]->current_state = tm;
532 /* We only check every minute */