new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / shared / read-agents.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All right reserved.
3  *
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
7  * Foundation
8  */
9
10 #include "shared.h"
11 #include "read-agents.h"
12 #include "os_net/os_net.h"
13
14 #ifndef WIN32
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)));
23
24 #endif /* !WIN32*/
25
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)));
29
30
31 /* Free the agent list in memory */
32 void free_agents(char **agent_list)
33 {
34     int i;
35     if (!agent_list) {
36         return;
37     }
38
39     for (i = 0;; i++) {
40         if (agent_list[i] == NULL) {
41             break;
42         }
43
44         free(agent_list[i]);
45         agent_list[i] = NULL;
46     }
47
48     free(agent_list);
49     agent_list = NULL;
50 }
51
52 #ifndef WIN32
53
54 /* Print syscheck attributes */
55 #define sk_strchr(x,y,z) z = strchr(x, y); if(z == NULL) return(0); else { *z = '\0'; z++; }
56
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)
59 {
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;
63     char perm_str[36];
64
65
66     /* A deleted file has no attributes */
67     if (strcmp(attrs, "-1") == 0) {
68         if (json_output)
69             cJSON_AddStringToObject(json_output, "event", "deleted");
70         else
71             printf("File deleted.\n");
72         return (0);
73     }
74
75     /* Set each value */
76     size = attrs;
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);
82
83     p_size = size;
84     p_perm = perm;
85     p_uid = uid;
86     p_gid = gid;
87     p_md5 = md5;
88     p_sha1 = sha1;
89
90     if (prev_attrs && (strcmp(prev_attrs, "-1") == 0)) {
91         if (json_output)
92             cJSON_AddStringToObject(json_output, "event", "restored");
93         else
94             printf("File restored. ");
95     } else if (prev_attrs) {
96         if (json_output)
97             cJSON_AddStringToObject(json_output, "event", "modified");
98         else
99             printf("File changed. ");
100
101         p_size = prev_attrs;
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);
107     } else {
108         if (json_output)
109             cJSON_AddStringToObject(json_output, "event", "added");
110         else
111             printf("File added to the database. ");
112     }
113
114     if (!json_output) {
115         /* Fix number of changes */
116         if (prev_attrs && !number_of_changes) {
117             number_of_changes = 1;
118         }
119
120         if (number_of_changes) {
121             switch (number_of_changes) {
122                 case 1:
123                     printf("- 1st time modified.\n");
124                     break;
125                 case 2:
126                     printf("- 2nd time modified.\n");
127                     break;
128                 case 3:
129                     printf("- 3rd time modified.\n");
130                     break;
131                 default:
132                     printf("- Being ignored (3 or more changes).\n");
133                     break;
134             }
135         } else {
136             printf("\n");
137         }
138     }
139
140     perm_str[35] = '\0';
141     snprintf(perm_str, 35, "%9.9s", agent_file_perm(perm));
142
143     if (json_output) {
144         cJSON_AddStringToObject(json_output, "size", size);
145         // Legacy
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);
152
153     } else{
154         printf("Integrity checking values:\n");
155         printf("   Size:%s%s\n", (strcmp(size, p_size) == 0) ? " " : " >", size);
156         if (!is_win) {
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);
160         }
161         printf("   Md5: %s%s\n", (strcmp(md5, p_md5) == 0) ? " " : " >", md5);
162         printf("   Sha1:%s%s\n", (strcmp(sha1, p_sha1) == 0) ? " " : " >", sha1);
163     }
164
165     /* Fix entries */
166     perm[-1] = ':';
167     uid[-1] = ':';
168     gid[-1] = ':';
169     md5[-1] = ':';
170     sha1[-1] = ':';
171
172     return (0);
173 }
174
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)
178 {
179     int f_found = 0;
180     struct tm *tm_time;
181     char read_day[24 + 1];
182     char buf[OS_MAXSTR + 1];
183     OSMatch reg;
184     OSStore *files_list = NULL;
185     fpos_t init_pos;
186     cJSON *json_entry = NULL, *json_attrs = NULL;
187
188     buf[OS_MAXSTR] = '\0';
189     read_day[24] = '\0';
190
191     /* If the compilation failed, we don't need to free anything */
192     if (!OSMatch_Compile(fname, &reg, 0)) {
193         if (!(csv_output || json_output))
194             printf("\n** ERROR: Invalid file name: '%s'\n", fname);
195         return (0);
196     }
197
198     /* Create list with files */
199     files_list = OSStore_Create();
200     if (!files_list) {
201         OSMatch_FreePattern(&reg);
202         goto cleanup;
203     }
204
205     /* Get initial position */
206     if (fgetpos(fp, &init_pos) != 0) {
207         if (!(csv_output || json_output))
208             printf("\n** ERROR: fgetpos failed.\n");
209         goto cleanup;
210     }
211
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;
217             char *changed_attrs;
218             char *prev_attrs;
219
220             if (strlen(buf) < 16) {
221                 fgetpos(fp, &init_pos);
222                 continue;
223             }
224
225             /* Remove newline */
226             buf[strlen(buf) - 1] = '\0';
227
228             /* With update counter, we only modify the last entry */
229             if (update_counter && buf[0] == '#') {
230                 fgetpos(fp, &init_pos);
231                 continue;
232             }
233
234             /* Check the number of changes */
235             if (buf[1] == '!') {
236                 number_changes = 2;
237                 if (buf[2] == '!') {
238                     number_changes = 3;
239                 } else if (buf[2] == '?') {
240                     number_changes = 4;
241                 }
242             }
243
244             changed_attrs = buf + 3;
245
246             changed_file_name = strchr(changed_attrs, '!');
247             if (!changed_file_name) {
248                 fgetpos(fp, &init_pos);
249                 continue;
250             }
251
252             /* Get time of change */
253             changed_file_name[-1] = '\0';
254             changed_file_name++;
255             change_time = (time_t)atoi(changed_file_name);
256
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);
261                 goto cleanup;
262             }
263             changed_file_name++;
264
265             /* Check if the name should be printed */
266             if (!OSMatch_Execute(changed_file_name, strlen(changed_file_name),
267                                  &reg)) {
268                 fgetpos(fp, &init_pos);
269                 continue;
270             }
271
272             f_found = 1;
273
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 "
279                                "counter).\n");
280                     goto cleanup;
281                 }
282
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 "
287                                    "counter).\n");
288                         goto cleanup;
289                     }
290                 }
291
292                 else {
293                     if (fprintf(fp, "!++") <= 0) {
294                         if (!(csv_output || json_output))
295                             printf("\n** ERROR: fputs failed (unable to update "
296                                    "counter).\n");
297                         goto cleanup;
298                     }
299                 }
300
301                 if (!(csv_output || json_output))
302                     printf("\n**Counter updated for file '%s'\n\n",
303                            changed_file_name);
304                 goto cleanup;
305             }
306
307             tm_time = localtime(&change_time);
308             strftime(read_day, 23, "%Y %h %d %T", tm_time);
309
310             if (json_output) {
311                 json_entry = cJSON_CreateObject();
312                 json_attrs = cJSON_CreateObject();
313
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);
317
318             } else if (csv_output)
319                 printf("%s,%s,%d\n", read_day, changed_file_name,
320                        number_changes);
321             else
322                 printf("\n%s,%d - %s\n", read_day, number_changes,
323                        changed_file_name);
324
325             prev_attrs = (char *) OSStore_Get(files_list, changed_file_name);
326
327             if (prev_attrs) {
328                 char *new_attrs;
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,
333                                          number_changes);
334
335                 free(files_list->cur_node->data);
336                 files_list->cur_node->data = new_attrs;
337             } else {
338                 char *new_attrs;
339
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,
345                                          number_changes);
346             }
347
348             if (json_output) {
349                 cJSON_AddItemToObject(json_entry, "attrs", json_attrs);
350                 cJSON_AddItemToArray(json_output, json_entry);
351             }
352
353             fgetpos(fp, &init_pos);
354         }
355     }
356
357     if (!f_found) {
358         printf("\n** No entries found.\n");
359     }
360
361 cleanup:
362     OSMatch_FreePattern(&reg);
363     if (files_list) {
364         OSStore_Free(files_list);
365     }
366
367     return (0);
368 }
369
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)
372 {
373     int f_found = 0;
374     struct tm *tm_time;
375
376     char read_day[24 + 1];
377     char saved_read_day[24 + 1];
378     char buf[OS_MAXSTR + 1];
379
380     buf[OS_MAXSTR] = '\0';
381     read_day[24] = '\0';
382     saved_read_day[0] = '\0';
383     saved_read_day[24] = '\0';
384
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;
390
391             if (strlen(buf) < 16) {
392                 continue;
393             }
394
395             /* Remove newline */
396             buf[strlen(buf) - 1] = '\0';
397
398             /* Check the number of changes */
399             if (buf[1] == '!') {
400                 number_changes = 2;
401                 if (buf[2] == '!') {
402                     number_changes = 3;
403                 } else if (buf[2] == '?') {
404                     number_changes = 4;
405                 }
406             }
407
408             changed_file_name = strchr(buf + 3, '!');
409             if (!changed_file_name) {
410                 continue;
411             }
412
413             f_found = 1;
414
415             /* Get time of change */
416             changed_file_name++;
417             change_time = atoi(changed_file_name);
418
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);
423                 return (-1);
424             }
425             changed_file_name++;
426
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);
432                 }
433                 strncpy(saved_read_day, read_day, 23);
434             }
435             strftime(read_day, 23, "%Y %h %d %T", tm_time);
436
437             if (json_output) {
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,
445                        number_changes);
446             else
447                 printf("%s,%d - %s\n", read_day, number_changes,
448                        changed_file_name);
449         }
450     }
451
452     if (!(f_found || csv_output || json_output)) {
453         printf("\n** No entries found.\n");
454     }
455
456     return (0);
457 }
458
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)
463 {
464     FILE *fp;
465     char tmp_file[513];
466
467     tmp_file[512] = '\0';
468
469     if (sk_name == NULL) {
470         /* Print database */
471         snprintf(tmp_file, 512, "%s/syscheck",
472                  SYSCHECK_DIR);
473
474         fp = fopen(tmp_file, "r+");
475     }
476
477     else if (sk_ip == NULL) {
478         /* Print database */
479         snprintf(tmp_file, 512, "%s/%s->syscheck", SYSCHECK_DIR, sk_name);
480
481         fp = fopen(tmp_file, "r+");
482     }
483
484     else if (!print_registry) {
485         /* Print database */
486         snprintf(tmp_file, 512, "%s/(%s) %s->syscheck",
487                  SYSCHECK_DIR,
488                  sk_name,
489                  sk_ip);
490
491         fp = fopen(tmp_file, "r+");
492     }
493
494     else {
495         /* Print database for the Windows registry */
496         snprintf(tmp_file, 512, "%s/(%s) %s->syscheck-registry",
497                  SYSCHECK_DIR,
498                  sk_name,
499                  sk_ip);
500
501         fp = fopen(tmp_file, "r+");
502     }
503
504     if (fp) {
505         if (!fname) {
506             _do_print_syscheck(fp, all_files, csv_output, json_output);
507         } else {
508             _do_print_file_syscheck(fp, fname, update_counter, csv_output, json_output);
509         }
510         fclose(fp);
511     }
512
513     return (0);
514 }
515
516 static int _do_get_rootcheckscan(FILE *fp)
517 {
518     char *tmp_str;
519     char buf[OS_MAXSTR + 1];
520
521     while (fgets(buf, OS_MAXSTR, fp) != NULL) {
522         tmp_str = strstr(buf, "Starting rootcheck scan");
523         if (tmp_str) {
524             time_t s_time = 0;
525             tmp_str = buf + 1;
526
527             s_time = (time_t)atoi(tmp_str);
528
529             return ((int)s_time);
530         }
531     }
532
533     return ((int)time(NULL));
534 }
535
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)
539 {
540     int i = 0;
541     int f_found = 0;
542
543     /* Time from the message */
544     time_t s_time = 0;
545     time_t i_time = 0;
546     struct tm *tm_time;
547
548     char old_day[24 + 1];
549     char read_day[24 + 1];
550     char buf[OS_MAXSTR + 1];
551     char *tmp_str;
552
553     const char *(ig_events[]) = {"Starting rootcheck scan",
554                                  "Ending rootcheck scan",
555                                  "Starting syscheck scan",
556                                  "Ending syscheck scan",
557                                  NULL
558                                 };
559
560     const char *(ns_events[]) = {"Application Found:",
561                                  "Windows Audit:",
562                                  "Windows Malware:",
563                                  NULL
564                                 };
565
566     buf[OS_MAXSTR] = '\0';
567     old_day[24] = '\0';
568     read_day[24] = '\0';
569
570     fseek(fp, 0, SEEK_SET);
571
572     if (!(csv_output || json_output)) {
573         if (show_last) {
574             tm_time = localtime(&time_last_scan);
575             strftime(read_day, 23, "%Y %h %d %T", tm_time);
576
577             printf("\nLast scan: %s\n\n", read_day);
578         } else if (resolved) {
579             printf("\nResolved events: \n\n");
580         } else {
581             printf("\nOutstanding events: \n\n");
582         }
583     }
584
585     while (fgets(buf, OS_MAXSTR, fp) != NULL) {
586         /* Remove first ! */
587         tmp_str = buf + 1;
588         s_time = (time_t)atoi(tmp_str);
589
590         /* Remove newline */
591         tmp_str = strchr(buf, '\n');
592         if (tmp_str) {
593             *tmp_str = '\0';
594         }
595
596         /* Get initial time */
597         tmp_str = strchr(buf + 1, '!');
598         if (!tmp_str) {
599             continue;
600         }
601         tmp_str++;
602
603         i_time = (time_t)atoi(tmp_str);
604
605         /* Get the actual message */
606         tmp_str = strchr(tmp_str, ' ');
607         if (!tmp_str) {
608             continue;
609         }
610         tmp_str++;
611
612         /* Check for resolved */
613         if (time_last_scan > (s_time + 86400)) {
614             if (!resolved) {
615                 continue;
616             }
617         } else {
618             if (resolved) {
619                 continue;
620             }
621         }
622
623         /* Check events to ignore */
624         i = 0;
625         while (ig_events[i]) {
626             if (strncmp(tmp_str, ig_events[i], strlen(ig_events[i]) - 1) == 0) {
627                 break;
628             }
629             i++;
630         }
631         if (ig_events[i]) {
632             continue;
633         }
634
635         /* Check events that are not system audit */
636         i = 0;
637         while (ns_events[i]) {
638             if (strncmp(tmp_str, ns_events[i], strlen(ns_events[i]) - 1) == 0) {
639                 break;
640             }
641             i++;
642         }
643
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);
648
649         if (json_output) {
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);
654
655             if (ns_events[i])
656                 cJSON_AddStringToObject(event, "event", tmp_str);
657             else {
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);
661             }
662
663             cJSON_AddItemToArray(json_output, event);
664         } else if (csv_output) {
665             printf("%s,%s,%s,%s%s\n", resolved == 0 ? "outstanding" : "resolved",
666                    read_day, old_day,
667                   ns_events[i] != NULL ? "" : "System Audit: ",
668                    tmp_str);
669         } else {
670             if (!show_last) {
671                 printf("%s (first time detected: %s)\n", read_day, old_day);
672             }
673
674             if (ns_events[i]) {
675                 printf("%s\n\n", tmp_str);
676             } else {
677                 printf("System Audit: %s\n\n", tmp_str);
678             }
679         }
680
681         f_found++;
682     }
683
684     if (!f_found && !(csv_output || json_output)) {
685         printf("** No entries found.\n");
686     }
687
688     return (0);
689 }
690
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)
694 {
695     int ltime = 0;
696     FILE *fp;
697     char tmp_file[513];
698
699     tmp_file[512] = '\0';
700
701     if (sk_name == NULL) {
702         /* Print database */
703         snprintf(tmp_file, 512, "%s/rootcheck",
704                  ROOTCHECK_DIR);
705
706         fp = fopen(tmp_file, "r+");
707     } else {
708         /* Print database */
709         snprintf(tmp_file, 512, "%s/(%s) %s->rootcheck",
710                  ROOTCHECK_DIR,
711                  sk_name,
712                  sk_ip);
713
714         fp = fopen(tmp_file, "r+");
715     }
716
717     if (fp) {
718         /* Get last time of scan */
719         ltime = _do_get_rootcheckscan(fp);
720         if (!fname) {
721             if (resolved == 1) {
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);
725             } else {
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);
728
729             }
730         }
731         fclose(fp);
732     }
733
734     return (0);
735 }
736
737 #endif
738
739 /* Delete syscheck db */
740 int delete_syscheck(const char *sk_name, const char *sk_ip, int full_delete)
741 {
742     FILE *fp;
743     char tmp_file[513];
744
745     tmp_file[512] = '\0';
746
747     /* Delete related files */
748     snprintf(tmp_file, 512, "%s/(%s) %s->syscheck",
749              SYSCHECK_DIR,
750              sk_name,
751              sk_ip);
752
753     fp = fopen(tmp_file, "w");
754     if (fp) {
755         fclose(fp);
756     }
757
758     if (full_delete) {
759         unlink(tmp_file);
760     }
761
762     /* Delete cpt files */
763     snprintf(tmp_file, 512, "%s/.(%s) %s->syscheck.cpt",
764              SYSCHECK_DIR,
765              sk_name,
766              sk_ip);
767
768     fp = fopen(tmp_file, "w");
769     if (fp) {
770         fclose(fp);
771     }
772     unlink(tmp_file);
773
774     /* Delete registry entries */
775     snprintf(tmp_file, 512, "%s/(%s) %s->syscheck-registry",
776              SYSCHECK_DIR,
777              sk_name,
778              sk_ip);
779
780     fp = fopen(tmp_file, "w");
781     if (fp) {
782         fclose(fp);
783     }
784     if (full_delete) {
785         unlink(tmp_file);
786     }
787
788     /* Delete cpt files */
789     snprintf(tmp_file, 512, "%s/.(%s) %s->syscheck-registry.cpt",
790              SYSCHECK_DIR,
791              sk_name,
792              sk_ip);
793
794     fp = fopen(tmp_file, "w");
795     if (fp) {
796         fclose(fp);
797     }
798     unlink(tmp_file);
799
800     return (1);
801 }
802
803 /* Delete rootcheck db */
804 int delete_rootcheck(const char *sk_name, const char *sk_ip, int full_delete)
805 {
806     FILE *fp;
807     char tmp_file[513];
808
809     tmp_file[512] = '\0';
810
811     /* Delete related files */
812     snprintf(tmp_file, 512, "%s/(%s) %s->rootcheck",
813              ROOTCHECK_DIR,
814              sk_name,
815              sk_ip);
816
817     fp = fopen(tmp_file, "w");
818     if (fp) {
819         fclose(fp);
820     }
821
822     if (full_delete) {
823         unlink(tmp_file);
824     }
825
826     return (1);
827 }
828
829 /* Delete agent */
830 int delete_agentinfo(const char *name)
831 {
832     const char *sk_name;
833     char *sk_ip;
834     char tmp_file[513];
835
836     tmp_file[512] = '\0';
837
838     /* Delete agent info */
839     snprintf(tmp_file, 512, "%s/%s", AGENTINFO_DIR, name);
840     unlink(tmp_file);
841
842     /* Delete syscheck */
843     sk_name = name;
844     sk_ip = strrchr(name, '-');
845     if (!sk_ip) {
846         return (0);
847     }
848
849     *sk_ip = '\0';
850     sk_ip++;
851
852     /* Delete syscheck */
853     delete_syscheck(sk_name, sk_ip, 1);
854
855     /* Delete rootcheck */
856     delete_rootcheck(sk_name, sk_ip, 1);
857
858     return (1);
859 }
860
861 /* Print the text representation of the agent status */
862 const char *print_agent_status(int status)
863 {
864     const char *status_str = "Never connected";
865
866     if (status == GA_STATUS_ACTIVE) {
867         status_str = "Active";
868     } else if (status == GA_STATUS_NACTIVE) {
869         status_str = "Disconnected";
870     }
871
872     return (status_str);
873 }
874
875 #ifndef WIN32
876 /* Non-windows functions from now on */
877
878 /* Send a message to an agent
879  * Returns -1 on error
880  */
881 int send_msg_to_agent(int msocket, const char *msg, const char *agt_id, const char *exec)
882 {
883     int rc;
884     char agt_msg[OS_SIZE_1024 + 1];
885
886     agt_msg[OS_SIZE_1024] = '\0';
887
888     if (!exec) {
889         snprintf(agt_msg, OS_SIZE_1024,
890                  "%s %c%c%c %s %s",
891                  "(msg_to_agent) []",
892                  (agt_id == NULL) ? ALL_AGENTS_C : NONE_C,
893                  NO_AR_C,
894                  (agt_id != NULL) ? SPECIFIC_AGENT_C : NONE_C,
895                  agt_id != NULL ? agt_id : "(null)",
896                  msg);
897     } else {
898         snprintf(agt_msg, OS_SIZE_1024,
899                  "%s %c%c%c %s %s - %s (from_the_server) (no_rule_id)",
900                  "(msg_to_agent) []",
901                  (agt_id == NULL) ? ALL_AGENTS_C : NONE_C,
902                  NONE_C,
903                  (agt_id != NULL) ? SPECIFIC_AGENT_C : NONE_C,
904                  agt_id != NULL ? agt_id : "(null)",
905                  msg, exec);
906
907     }
908
909     if ((rc = OS_SendUnix(msocket, agt_msg, 0)) < 0) {
910         if (rc == OS_SOCKBUSY) {
911             merror("%s: ERROR: Remoted socket busy.", __local_name);
912         } else {
913             merror("%s: ERROR: Remoted socket error.", __local_name);
914         }
915         merror("%s: Error communicating with remoted queue (%d).",
916                __local_name, rc);
917
918         return (-1);
919     }
920
921     return (0);
922 }
923
924 /* Connect to remoted to be able to send messages to the agents
925  * Returns the socket on success or -1 on failure
926  */
927 int connect_to_remoted()
928 {
929     int arq = -1;
930
931     if ((arq = StartMQ(ARQUEUE, WRITE)) < 0) {
932         merror(ARQ_ERROR, __local_name);
933         return (-1);
934     }
935
936     return (arq);
937 }
938
939 const char *agent_file_perm(char *perm)
940 {
941         /* rwxrwxrwx0 -> 10 */
942         static char permissions[10];
943         mode_t mode = 0;
944
945         /* octal or decimal */
946         mode = (mode_t) strtoul(perm, 0, strlen(perm) == 3 ? 8 : 10);
947
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';
958
959         return &permissions[0];
960 }
961
962 #endif /* !WIN32 */
963
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)
966 {
967     FILE *fp;
968     char buf[1024 + 1];
969
970     /* Agent name of null, means it is the server info */
971     if (agent_name == NULL) {
972         snprintf(buf, 1024, "%s/rootcheck",
973                  ROOTCHECK_DIR);
974     } else {
975         snprintf(buf, 1024, "%s/(%s) %s->rootcheck",
976                  ROOTCHECK_DIR, agent_name, agent_ip);
977     }
978
979     /* If file is not there, set to unknown */
980     fp = fopen(buf, "r");
981     if (!fp) {
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);
986         return (0);
987     }
988
989     while (fgets(buf, 1024, fp) != NULL) {
990         char *tmp_str = NULL;
991
992         /* Remove newline */
993         tmp_str = strchr(buf, '\n');
994         if (tmp_str) {
995             *tmp_str = '\0';
996         }
997
998         tmp_str = strstr(buf, "Starting syscheck scan");
999         if (tmp_str) {
1000             time_t s_time = 0;
1001             tmp_str = buf + 1;
1002
1003             s_time = (time_t)atoi(tmp_str);
1004             os_strdup(ctime(&s_time), agt_info->syscheck_time);
1005
1006             /* Remove newline */
1007             tmp_str = strchr(agt_info->syscheck_time, '\n');
1008             if (tmp_str) {
1009                 *tmp_str = '\0';
1010             }
1011
1012             continue;
1013         }
1014
1015         tmp_str = strstr(buf, "Ending syscheck scan");
1016         if (tmp_str) {
1017             time_t s_time = 0;
1018             tmp_str = buf + 1;
1019
1020             s_time = (time_t)atoi(tmp_str);
1021
1022             os_strdup(ctime(&s_time), agt_info->syscheck_endtime);
1023
1024             /* Remove newline */
1025             tmp_str = strchr(agt_info->syscheck_endtime, '\n');
1026             if (tmp_str) {
1027                 *tmp_str = '\0';
1028             }
1029
1030             continue;
1031         }
1032
1033         tmp_str = strstr(buf, "Starting rootcheck scan");
1034         if (tmp_str) {
1035             time_t s_time = 0;
1036             tmp_str = buf + 1;
1037
1038             s_time = (time_t)atoi(tmp_str);
1039
1040             os_strdup(ctime(&s_time), agt_info->rootcheck_time);
1041
1042             /* Remove newline */
1043             tmp_str = strchr(agt_info->rootcheck_time, '\n');
1044             if (tmp_str) {
1045                 *tmp_str = '\0';
1046             }
1047
1048             continue;
1049         }
1050
1051         tmp_str = strstr(buf, "Ending rootcheck scan");
1052         if (tmp_str) {
1053             time_t s_time = 0;
1054             tmp_str = buf + 1;
1055             s_time = (time_t)atoi(tmp_str);
1056             os_strdup(ctime(&s_time), agt_info->rootcheck_endtime);
1057
1058             /* Remove newline */
1059             tmp_str = strchr(agt_info->rootcheck_endtime, '\n');
1060             if (tmp_str) {
1061                 *tmp_str = '\0';
1062             }
1063
1064             continue;
1065         }
1066     }
1067
1068     /* Set unknown values */
1069     if (!agt_info->rootcheck_time) {
1070         os_strdup("Unknown", agt_info->rootcheck_time);
1071     }
1072     if (!agt_info->rootcheck_endtime) {
1073         os_strdup("Unknown", agt_info->rootcheck_endtime);
1074     }
1075     if (!agt_info->syscheck_time) {
1076         os_strdup("Unknown", agt_info->syscheck_time);
1077     }
1078     if (!agt_info->syscheck_endtime) {
1079         os_strdup("Unknown", agt_info->syscheck_endtime);
1080     }
1081
1082     fclose(fp);
1083     return (0);
1084 }
1085
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)
1088 {
1089     char buf[1024 + 1];
1090     struct stat file_status;
1091
1092     /* No keepalive for the server */
1093     if (!agent_name) {
1094         return (strdup("Not available"));
1095     }
1096
1097     snprintf(buf, 1024, "%s/%s-%s", AGENTINFO_DIR, agent_name, agent_ip);
1098     if (stat(buf, &file_status) < 0) {
1099         return (strdup("Unknown"));
1100     }
1101
1102     return (strdup(ctime(&file_status.st_mtime)));
1103 }
1104
1105 /* Internal function. Extract operating system. */
1106 static int _get_agent_os(const char *agent_name, const char *agent_ip, agent_info *agt_info)
1107 {
1108     FILE *fp;
1109     char buf[1024 + 1];
1110
1111     /* Get server info */
1112     if (!agent_name) {
1113         char *ossec_version = NULL;
1114         agt_info->os = getuname();
1115         os_strdup(__ossec_name " " __version, agt_info->version);
1116
1117         /* Remove newline */
1118         ossec_version = strchr(agt_info->os, '\n');
1119         if (ossec_version) {
1120             *ossec_version = '\0';
1121         }
1122
1123         ossec_version = strstr(agt_info->os, " - ");
1124         if (ossec_version) {
1125             *ossec_version = '\0';
1126         }
1127
1128         return (0);
1129     }
1130
1131     snprintf(buf, 1024, "%s/%s-%s", AGENTINFO_DIR, agent_name, agent_ip);
1132     fp = fopen(buf, "r");
1133     if (!fp) {
1134         os_strdup("Unknown", agt_info->os);
1135         os_strdup("Unknown", agt_info->version);
1136         return (0);
1137     }
1138
1139     if (fgets(buf, 1024, fp)) {
1140         char *ossec_version = NULL;
1141
1142         /* Remove newline */
1143         ossec_version = strchr(buf, '\n');
1144         if (ossec_version) {
1145             *ossec_version = '\0';
1146         }
1147
1148         ossec_version = strstr(buf, " - ");
1149         if (ossec_version) {
1150             *ossec_version = '\0';
1151             ossec_version += 3;
1152
1153             os_calloc(1024 + 1, sizeof(char), agt_info->version);
1154             strncpy(agt_info->version, ossec_version, 1024);
1155         }
1156
1157         os_strdup(buf, agt_info->os);
1158         fclose(fp);
1159
1160         return (1);
1161     }
1162
1163     fclose(fp);
1164
1165     os_strdup("Unknown", agt_info->os);
1166     os_strdup("Unknown", agt_info->version);
1167
1168     return (0);
1169 }
1170
1171 /* Get information from an agent */
1172 agent_info *get_agent_info(const char *agent_name, const char *agent_ip)
1173 {
1174     char *agent_ip_pt = NULL;
1175     char *tmp_str = NULL;
1176
1177     agent_info *agt_info = NULL;
1178
1179     /* Remove the "/", since it is not present on the file */
1180     if ((agent_ip_pt = strchr(agent_ip, '/'))) {
1181         *agent_ip_pt = '\0';
1182     }
1183
1184     /* Allocate memory for the info structure */
1185     os_calloc(1, sizeof(agent_info), agt_info);
1186
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;
1195
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);
1200
1201     /* Remove newline from keepalive */
1202     tmp_str = strchr(agt_info->last_keepalive, '\n');
1203     if (tmp_str) {
1204         *tmp_str = '\0';
1205     }
1206
1207     /* Set back the IP address */
1208     if (agent_ip_pt) {
1209         *agent_ip_pt = '/';
1210     }
1211
1212     return (agt_info);
1213 }
1214
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)
1217 {
1218     char tmp_file[513];
1219     char *agent_ip_pt = NULL;
1220     struct stat file_status;
1221
1222     tmp_file[512] = '\0';
1223
1224     /* Server info */
1225     if (agent_name == NULL) {
1226         return (GA_STATUS_ACTIVE);
1227     }
1228
1229     /* Remove the  "/", since it is not present on the file */
1230     if ((agent_ip_pt = strchr(agent_ip, '/'))) {
1231         *agent_ip_pt = '\0';
1232     }
1233
1234     snprintf(tmp_file, 512, "%s/%s-%s", AGENTINFO_DIR, agent_name, agent_ip);
1235
1236     /* Set back the IP address */
1237     if (agent_ip_pt) {
1238         *agent_ip_pt = '/';
1239     }
1240
1241     if (stat(tmp_file, &file_status) < 0) {
1242         return (GA_STATUS_INV);
1243     }
1244
1245     if (file_status.st_mtime > (time(0) - (3 * NOTIFY_TIME + 30))) {
1246         return (GA_STATUS_ACTIVE);
1247     }
1248
1249     return (GA_STATUS_NACTIVE);
1250 }
1251
1252 /* List available agents with specified timeout */
1253 char **get_agents_with_timeout(int flag, int timeout)
1254 {
1255     size_t f_size = 0;
1256     char **f_files = NULL;
1257     DIR *dp;
1258     struct dirent *entry;
1259
1260     /* Open the directory */
1261     dp = opendir(AGENTINFO_DIR);
1262     if (!dp) {
1263         merror("%s: Error opening directory: '%s': %s ",
1264                __local_name,
1265                AGENTINFO_DIR,
1266                strerror(errno));
1267         return (NULL);
1268     }
1269
1270     /* Read directory */
1271     while ((entry = readdir(dp)) != NULL) {
1272         int status = 0;
1273         char tmp_file[513];
1274         tmp_file[512] = '\0';
1275
1276         /* Ignore . and ..  */
1277         if ((strcmp(entry->d_name, ".") == 0) ||
1278                 (strcmp(entry->d_name, "..") == 0)) {
1279             continue;
1280         }
1281
1282         snprintf(tmp_file, 512, "%s/%s", AGENTINFO_DIR, entry->d_name);
1283
1284         if (flag != GA_ALL) {
1285             struct stat file_status;
1286
1287             if (stat(tmp_file, &file_status) < 0) {
1288                 continue;
1289             }
1290
1291             if (file_status.st_mtime > (time(0) - (3 * timeout + 30))) {
1292                 status = 1;
1293                 if (flag == GA_NOTACTIVE) {
1294                     continue;
1295                 }
1296             } else {
1297                 if (flag == GA_ACTIVE) {
1298                     continue;
1299                 }
1300             }
1301         }
1302
1303         f_files = (char **)realloc(f_files, (f_size + 2) * sizeof(char *));
1304         if (!f_files) {
1305             ErrorExit(MEM_ERROR, __local_name, errno, strerror(errno));
1306         }
1307
1308         /* Add agent entry */
1309         if (flag == GA_ALL_WSTATUS) {
1310             char agt_stat[512];
1311
1312             snprintf(agt_stat, sizeof(agt_stat) - 1, "%s %s",
1313                      entry->d_name, status == 1 ? "active" : "disconnected");
1314
1315             os_strdup(agt_stat, f_files[f_size]);
1316         } else {
1317             os_strdup(entry->d_name, f_files[f_size]);
1318         }
1319
1320         f_files[f_size + 1] = NULL;
1321
1322         f_size++;
1323     }
1324
1325     closedir(dp);
1326     return (f_files);
1327 }
1328
1329 /* List available agents */
1330 char **get_agents(int flag) {
1331   return get_agents_with_timeout(flag, NOTIFY_TIME);
1332 }