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 "read-agents.h"
12 #include "os_net/os_net.h"
15 static int _do_print_attrs_syscheck(const char *prev_attrs, const char *attrs, int csv_output, cJSON *json_output,
16 int is_win, int number_of_changes) __attribute__((nonnull(2)));
17 static int _do_print_file_syscheck(FILE *fp, const char *fname, int update_counter,
18 int csv_output, cJSON *json_output) __attribute__((nonnull(1)));
19 static int _do_print_syscheck(FILE *fp, int all_files, int csv_output, cJSON *json_output) __attribute__((nonnull(1)));
20 static int _do_get_rootcheckscan(FILE *fp) __attribute__((nonnull));
21 static int _do_print_rootcheck(FILE *fp, int resolved, time_t time_last_scan,
22 int csv_output, cJSON *json_output, int show_last) __attribute__((nonnull(1)));
26 static int _get_time_rkscan(const char *agent_name, const char *agent_ip, agent_info *agt_info) __attribute__((nonnull(2, 3)));
27 static char *_get_agent_keepalive(const char *agent_name, const char *agent_ip) __attribute__((nonnull(2)));
28 static int _get_agent_os(const char *agent_name, const char *agent_ip, agent_info *agt_info) __attribute__((nonnull(2, 3)));
31 /* Free the agent list in memory */
32 void free_agents(char **agent_list)
40 if (agent_list[i] == NULL) {
54 /* Print syscheck attributes */
55 #define sk_strchr(x,y,z) z = strchr(x, y); if(z == NULL) return(0); else { *z = '\0'; z++; }
57 static int _do_print_attrs_syscheck(const char *prev_attrs, const char *attrs, __attribute__((unused)) int csv_output,
58 cJSON *json_output, int is_win, int number_of_changes)
60 const char *p_size, *size;
61 char *p_perm, *p_uid, *p_gid, *p_md5, *p_sha1;
62 char *perm, *uid, *gid, *md5, *sha1;
66 /* A deleted file has no attributes */
67 if (strcmp(attrs, "-1") == 0) {
69 cJSON_AddStringToObject(json_output, "event", "deleted");
71 printf("File deleted.\n");
77 sk_strchr(size, ':', perm);
78 sk_strchr(perm, ':', uid);
79 sk_strchr(uid, ':', gid);
80 sk_strchr(gid, ':', md5);
81 sk_strchr(md5, ':', sha1);
90 if (prev_attrs && (strcmp(prev_attrs, "-1") == 0)) {
92 cJSON_AddStringToObject(json_output, "event", "restored");
94 printf("File restored. ");
95 } else if (prev_attrs) {
97 cJSON_AddStringToObject(json_output, "event", "modified");
99 printf("File changed. ");
102 sk_strchr(p_size, ':', p_perm);
103 sk_strchr(p_perm, ':', p_uid);
104 sk_strchr(p_uid, ':', p_gid);
105 sk_strchr(p_gid, ':', p_md5);
106 sk_strchr(p_md5, ':', p_sha1);
109 cJSON_AddStringToObject(json_output, "event", "added");
111 printf("File added to the database. ");
115 /* Fix number of changes */
116 if (prev_attrs && !number_of_changes) {
117 number_of_changes = 1;
120 if (number_of_changes) {
121 switch (number_of_changes) {
123 printf("- 1st time modified.\n");
126 printf("- 2nd time modified.\n");
129 printf("- 3rd time modified.\n");
132 printf("- Being ignored (3 or more changes).\n");
141 snprintf(perm_str, 35, "%9.9s", agent_file_perm(perm));
144 cJSON_AddStringToObject(json_output, "size", size);
146 //cJSON_AddNumberToObject(json_output, "mode", is_win ? 0 : perm_int);
147 cJSON_AddStringToObject(json_output, "perm", is_win ? "" : perm_str);
148 cJSON_AddStringToObject(json_output, "uid", is_win ? "" : uid);
149 cJSON_AddStringToObject(json_output, "gid", is_win ? "" : gid);
150 cJSON_AddStringToObject(json_output, "md5", md5);
151 cJSON_AddStringToObject(json_output, "sha1", sha1);
154 printf("Integrity checking values:\n");
155 printf(" Size:%s%s\n", (strcmp(size, p_size) == 0) ? " " : " >", size);
157 printf(" Perm:%s%s\n", (strcmp(perm, p_perm) == 0) ? " " : " >", perm_str);
158 printf(" Uid: %s%s\n", (strcmp(uid, p_uid) == 0) ? " " : " >", uid);
159 printf(" Gid: %s%s\n", (strcmp(gid, p_gid) == 0) ? " " : " >", gid);
161 printf(" Md5: %s%s\n", (strcmp(md5, p_md5) == 0) ? " " : " >", md5);
162 printf(" Sha1:%s%s\n", (strcmp(sha1, p_sha1) == 0) ? " " : " >", sha1);
175 /* Print information about a specific file */
176 static int _do_print_file_syscheck(FILE *fp, const char *fname, int update_counter,
177 int csv_output, cJSON *json_output)
181 char read_day[24 + 1];
182 char buf[OS_MAXSTR + 1];
184 OSStore *files_list = NULL;
186 cJSON *json_entry = NULL, *json_attrs = NULL;
188 buf[OS_MAXSTR] = '\0';
191 /* If the compilation failed, we don't need to free anything */
192 if (!OSMatch_Compile(fname, ®, 0)) {
193 if (!(csv_output || json_output))
194 printf("\n** ERROR: Invalid file name: '%s'\n", fname);
198 /* Create list with files */
199 files_list = OSStore_Create();
201 OSMatch_FreePattern(®);
205 /* Get initial position */
206 if (fgetpos(fp, &init_pos) != 0) {
207 if (!(csv_output || json_output))
208 printf("\n** ERROR: fgetpos failed.\n");
212 while (fgets(buf, OS_MAXSTR, fp) != NULL) {
213 if (buf[0] == '!' || buf[0] == '#' || buf[0] == '+') {
214 int number_changes = 0;
215 time_t change_time = 0;
216 char *changed_file_name;
220 if (strlen(buf) < 16) {
221 fgetpos(fp, &init_pos);
226 buf[strlen(buf) - 1] = '\0';
228 /* With update counter, we only modify the last entry */
229 if (update_counter && buf[0] == '#') {
230 fgetpos(fp, &init_pos);
234 /* Check the number of changes */
239 } else if (buf[2] == '?') {
244 changed_attrs = buf + 3;
246 changed_file_name = strchr(changed_attrs, '!');
247 if (!changed_file_name) {
248 fgetpos(fp, &init_pos);
252 /* Get time of change */
253 changed_file_name[-1] = '\0';
255 change_time = (time_t)atoi(changed_file_name);
257 changed_file_name = strchr(changed_file_name, ' ');
258 if (!changed_file_name) {
259 if (!(csv_output || json_output))
260 printf("\n** ERROR: Invalid line: '%s'.\n", buf);
265 /* Check if the name should be printed */
266 if (!OSMatch_Execute(changed_file_name, strlen(changed_file_name),
268 fgetpos(fp, &init_pos);
274 /* Reset the values */
275 if (update_counter) {
276 if (fsetpos(fp, &init_pos) != 0) {
277 if (!(csv_output || json_output))
278 printf("\n** ERROR: fsetpos failed (unable to update "
283 if (update_counter == 2) {
284 if (fprintf(fp, "!!?") <= 0) {
285 if (!(csv_output || json_output))
286 printf("\n** ERROR: fputs failed (unable to update "
293 if (fprintf(fp, "!++") <= 0) {
294 if (!(csv_output || json_output))
295 printf("\n** ERROR: fputs failed (unable to update "
301 if (!(csv_output || json_output))
302 printf("\n**Counter updated for file '%s'\n\n",
307 tm_time = localtime(&change_time);
308 strftime(read_day, 23, "%Y %h %d %T", tm_time);
311 json_entry = cJSON_CreateObject();
312 json_attrs = cJSON_CreateObject();
314 cJSON_AddStringToObject(json_entry, "readDay", read_day);
315 cJSON_AddStringToObject(json_entry, "file", changed_file_name);
316 cJSON_AddNumberToObject(json_entry, "changes", number_changes);
318 } else if (csv_output)
319 printf("%s,%s,%d\n", read_day, changed_file_name,
322 printf("\n%s,%d - %s\n", read_day, number_changes,
325 prev_attrs = (char *) OSStore_Get(files_list, changed_file_name);
329 os_strdup(changed_attrs, new_attrs);
330 _do_print_attrs_syscheck(prev_attrs, changed_attrs,
331 csv_output, json_attrs,
332 changed_file_name[0] == '/' ? 0 : 1,
335 free(files_list->cur_node->data);
336 files_list->cur_node->data = new_attrs;
340 os_strdup(changed_attrs, new_attrs);
341 OSStore_Put(files_list, changed_file_name, new_attrs);
342 _do_print_attrs_syscheck(NULL,
343 changed_attrs, csv_output, json_attrs,
344 changed_file_name[0] == '/' ? 0 : 1,
349 cJSON_AddItemToObject(json_entry, "attrs", json_attrs);
350 cJSON_AddItemToArray(json_output, json_entry);
353 fgetpos(fp, &init_pos);
358 printf("\n** No entries found.\n");
362 OSMatch_FreePattern(®);
364 OSStore_Free(files_list);
370 /* Print syscheck db (of modified files) */
371 static int _do_print_syscheck(FILE *fp, __attribute__((unused)) int all_files, int csv_output, cJSON *json_output)
376 char read_day[24 + 1];
377 char saved_read_day[24 + 1];
378 char buf[OS_MAXSTR + 1];
380 buf[OS_MAXSTR] = '\0';
382 saved_read_day[0] = '\0';
383 saved_read_day[24] = '\0';
385 while (fgets(buf, OS_MAXSTR, fp) != NULL) {
386 if (buf[0] == '!' || buf[0] == '#') {
387 int number_changes = 0;
388 time_t change_time = 0;
389 char *changed_file_name;
391 if (strlen(buf) < 16) {
396 buf[strlen(buf) - 1] = '\0';
398 /* Check the number of changes */
403 } else if (buf[2] == '?') {
408 changed_file_name = strchr(buf + 3, '!');
409 if (!changed_file_name) {
415 /* Get time of change */
417 change_time = atoi(changed_file_name);
419 changed_file_name = strchr(changed_file_name, ' ');
420 if (!changed_file_name) {
421 if (!(csv_output || json_output))
422 printf("\n** ERROR: Invalid line: '%s'.\n", buf);
427 tm_time = localtime(&change_time);
428 strftime(read_day, 23, "%Y %h %d", tm_time);
429 if (strcmp(read_day, saved_read_day) != 0) {
430 if (!(csv_output || json_output)) {
431 printf("\nChanges for %s:\n", read_day);
433 strncpy(saved_read_day, read_day, 23);
435 strftime(read_day, 23, "%Y %h %d %T", tm_time);
438 cJSON *entry = cJSON_CreateObject();
439 cJSON_AddStringToObject(entry, "readDay", read_day);
440 cJSON_AddStringToObject(entry, "file", changed_file_name);
441 cJSON_AddNumberToObject(entry, "changes", number_changes);
442 cJSON_AddItemToArray(json_output, entry);
443 } else if (csv_output)
444 printf("%s,%s,%d\n", read_day, changed_file_name,
447 printf("%s,%d - %s\n", read_day, number_changes,
452 if (!(f_found || csv_output || json_output)) {
453 printf("\n** No entries found.\n");
459 /* Print syscheck db (of modified files) */
460 int print_syscheck(const char *sk_name, const char *sk_ip, const char *fname,
461 int print_registry, int all_files, int csv_output,
462 cJSON *json_output, int update_counter)
467 tmp_file[512] = '\0';
469 if (sk_name == NULL) {
471 snprintf(tmp_file, 512, "%s/syscheck",
474 fp = fopen(tmp_file, "r+");
477 else if (sk_ip == NULL) {
479 snprintf(tmp_file, 512, "%s/%s->syscheck", SYSCHECK_DIR, sk_name);
481 fp = fopen(tmp_file, "r+");
484 else if (!print_registry) {
486 snprintf(tmp_file, 512, "%s/(%s) %s->syscheck",
491 fp = fopen(tmp_file, "r+");
495 /* Print database for the Windows registry */
496 snprintf(tmp_file, 512, "%s/(%s) %s->syscheck-registry",
501 fp = fopen(tmp_file, "r+");
506 _do_print_syscheck(fp, all_files, csv_output, json_output);
508 _do_print_file_syscheck(fp, fname, update_counter, csv_output, json_output);
516 static int _do_get_rootcheckscan(FILE *fp)
519 char buf[OS_MAXSTR + 1];
521 while (fgets(buf, OS_MAXSTR, fp) != NULL) {
522 tmp_str = strstr(buf, "Starting rootcheck scan");
527 s_time = (time_t)atoi(tmp_str);
529 return ((int)s_time);
533 return ((int)time(NULL));
536 /* Print syscheck db (of modified files) */
537 static int _do_print_rootcheck(FILE *fp, int resolved, time_t time_last_scan,
538 int csv_output, cJSON *json_output, int show_last)
543 /* Time from the message */
548 char old_day[24 + 1];
549 char read_day[24 + 1];
550 char buf[OS_MAXSTR + 1];
553 const char *(ig_events[]) = {"Starting rootcheck scan",
554 "Ending rootcheck scan",
555 "Starting syscheck scan",
556 "Ending syscheck scan",
560 const char *(ns_events[]) = {"Application Found:",
566 buf[OS_MAXSTR] = '\0';
570 fseek(fp, 0, SEEK_SET);
572 if (!(csv_output || json_output)) {
574 tm_time = localtime(&time_last_scan);
575 strftime(read_day, 23, "%Y %h %d %T", tm_time);
577 printf("\nLast scan: %s\n\n", read_day);
578 } else if (resolved) {
579 printf("\nResolved events: \n\n");
581 printf("\nOutstanding events: \n\n");
585 while (fgets(buf, OS_MAXSTR, fp) != NULL) {
588 s_time = (time_t)atoi(tmp_str);
591 tmp_str = strchr(buf, '\n');
596 /* Get initial time */
597 tmp_str = strchr(buf + 1, '!');
603 i_time = (time_t)atoi(tmp_str);
605 /* Get the actual message */
606 tmp_str = strchr(tmp_str, ' ');
612 /* Check for resolved */
613 if (time_last_scan > (s_time + 86400)) {
623 /* Check events to ignore */
625 while (ig_events[i]) {
626 if (strncmp(tmp_str, ig_events[i], strlen(ig_events[i]) - 1) == 0) {
635 /* Check events that are not system audit */
637 while (ns_events[i]) {
638 if (strncmp(tmp_str, ns_events[i], strlen(ns_events[i]) - 1) == 0) {
644 tm_time = localtime((time_t *)&s_time);
645 strftime(read_day, 23, "%Y %h %d %T", tm_time);
646 tm_time = localtime((time_t *)&i_time);
647 strftime(old_day, 23, "%Y %h %d %T", tm_time);
650 cJSON *event = cJSON_CreateObject();
651 cJSON_AddStringToObject(event, "status", resolved == 0 ? "outstanding" : "resolved");
652 cJSON_AddStringToObject(event, "readDay", read_day);
653 cJSON_AddStringToObject(event, "oldDay", old_day);
656 cJSON_AddStringToObject(event, "event", tmp_str);
658 char json_buffer[OS_MAXSTR + 1];
659 snprintf(json_buffer, OS_MAXSTR, "%s%s", ns_events[i], tmp_str);
660 cJSON_AddStringToObject(event, "event", json_buffer);
663 cJSON_AddItemToArray(json_output, event);
664 } else if (csv_output) {
665 printf("%s,%s,%s,%s%s\n", resolved == 0 ? "outstanding" : "resolved",
667 ns_events[i] != NULL ? "" : "System Audit: ",
671 printf("%s (first time detected: %s)\n", read_day, old_day);
675 printf("%s\n\n", tmp_str);
677 printf("System Audit: %s\n\n", tmp_str);
684 if (!f_found && !(csv_output || json_output)) {
685 printf("** No entries found.\n");
691 /* Print rootcheck db */
692 int print_rootcheck(const char *sk_name, const char *sk_ip, const char *fname,
693 int resolved, int csv_output, cJSON *json_output, int show_last)
699 tmp_file[512] = '\0';
701 if (sk_name == NULL) {
703 snprintf(tmp_file, 512, "%s/rootcheck",
706 fp = fopen(tmp_file, "r+");
709 snprintf(tmp_file, 512, "%s/(%s) %s->rootcheck",
714 fp = fopen(tmp_file, "r+");
718 /* Get last time of scan */
719 ltime = _do_get_rootcheckscan(fp);
722 _do_print_rootcheck(fp, 1, ltime, csv_output, json_output, 0);
723 } else if (resolved == 2) {
724 _do_print_rootcheck(fp, 0, ltime, csv_output, json_output, show_last);
726 _do_print_rootcheck(fp, 1, ltime, csv_output, json_output, 0);
727 _do_print_rootcheck(fp, 0, ltime, csv_output, json_output, show_last);
739 /* Delete syscheck db */
740 int delete_syscheck(const char *sk_name, const char *sk_ip, int full_delete)
745 tmp_file[512] = '\0';
747 /* Delete related files */
748 snprintf(tmp_file, 512, "%s/(%s) %s->syscheck",
753 fp = fopen(tmp_file, "w");
762 /* Delete cpt files */
763 snprintf(tmp_file, 512, "%s/.(%s) %s->syscheck.cpt",
768 fp = fopen(tmp_file, "w");
774 /* Delete registry entries */
775 snprintf(tmp_file, 512, "%s/(%s) %s->syscheck-registry",
780 fp = fopen(tmp_file, "w");
788 /* Delete cpt files */
789 snprintf(tmp_file, 512, "%s/.(%s) %s->syscheck-registry.cpt",
794 fp = fopen(tmp_file, "w");
803 /* Delete rootcheck db */
804 int delete_rootcheck(const char *sk_name, const char *sk_ip, int full_delete)
809 tmp_file[512] = '\0';
811 /* Delete related files */
812 snprintf(tmp_file, 512, "%s/(%s) %s->rootcheck",
817 fp = fopen(tmp_file, "w");
830 int delete_agentinfo(const char *name)
836 tmp_file[512] = '\0';
838 /* Delete agent info */
839 snprintf(tmp_file, 512, "%s/%s", AGENTINFO_DIR, name);
842 /* Delete syscheck */
844 sk_ip = strrchr(name, '-');
852 /* Delete syscheck */
853 delete_syscheck(sk_name, sk_ip, 1);
855 /* Delete rootcheck */
856 delete_rootcheck(sk_name, sk_ip, 1);
861 /* Print the text representation of the agent status */
862 const char *print_agent_status(int status)
864 const char *status_str = "Never connected";
866 if (status == GA_STATUS_ACTIVE) {
867 status_str = "Active";
868 } else if (status == GA_STATUS_NACTIVE) {
869 status_str = "Disconnected";
876 /* Non-windows functions from now on */
878 /* Send a message to an agent
879 * Returns -1 on error
881 int send_msg_to_agent(int msocket, const char *msg, const char *agt_id, const char *exec)
884 char agt_msg[OS_SIZE_1024 + 1];
886 agt_msg[OS_SIZE_1024] = '\0';
889 snprintf(agt_msg, OS_SIZE_1024,
892 (agt_id == NULL) ? ALL_AGENTS_C : NONE_C,
894 (agt_id != NULL) ? SPECIFIC_AGENT_C : NONE_C,
895 agt_id != NULL ? agt_id : "(null)",
898 snprintf(agt_msg, OS_SIZE_1024,
899 "%s %c%c%c %s %s - %s (from_the_server) (no_rule_id)",
901 (agt_id == NULL) ? ALL_AGENTS_C : NONE_C,
903 (agt_id != NULL) ? SPECIFIC_AGENT_C : NONE_C,
904 agt_id != NULL ? agt_id : "(null)",
909 if ((rc = OS_SendUnix(msocket, agt_msg, 0)) < 0) {
910 if (rc == OS_SOCKBUSY) {
911 merror("%s: ERROR: Remoted socket busy.", __local_name);
913 merror("%s: ERROR: Remoted socket error.", __local_name);
915 merror("%s: Error communicating with remoted queue (%d).",
924 /* Connect to remoted to be able to send messages to the agents
925 * Returns the socket on success or -1 on failure
927 int connect_to_remoted()
931 if ((arq = StartMQ(ARQUEUE, WRITE)) < 0) {
932 merror(ARQ_ERROR, __local_name);
939 const char *agent_file_perm(char *perm)
941 /* rwxrwxrwx0 -> 10 */
942 static char permissions[10];
945 /* octal or decimal */
946 mode = (mode_t) strtoul(perm, 0, strlen(perm) == 3 ? 8 : 10);
948 permissions[0] = (mode & S_IRUSR) ? 'r' : '-';
949 permissions[1] = (mode & S_IWUSR) ? 'w' : '-';
950 permissions[2] = (mode & S_ISUID) ? 's' : (mode & S_IXUSR) ? 'x' : '-';
951 permissions[3] = (mode & S_IRGRP) ? 'r' : '-';
952 permissions[4] = (mode & S_IWGRP) ? 'w' : '-';
953 permissions[5] = (mode & S_ISGID) ? 's' : (mode & S_IXGRP) ? 'x' : '-';
954 permissions[6] = (mode & S_IROTH) ? 'r' : '-';
955 permissions[7] = (mode & S_IWOTH) ? 'w' : '-';
956 permissions[8] = (mode & S_ISVTX) ? 't' : (mode & S_IXOTH) ? 'x' : '-';
957 permissions[9] = '\0';
959 return &permissions[0];
964 /* Internal function. Extract last time of scan from rootcheck/syscheck. */
965 static int _get_time_rkscan(const char *agent_name, const char *agent_ip, agent_info *agt_info)
970 /* Agent name of null, means it is the server info */
971 if (agent_name == NULL) {
972 snprintf(buf, 1024, "%s/rootcheck",
975 snprintf(buf, 1024, "%s/(%s) %s->rootcheck",
976 ROOTCHECK_DIR, agent_name, agent_ip);
979 /* If file is not there, set to unknown */
980 fp = fopen(buf, "r");
982 os_strdup("Unknown", agt_info->rootcheck_time);
983 os_strdup("Unknown", agt_info->rootcheck_endtime);
984 os_strdup("Unknown", agt_info->syscheck_time);
985 os_strdup("Unknown", agt_info->syscheck_endtime);
989 while (fgets(buf, 1024, fp) != NULL) {
990 char *tmp_str = NULL;
993 tmp_str = strchr(buf, '\n');
998 tmp_str = strstr(buf, "Starting syscheck scan");
1003 s_time = (time_t)atoi(tmp_str);
1004 os_strdup(ctime(&s_time), agt_info->syscheck_time);
1006 /* Remove newline */
1007 tmp_str = strchr(agt_info->syscheck_time, '\n');
1015 tmp_str = strstr(buf, "Ending syscheck scan");
1020 s_time = (time_t)atoi(tmp_str);
1022 os_strdup(ctime(&s_time), agt_info->syscheck_endtime);
1024 /* Remove newline */
1025 tmp_str = strchr(agt_info->syscheck_endtime, '\n');
1033 tmp_str = strstr(buf, "Starting rootcheck scan");
1038 s_time = (time_t)atoi(tmp_str);
1040 os_strdup(ctime(&s_time), agt_info->rootcheck_time);
1042 /* Remove newline */
1043 tmp_str = strchr(agt_info->rootcheck_time, '\n');
1051 tmp_str = strstr(buf, "Ending rootcheck scan");
1055 s_time = (time_t)atoi(tmp_str);
1056 os_strdup(ctime(&s_time), agt_info->rootcheck_endtime);
1058 /* Remove newline */
1059 tmp_str = strchr(agt_info->rootcheck_endtime, '\n');
1068 /* Set unknown values */
1069 if (!agt_info->rootcheck_time) {
1070 os_strdup("Unknown", agt_info->rootcheck_time);
1072 if (!agt_info->rootcheck_endtime) {
1073 os_strdup("Unknown", agt_info->rootcheck_endtime);
1075 if (!agt_info->syscheck_time) {
1076 os_strdup("Unknown", agt_info->syscheck_time);
1078 if (!agt_info->syscheck_endtime) {
1079 os_strdup("Unknown", agt_info->syscheck_endtime);
1086 /* Internal function. Extract last time of scan from rootcheck/syscheck. */
1087 static char *_get_agent_keepalive(const char *agent_name, const char *agent_ip)
1090 struct stat file_status;
1092 /* No keepalive for the server */
1094 return (strdup("Not available"));
1097 snprintf(buf, 1024, "%s/%s-%s", AGENTINFO_DIR, agent_name, agent_ip);
1098 if (stat(buf, &file_status) < 0) {
1099 return (strdup("Unknown"));
1102 return (strdup(ctime(&file_status.st_mtime)));
1105 /* Internal function. Extract operating system. */
1106 static int _get_agent_os(const char *agent_name, const char *agent_ip, agent_info *agt_info)
1111 /* Get server info */
1113 char *ossec_version = NULL;
1114 agt_info->os = getuname();
1115 os_strdup(__ossec_name " " __version, agt_info->version);
1117 /* Remove newline */
1118 ossec_version = strchr(agt_info->os, '\n');
1119 if (ossec_version) {
1120 *ossec_version = '\0';
1123 ossec_version = strstr(agt_info->os, " - ");
1124 if (ossec_version) {
1125 *ossec_version = '\0';
1131 snprintf(buf, 1024, "%s/%s-%s", AGENTINFO_DIR, agent_name, agent_ip);
1132 fp = fopen(buf, "r");
1134 os_strdup("Unknown", agt_info->os);
1135 os_strdup("Unknown", agt_info->version);
1139 if (fgets(buf, 1024, fp)) {
1140 char *ossec_version = NULL;
1142 /* Remove newline */
1143 ossec_version = strchr(buf, '\n');
1144 if (ossec_version) {
1145 *ossec_version = '\0';
1148 ossec_version = strstr(buf, " - ");
1149 if (ossec_version) {
1150 *ossec_version = '\0';
1153 os_calloc(1024 + 1, sizeof(char), agt_info->version);
1154 strncpy(agt_info->version, ossec_version, 1024);
1157 os_strdup(buf, agt_info->os);
1165 os_strdup("Unknown", agt_info->os);
1166 os_strdup("Unknown", agt_info->version);
1171 /* Get information from an agent */
1172 agent_info *get_agent_info(const char *agent_name, const char *agent_ip)
1174 char *agent_ip_pt = NULL;
1175 char *tmp_str = NULL;
1177 agent_info *agt_info = NULL;
1179 /* Remove the "/", since it is not present on the file */
1180 if ((agent_ip_pt = strchr(agent_ip, '/'))) {
1181 *agent_ip_pt = '\0';
1184 /* Allocate memory for the info structure */
1185 os_calloc(1, sizeof(agent_info), agt_info);
1187 /* Zero the values */
1188 agt_info->rootcheck_time = NULL;
1189 agt_info->rootcheck_endtime = NULL;
1190 agt_info->syscheck_time = NULL;
1191 agt_info->syscheck_endtime = NULL;
1192 agt_info->os = NULL;
1193 agt_info->version = NULL;
1194 agt_info->last_keepalive = NULL;
1196 /* Get information about the OS */
1197 _get_agent_os(agent_name, agent_ip, agt_info);
1198 _get_time_rkscan(agent_name, agent_ip, agt_info);
1199 agt_info->last_keepalive = _get_agent_keepalive(agent_name, agent_ip);
1201 /* Remove newline from keepalive */
1202 tmp_str = strchr(agt_info->last_keepalive, '\n');
1207 /* Set back the IP address */
1215 /* Gets the status of an agent, based on the name / IP address */
1216 int get_agent_status(const char *agent_name, const char *agent_ip)
1219 char *agent_ip_pt = NULL;
1220 struct stat file_status;
1222 tmp_file[512] = '\0';
1225 if (agent_name == NULL) {
1226 return (GA_STATUS_ACTIVE);
1229 /* Remove the "/", since it is not present on the file */
1230 if ((agent_ip_pt = strchr(agent_ip, '/'))) {
1231 *agent_ip_pt = '\0';
1234 snprintf(tmp_file, 512, "%s/%s-%s", AGENTINFO_DIR, agent_name, agent_ip);
1236 /* Set back the IP address */
1241 if (stat(tmp_file, &file_status) < 0) {
1242 return (GA_STATUS_INV);
1245 if (file_status.st_mtime > (time(0) - (3 * NOTIFY_TIME + 30))) {
1246 return (GA_STATUS_ACTIVE);
1249 return (GA_STATUS_NACTIVE);
1252 /* List available agents with specified timeout */
1253 char **get_agents_with_timeout(int flag, int timeout)
1256 char **f_files = NULL;
1258 struct dirent *entry;
1260 /* Open the directory */
1261 dp = opendir(AGENTINFO_DIR);
1263 merror("%s: Error opening directory: '%s': %s ",
1270 /* Read directory */
1271 while ((entry = readdir(dp)) != NULL) {
1274 tmp_file[512] = '\0';
1276 /* Ignore . and .. */
1277 if ((strcmp(entry->d_name, ".") == 0) ||
1278 (strcmp(entry->d_name, "..") == 0)) {
1282 snprintf(tmp_file, 512, "%s/%s", AGENTINFO_DIR, entry->d_name);
1284 if (flag != GA_ALL) {
1285 struct stat file_status;
1287 if (stat(tmp_file, &file_status) < 0) {
1291 if (file_status.st_mtime > (time(0) - (3 * timeout + 30))) {
1293 if (flag == GA_NOTACTIVE) {
1297 if (flag == GA_ACTIVE) {
1303 f_files = (char **)realloc(f_files, (f_size + 2) * sizeof(char *));
1305 ErrorExit(MEM_ERROR, __local_name, errno, strerror(errno));
1308 /* Add agent entry */
1309 if (flag == GA_ALL_WSTATUS) {
1312 snprintf(agt_stat, sizeof(agt_stat) - 1, "%s %s",
1313 entry->d_name, status == 1 ? "active" : "disconnected");
1315 os_strdup(agt_stat, f_files[f_size]);
1317 os_strdup(entry->d_name, f_files[f_size]);
1320 f_files[f_size + 1] = NULL;
1329 /* List available agents */
1330 char **get_agents(int flag) {
1331 return get_agents_with_timeout(flag, NOTIFY_TIME);