new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / addagent / validate.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights 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 <time.h>
11 #include "manage_agents.h"
12 #include "os_crypto/md5/md5_op.h"
13
14 /* Global variables */
15 fpos_t fp_pos;
16
17 /*Number bit of int type*/
18 #define INT_BIT_SIZE          (sizeof(int)*CHAR_BIT)
19 /*Enable bit at a position*/
20 #define SetBit(Array,pos)     ( Array[(pos/INT_BIT_SIZE)] |= (1 << (pos%INT_BIT_SIZE)) )
21 /*Check state of bit at a */
22 #define TestBit(Array,pos)    ( Array[(pos/INT_BIT_SIZE)] & (1 << (pos%INT_BIT_SIZE)) )
23
24 int *MapIDToBitArray()
25 {
26     FILE *fp;
27     char line_read[FILE_SIZE + 1];
28     line_read[FILE_SIZE] = '\0';
29     int *arrayID;
30     int max = MAX_AGENTS + AUTHD_FIRST_ID;
31     if (isChroot()) {
32         fp = fopen(AUTH_FILE, "r");
33     } else {
34         fp = fopen(KEYSFILE_PATH, "r");
35     }
36
37     if (!fp) {
38         return (NULL);
39     }
40
41     os_calloc(MAX_AGENTS/INT_BIT_SIZE + 1, sizeof(int), arrayID);
42
43     while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
44         char *name;
45
46         if (line_read[0] == '#') {
47             continue;
48         }
49
50         name = strchr(line_read, ' ');
51         if (name) {
52             *name = '\0';
53             int name_num=atoi(line_read);
54             /*Enable bit at ID already allocated*/
55             if (name_num >= AUTHD_FIRST_ID && name_num < max) {
56                 SetBit(arrayID, (name_num-AUTHD_FIRST_ID));
57             }
58         }
59
60     }
61     fclose(fp);
62     return arrayID;
63 }
64
65 char *OS_AddNewAgent(const char *name, const char *ip, const char *id)
66 {
67     FILE *fp;
68     os_md5 md1;
69     os_md5 md2;
70     char str1[STR_SIZE + 1];
71     char str2[STR_SIZE + 1];
72     char *muname;
73     char *finals;
74     char nid[9] = { '\0' };
75
76     srandom_init();
77     muname = getuname();
78
79     snprintf(str1, STR_SIZE, "%d%s%d%s", (int)time(0), name, (int)random(), muname);
80     snprintf(str2, STR_SIZE, "%s%s%ld", ip, id, (long int)random());
81     OS_MD5_Str(str1, md1);
82     OS_MD5_Str(str2, md2);
83
84     free(muname);
85
86     if (id == NULL) {
87         int *arrayID;
88         int i;
89         arrayID=(int *)MapIDToBitArray();
90         if (arrayID != NULL) {
91             /*Find first item in bit array which is not marked as allocated*/
92             for (i=0; i<MAX_AGENTS; i++) {
93                 if(!TestBit(arrayID, i)) {
94                     snprintf(nid, 8, "%d", (i + AUTHD_FIRST_ID));
95                     break;
96                 }
97             }
98             os_free(arrayID);
99
100             if (i == MAX_AGENTS) {
101                 return (NULL);
102             }
103         }
104         else {
105             return (NULL);
106         }
107
108         id = nid;
109     }
110
111     char authentication_file[2048 + 1];
112     snprintf(authentication_file, 2048, "%s%s", DEFAULTDIR, AUTH_FILE);
113
114     fp = fopen(authentication_file, "a");
115     if (!fp) {
116         return (NULL);
117     }
118
119     os_calloc(2048, sizeof(char), finals);
120     if (ip == NULL) {
121         snprintf(finals, 2048, "%s %s any %s%s", id, name, md1, md2);
122     } else {
123         snprintf(finals, 2048, "%s %s %s %s%s", id, name, ip, md1, md2);
124     }
125     fprintf(fp, "%s\n", finals);
126
127     fclose(fp);
128     return (finals);
129 }
130
131 int OS_RemoveAgent(const char *u_id) {
132     FILE *fp;
133     int id_exist;
134     char *full_name;
135
136     id_exist = IDExist(u_id);
137
138     if (!id_exist)
139         return 0;
140
141     fp = fopen(isChroot() ? AUTH_FILE : KEYSFILE_PATH, "r+");
142
143     if (!fp)
144         return 0;
145
146 #ifndef WIN32
147     if((chmod(AUTH_FILE, 0440)) < 0) {
148         merror("addagent: ERROR: Cannot chmod %s: %s", AUTH_FILE, strerror(errno));
149     }
150 #endif
151
152 #ifdef REUSE_ID
153     long fp_seek;
154     size_t fp_read;
155     char *buffer;
156     char buf_discard[OS_BUFFER_SIZE];
157     struct stat fp_stat;
158
159     if (stat(AUTH_FILE, &fp_stat) < 0) {
160         fclose(fp);
161         return 0;
162     }
163
164     buffer = malloc(fp_stat.st_size);
165     if (!buffer) {
166         fclose(fp);
167         return 0;
168     }
169
170     fsetpos(fp, &fp_pos);
171     fp_seek = ftell(fp);
172     fseek(fp, 0, SEEK_SET);
173     fp_read = fread(buffer, sizeof(char), fp_seek, fp);
174     fgets(buf_discard, OS_BUFFER_SIZE - 1, fp);
175
176     if (!feof(fp))
177         fp_read += fread(buffer + fp_read, sizeof(char), fp_stat.st_size, fp);
178
179     fclose(fp);
180     fp = fopen(AUTH_FILE, "w");
181
182     if (!fp) {
183         free(buffer);
184         return 0;
185     }
186
187     fwrite(buffer, sizeof(char), fp_read, fp);
188
189 #else
190     /* Remove the agent, but keep the id */
191     fsetpos(fp, &fp_pos);
192     fprintf(fp, "%s #*#*#*#*#*#*#*#*#*#*#", u_id);
193 #endif
194     fclose(fp);
195
196     full_name = getFullnameById(u_id);
197     if (full_name)
198         delete_agentinfo(full_name);
199
200     /* Remove counter for ID */
201     OS_RemoveCounter(u_id);
202     return 1;
203 }
204
205 int OS_IsValidID(const char *id)
206 {
207     size_t id_len, i;
208
209     /* ID must not be null */
210     if (!id) {
211         return (0);
212     }
213
214     id_len = strlen(id);
215
216     /* Check ID length, it should contain max. 8 characters */
217     if (id_len > 8) {
218         return (0);
219     }
220
221     /* Check ID if it contains only numeric characters [0-9] */
222     for (i = 0; i < id_len; i++) {
223         if (!(isdigit((int)id[i]))) {
224             return (0);
225         }
226     }
227
228     return (1);
229 }
230
231 /* Get full agent name (name + IP) of ID */
232 char *getFullnameById(const char *id)
233 {
234     FILE *fp;
235     char line_read[FILE_SIZE + 1];
236     line_read[FILE_SIZE] = '\0';
237
238     /* ID must not be null */
239     if (!id) {
240         return (NULL);
241     }
242
243     fp = fopen(AUTH_FILE, "r");
244     if (!fp) {
245         return (NULL);
246     }
247
248     while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
249         char *name;
250         char *ip;
251         char *tmp_str;
252
253         if (line_read[0] == '#') {
254             continue;
255         }
256
257         name = strchr(line_read, ' ');
258         if (name) {
259             *name = '\0';
260             /* Didn't match */
261             if (strcmp(line_read, id) != 0) {
262                 continue;
263             }
264
265             name++;
266
267             /* Removed entry */
268             if (*name == '#') {
269                 continue;
270             }
271
272             ip = strchr(name, ' ');
273             if (ip) {
274                 *ip = '\0';
275                 ip++;
276
277                 /* Clean up IP */
278                 tmp_str = strchr(ip, ' ');
279                 if (tmp_str) {
280                     char *final_str;
281                     *tmp_str = '\0';
282                     tmp_str = strchr(ip, '/');
283                     if (tmp_str) {
284                         *tmp_str = '\0';
285                     }
286
287                     /* If we reached here, we found the IP and name */
288                     os_calloc(1, FILE_SIZE, final_str);
289                     snprintf(final_str, FILE_SIZE - 1, "%s-%s", name, ip);
290
291                     fclose(fp);
292                     return (final_str);
293                 }
294             }
295         }
296     }
297
298     fclose(fp);
299     return (NULL);
300 }
301
302 /* ID Search (is valid ID) */
303 int IDExist(const char *id)
304 {
305     FILE *fp;
306     char line_read[FILE_SIZE + 1];
307     line_read[FILE_SIZE] = '\0';
308
309     /* ID must not be null */
310     if (!id) {
311         return (0);
312     }
313
314     if (isChroot()) {
315         fp = fopen(AUTH_FILE, "r");
316     } else {
317         fp = fopen(KEYSFILE_PATH, "r");
318     }
319
320     if (!fp) {
321         return (0);
322     }
323
324     fseek(fp, 0, SEEK_SET);
325     fgetpos(fp, &fp_pos);
326
327     while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
328         char *name;
329
330         if (line_read[0] == '#') {
331             fgetpos(fp, &fp_pos);
332             continue;
333         }
334
335         name = strchr(line_read, ' ');
336         if (name) {
337             *name = '\0';
338             name++;
339
340             if (strcmp(line_read, id) == 0) {
341                 fclose(fp);
342                 return (1); /*(fp_pos);*/
343             }
344         }
345
346         fgetpos(fp, &fp_pos);
347     }
348
349     fclose(fp);
350     return (0);
351 }
352
353 /* Validate agent name */
354 int OS_IsValidName(const char *u_name)
355 {
356     size_t i, uname_length = strlen(u_name);
357
358     /* We must have something in the name */
359     if (uname_length < 2 || uname_length > 128) {
360         return (0);
361     }
362
363     /* Check if it contains any non-alphanumeric characters */
364     for (i = 0; i < uname_length; i++) {
365         if ( !( isalnum((int)u_name[i]) || (u_name[i] == '-') ||
366                 (u_name[i] == '_') || (u_name[i] == '.') ||
367                 (u_name[i] == ':') ) ) {
368             return (0);
369         }
370     }
371
372     return (1);
373 }
374
375 int NameExist(const char *u_name)
376 {
377     FILE *fp;
378     char line_read[FILE_SIZE + 1];
379     line_read[FILE_SIZE] = '\0';
380
381     if ((!u_name) ||
382             (*u_name == '\0') ||
383             (*u_name == '\r') ||
384             (*u_name == '\n')) {
385         return (0);
386     }
387
388     if (isChroot()) {
389         fp = fopen(AUTH_FILE, "r");
390     } else {
391         fp = fopen(KEYSFILE_PATH, "r");
392     }
393
394     if (!fp) {
395         return (0);
396     }
397
398     fseek(fp, 0, SEEK_SET);
399     fgetpos(fp, &fp_pos);
400
401     while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
402         char *name;
403
404         if (line_read[0] == '#') {
405             continue;
406         }
407
408         name = strchr(line_read, ' ');
409         if (name) {
410             char *ip;
411             name++;
412
413             if (*name == '#') {
414                 continue;
415             }
416
417             ip = strchr(name, ' ');
418             if (ip) {
419                 *ip = '\0';
420                 if (strcmp(u_name, name) == 0) {
421                     fclose(fp);
422                     return (1);
423                 }
424             }
425         }
426         fgetpos(fp, &fp_pos);
427     }
428
429     fclose(fp);
430     return (0);
431 }
432
433 /* Returns the ID of an agent, or NULL if not found */
434 char *IPExist(const char *u_ip)
435 {
436     FILE *fp;
437     char *name, *ip, *pass;
438     char line_read[FILE_SIZE + 1];
439     line_read[FILE_SIZE] = '\0';
440
441     if (!(u_ip && strncmp(u_ip, "any", 3)) || strchr(u_ip, '/'))
442         return NULL;
443
444     if (isChroot())
445         fp = fopen(AUTH_FILE, "r");
446     else
447         fp = fopen(KEYSFILE_PATH, "r");
448
449     if (!fp)
450         return NULL;
451
452     fseek(fp, 0, SEEK_SET);
453     fgetpos(fp, &fp_pos);
454
455     while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
456         if (line_read[0] == '#') {
457             continue;
458         }
459
460         name = strchr(line_read, ' ');
461         if (name) {
462             name++;
463
464             if (*name == '#') {
465                 continue;
466             }
467
468             ip = strchr(name, ' ');
469             if (ip) {
470                 ip++;
471
472                 pass = strchr(ip, ' ');
473                 if (pass) {
474                     *pass = '\0';
475                     if (strcmp(u_ip, ip) == 0) {
476                         fclose(fp);
477                         name[-1] = '\0';
478                         return strdup(line_read);
479                     }
480                 }
481             }
482         }
483
484         fgetpos(fp, &fp_pos);
485     }
486
487     fclose(fp);
488     return NULL;
489 }
490
491 /* Returns the number of seconds since last agent connection, or -1 if error. */
492 double OS_AgentAntiquity(const char *id)
493 {
494     struct stat file_stat;
495     char file_name[OS_FLSIZE];
496     char *full_name = getFullnameById(id);
497
498     if (!full_name) {
499         return -1;
500     }
501
502     snprintf(file_name, OS_FLSIZE - 1, "%s/%s", AGENTINFO_DIR, full_name);
503
504     if (stat(file_name, &file_stat) < 0) {
505         if(full_name) {
506             free(full_name);
507         }
508         return -1;
509     }
510
511     free(full_name);
512
513     return difftime(time(NULL), file_stat.st_mtime);
514 }
515
516 /* Print available agents */
517 int print_agents(int print_status, int active_only, int csv_output, cJSON *json_output)
518 {
519     int total = 0;
520     FILE *fp;
521     char line_read[FILE_SIZE + 1];
522     line_read[FILE_SIZE] = '\0';
523
524     fp = fopen(AUTH_FILE, "r");
525     if (!fp) {
526         return (0);
527     }
528
529     fseek(fp, 0, SEEK_SET);
530
531     memset(line_read, '\0', FILE_SIZE);
532
533     while (fgets(line_read, FILE_SIZE - 1, fp) != NULL) {
534         char *name;
535
536         if (line_read[0] == '#') {
537             continue;
538         }
539
540         name = strchr(line_read, ' ');
541         if (name) {
542             char *ip;
543             *name = '\0';
544             name++;
545
546             /* Removed agent */
547             if (*name == '#') {
548                 continue;
549             }
550
551             ip = strchr(name, ' ');
552             if (ip) {
553                 char *key;
554                 *ip = '\0';
555                 ip++;
556                 key = strchr(ip, ' ');
557                 if (key) {
558                     *key = '\0';
559                     if (!total && !print_status) {
560                         printf(PRINT_AVAILABLE);
561                     }
562                     total++;
563
564                     if (print_status) {
565                         int agt_status = get_agent_status(name, ip);
566                         if (active_only && (agt_status != GA_STATUS_ACTIVE)) {
567                             continue;
568                         }
569
570                         if (csv_output) {
571                             printf("%s,%s,%s,%s,\n", line_read, name, ip, print_agent_status(agt_status));
572                         } else if (json_output) {
573                             cJSON *json_agent = cJSON_CreateObject();
574                           
575                             if (!json_agent)
576                                 return 0;
577                             
578                             cJSON_AddStringToObject(json_agent, "id", line_read);
579                             cJSON_AddStringToObject(json_agent, "name", name);
580                             cJSON_AddStringToObject(json_agent, "ip", ip);
581                             cJSON_AddStringToObject(json_agent, "status", print_agent_status(agt_status));
582                             cJSON_AddItemToArray(json_output, json_agent);
583                         } else {
584                             printf(PRINT_AGENT_STATUS, line_read, name, ip, print_agent_status(agt_status));
585                         }
586                     } else {
587                         printf(PRINT_AGENT, line_read, name, ip);
588                     }
589                 }
590             }
591         }
592     }
593
594     /* Only print agentless for non-active only searches */
595     if (!active_only && print_status) {
596         const char *aip = NULL;
597         DIR *dirp;
598         struct dirent *dp;
599
600         if (!csv_output && !json_output) {
601             printf("\nList of agentless devices:\n");
602         }
603
604         dirp = opendir(AGENTLESS_ENTRYDIR);
605         if (dirp) {
606             while ((dp = readdir(dirp)) != NULL) {
607                 if (strncmp(dp->d_name, ".", 1) == 0) {
608                     continue;
609                 }
610
611                 aip = strchr(dp->d_name, '@');
612                 if (aip) {
613                     aip++;
614                 } else {
615                     aip = "<na>";
616                 }
617
618                 if (csv_output) {
619                     printf("na,%s,%s,agentless,\n", dp->d_name, aip);
620                 } else {
621                     printf("   ID: na, Name: %s, IP: %s, agentless\n",
622                            dp->d_name, aip);
623                 }
624             }
625             closedir(dirp);
626         }
627     }
628
629     fclose(fp);
630     if (total) {
631         return (1);
632     }
633
634     return (0);
635 }
636
637 void FormatID(char *id) {
638     int number;
639     char *end;
640
641     if (id && *id) {
642         number = strtol(id, &end, 10);
643
644         if (!*end) {
645             sprintf(id, "%03d", number);
646         }
647     }
648 }