new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / remoted / manager.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 "remoted.h"
12 #include "os_crypto/md5/md5_op.h"
13 #include "os_net/os_net.h"
14 #include <pthread.h>
15
16 /* Internal structures */
17 typedef struct _file_sum {
18     int mark;
19     char *name;
20     os_md5 sum;
21 } file_sum;
22
23 /* Internal functions prototypes */
24 static void read_controlmsg(unsigned int agentid, char *msg);
25 static int send_file_toagent(unsigned int agentid, const char *name, const char *sum);
26 static void f_files(void);
27 static void c_files(void);
28
29 /* Global vars */
30 static file_sum **f_sum;
31 static time_t _ctime;
32 static time_t _stime;
33
34 /* For the last message tracking */
35 static char *_msg[MAX_AGENTS + 1];
36 static char *_keep_alive[MAX_AGENTS + 1];
37 static int _changed[MAX_AGENTS + 1];
38 static int modified_agentid;
39
40 /* pthread mutex variables */
41 static pthread_mutex_t lastmsg_mutex;
42 static pthread_cond_t awake_mutex;
43
44
45 /* Save a control message received from an agent
46  * read_controlmsg (other thread) is going to deal with it
47  * (only if message changed)
48  */
49 void save_controlmsg(unsigned int agentid, char *r_msg)
50 {
51     char msg_ack[OS_FLSIZE + 1];
52
53     /* Reply to the agent */
54     snprintf(msg_ack, OS_FLSIZE, "%s%s", CONTROL_HEADER, HC_ACK);
55     send_msg(agentid, msg_ack);
56
57     /* Check if there is a keep alive already for this agent */
58     if (_keep_alive[agentid] && _msg[agentid] &&
59             (strcmp(_msg[agentid], r_msg) == 0)) {
60         utimes(_keep_alive[agentid], NULL);
61     }
62
63     else if (strcmp(r_msg, HC_STARTUP) == 0) {
64         return;
65     }
66
67     else {
68         FILE *fp;
69         char *uname = r_msg;
70         char *random_leftovers;
71
72         /* Lock mutex */
73         if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
74             merror(MUTEX_ERROR, ARGV0);
75             return;
76         }
77
78         /* Update rmsg */
79         if (_msg[agentid]) {
80             free(_msg[agentid]);
81         }
82         os_strdup(r_msg, _msg[agentid]);
83
84         /* Unlock mutex */
85         if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
86             merror(MUTEX_ERROR, ARGV0);
87             return;
88         }
89
90         r_msg = strchr(r_msg, '\n');
91         if (!r_msg) {
92             merror("%s: WARN: Invalid message from agent id: '%d'(uname)",
93                    ARGV0,
94                    agentid);
95             return;
96         }
97
98         *r_msg = '\0';
99         random_leftovers = strchr(r_msg, '\n');
100         if (random_leftovers) {
101             *random_leftovers = '\0';
102         }
103
104         /* Update the keep alive */
105         if (!_keep_alive[agentid]) {
106             char agent_file[OS_SIZE_1024 + 1];
107             agent_file[OS_SIZE_1024] = '\0';
108
109             /* Write to the agent file */
110             snprintf(agent_file, OS_SIZE_1024, "%s/%s-%s",
111                      AGENTINFO_DIR,
112                      keys.keyentries[agentid]->name,
113                      keys.keyentries[agentid]->ip->ip);
114             os_strdup(agent_file, _keep_alive[agentid]);
115         }
116
117         /* Write to the file */
118         fp = fopen(_keep_alive[agentid], "w");
119         if (fp) {
120             fprintf(fp, "%s\n", uname);
121             fclose(fp);
122         } else {
123             merror("ossec-remoted: ERROR: Could not open %s: %s", _keep_alive[agentid], strerror(errno));
124         }
125     }
126
127     /* Lock now to notify of change */
128     if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
129         merror(MUTEX_ERROR, ARGV0);
130         return;
131     }
132
133     /* Assign new values */
134     _changed[agentid] = 1;
135     modified_agentid = (int) agentid;
136
137     /* Signal that new data is available */
138     pthread_cond_signal(&awake_mutex);
139
140     /* Unlock mutex */
141     if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
142         merror(MUTEX_ERROR, ARGV0);
143         return;
144     }
145
146     return;
147 }
148
149 /* Free the files memory */
150 static void f_files()
151 {
152     int i;
153     if (!f_sum) {
154         return;
155     }
156     for (i = 0;; i++) {
157         if (f_sum[i] == NULL) {
158             break;
159         }
160
161         if (f_sum[i]->name) {
162             free(f_sum[i]->name);
163         }
164
165         free(f_sum[i]);
166         f_sum[i] = NULL;
167     }
168
169     free(f_sum);
170     f_sum = NULL;
171 }
172
173 /* Create the structure with the files and checksums */
174 static void c_files()
175 {
176     DIR *dp;
177     struct dirent *entry;
178     os_md5 md5sum;
179     unsigned int f_size = 0;
180
181     f_sum = NULL;
182
183     /* Create merged file */
184     os_realloc(f_sum, (f_size + 2) * sizeof(file_sum *), f_sum);
185     os_calloc(1, sizeof(file_sum), f_sum[f_size]);
186     f_sum[f_size]->mark = 0;
187     f_sum[f_size]->name = NULL;
188     f_sum[f_size]->sum[0] = '\0';
189     MergeAppendFile(SHAREDCFG_FILE, NULL);
190     f_size++;
191
192     /* Open directory */
193     dp = opendir(SHAREDCFG_DIR);
194     if (!dp) {
195         merror("%s: Error opening directory: '%s': %s ",
196                ARGV0,
197                SHAREDCFG_DIR,
198                strerror(errno));
199         return;
200     }
201
202     /* Read directory */
203     while ((entry = readdir(dp)) != NULL) {
204         char tmp_dir[512];
205
206         /* Ignore . and ..  */
207         if ((strcmp(entry->d_name, ".") == 0) ||
208                 (strcmp(entry->d_name, "..") == 0)) {
209             continue;
210         }
211
212         snprintf(tmp_dir, 512, "%s/%s", SHAREDCFG_DIR, entry->d_name);
213
214         /* Leave the shared config file for later */
215         if (strcmp(tmp_dir, SHAREDCFG_FILE) == 0) {
216             continue;
217         }
218
219         if (OS_MD5_File(tmp_dir, md5sum, OS_TEXT) != 0) {
220             merror("%s: Error accessing file '%s'", ARGV0, tmp_dir);
221             continue;
222         }
223
224         f_sum = (file_sum **)realloc(f_sum, (f_size + 2) * sizeof(file_sum *));
225         if (!f_sum) {
226             ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
227         }
228
229         f_sum[f_size] = (file_sum *) calloc(1, sizeof(file_sum));
230         if (!f_sum[f_size]) {
231             ErrorExit(MEM_ERROR, ARGV0, errno, strerror(errno));
232         }
233
234         strncpy(f_sum[f_size]->sum, md5sum, 32);
235         os_strdup(entry->d_name, f_sum[f_size]->name);
236         f_sum[f_size]->mark = 0;
237
238         MergeAppendFile(SHAREDCFG_FILE, tmp_dir);
239         f_size++;
240     }
241
242     if (f_sum != NULL) {
243         f_sum[f_size] = NULL;
244     }
245
246     closedir(dp);
247
248     if (OS_MD5_File(SHAREDCFG_FILE, md5sum, OS_TEXT) != 0) {
249         merror("%s: Error accessing file '%s'", ARGV0, SHAREDCFG_FILE);
250         f_sum[0]->sum[0] = '\0';
251     }
252     strncpy(f_sum[0]->sum, md5sum, 32);
253
254     os_strdup(SHAREDCFG_FILENAME, f_sum[0]->name);
255
256     return;
257 }
258
259 /* Send a file to the agent
260  * Returns -1 on error
261  */
262 static int send_file_toagent(unsigned int agentid, const char *name, const char *sum)
263 {
264     int i = 0;
265     size_t n = 0;
266     char file[OS_SIZE_1024 + 1];
267     char buf[OS_SIZE_1024 + 1];
268     FILE *fp;
269
270     snprintf(file, OS_SIZE_1024, "%s/%s", SHAREDCFG_DIR, name);
271     fp = fopen(file, "r");
272     if (!fp) {
273         merror(FOPEN_ERROR, ARGV0, file, errno, strerror(errno));
274         return (-1);
275     }
276
277     /* Send the file name first */
278     snprintf(buf, OS_SIZE_1024, "%s%s%s %s\n",
279              CONTROL_HEADER, FILE_UPDATE_HEADER, sum, name);
280     if (send_msg(agentid, buf) == -1) {
281         merror(SEC_ERROR, ARGV0);
282         fclose(fp);
283         return (-1);
284     }
285
286     /* Send the file contents */
287     while ((n = fread(buf, 1, 900, fp)) > 0) {
288         buf[n] = '\0';
289
290         if (send_msg(agentid, buf) == -1) {
291             merror(SEC_ERROR, ARGV0);
292             fclose(fp);
293             return (-1);
294         }
295
296         /* Sleep 1 every 30 messages -- no flood */
297         if (i > 30) {
298             sleep(1);
299             i = 0;
300         }
301         i++;
302     }
303
304     /* Send the message to close the file */
305     snprintf(buf, OS_SIZE_1024, "%s%s", CONTROL_HEADER, FILE_CLOSE_HEADER);
306     if (send_msg(agentid, buf) == -1) {
307         merror(SEC_ERROR, ARGV0);
308         fclose(fp);
309         return (-1);
310     }
311
312     fclose(fp);
313
314     return (0);
315 }
316
317 /* Read the available control message from the agent */
318 static void read_controlmsg(unsigned int agentid, char *msg)
319 {
320     int i;
321
322     /* Remove uname */
323     msg = strchr(msg, '\n');
324     if (!msg) {
325         merror("%s: Invalid message from '%d' (uname)", ARGV0, agentid);
326         return;
327     }
328
329     *msg = '\0';
330     msg++;
331
332     if (!f_sum) {
333         /* Nothing to share with agent */
334         return;
335     }
336
337     /* Parse message */
338     while (*msg != '\0') {
339         char *md5;
340         char *file;
341
342         md5 = msg;
343         file = msg;
344
345         msg = strchr(msg, '\n');
346         if (!msg) {
347             merror("%s: Invalid message from '%s' (strchr \\n)",
348                    ARGV0,
349                    keys.keyentries[agentid]->ip->ip);
350             break;
351         }
352
353         *msg = '\0';
354         msg++;
355
356         file = strchr(file, ' ');
357         if (!file) {
358             merror("%s: Invalid message from '%s' (strchr ' ')",
359                    ARGV0,
360                    keys.keyentries[agentid]->ip->ip);
361             break;
362         }
363
364         *file = '\0';
365         file++;
366
367         /* New agents only have merged.mg */
368         if (strcmp(file, SHAREDCFG_FILENAME) == 0) {
369             if (strcmp(f_sum[0]->sum, md5) != 0) {
370                 debug1("%s: DEBUG Sending file '%s' to agent.", ARGV0,
371                        f_sum[0]->name);
372                 if (send_file_toagent(agentid, f_sum[0]->name, f_sum[0]->sum) < 0) {
373                     merror("%s: ERROR: Unable to send file '%s' to agent.",
374                            ARGV0,
375                            f_sum[0]->name);
376                 }
377             }
378
379             i = 0;
380             while (f_sum[i]) {
381                 f_sum[i]->mark = 0;
382                 i++;
383             }
384
385             return;
386         }
387
388         for (i = 1;; i++) {
389             if (f_sum[i] == NULL) {
390                 break;
391             }
392
393             else if (strcmp(f_sum[i]->name, file) != 0) {
394                 continue;
395             }
396
397             else if (strcmp(f_sum[i]->sum, md5) != 0) {
398                 f_sum[i]->mark = 1;    /* Marked to update */
399             }
400
401             else {
402                 f_sum[i]->mark = 2;
403             }
404             break;
405         }
406     }
407
408     /* Update each marked file */
409     for (i = 1;; i++) {
410         if (f_sum[i] == NULL) {
411             break;
412         }
413
414         if ((f_sum[i]->mark == 1) ||
415                 (f_sum[i]->mark == 0)) {
416
417             debug1("%s: Sending file '%s' to agent.", ARGV0, f_sum[i]->name);
418             if (send_file_toagent(agentid, f_sum[i]->name, f_sum[i]->sum) < 0) {
419                 merror("%s: Error sending file '%s' to agent.",
420                        ARGV0,
421                        f_sum[i]->name);
422             }
423         }
424
425         f_sum[i]->mark = 0;
426     }
427
428     return;
429 }
430
431 /* Wait for new messages to read
432  * The messages will be sent using save_controlmsg
433  */
434 void *wait_for_msgs(__attribute__((unused)) void *none)
435 {
436     int id;
437     char msg[OS_SIZE_1024 + 2];
438
439     /* Initialize the memory */
440     memset(msg, '\0', OS_SIZE_1024 + 2);
441
442     /* Should never leave this loop */
443     while (1) {
444         unsigned int i;
445         /* Every NOTIFY * 30 minutes, re-read the files
446          * If something changed, notify all agents
447          */
448         _ctime = time(0);
449         if ((_ctime - _stime) > (NOTIFY_TIME * 30)) {
450             f_files();
451             c_files();
452
453             _stime = _ctime;
454         }
455
456         /* Lock mutex */
457         if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
458             merror(MUTEX_ERROR, ARGV0);
459             return (NULL);
460         }
461
462         /* If no agent changed, wait for signal */
463         if (modified_agentid == -1) {
464             pthread_cond_wait(&awake_mutex, &lastmsg_mutex);
465         }
466
467         /* Unlock mutex */
468         if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
469             merror(MUTEX_ERROR, ARGV0);
470             return (NULL);
471         }
472
473         /* Check if any agent is ready */
474         for (i = 0; i < keys.keysize; i++) {
475             /* If agent wasn't changed, try next */
476             if (_changed[i] != 1) {
477                 continue;
478             }
479
480             id = 0;
481
482             /* Lock mutex */
483             if (pthread_mutex_lock(&lastmsg_mutex) != 0) {
484                 merror(MUTEX_ERROR, ARGV0);
485                 break;
486             }
487
488             if (_msg[i]) {
489                 /* Copy the message to be analyzed */
490                 strncpy(msg, _msg[i], OS_SIZE_1024);
491                 _changed[i] = 0;
492
493                 if (modified_agentid >= (int) i) {
494                     modified_agentid = -1;
495                 }
496
497                 id = 1;
498             }
499
500             /* Unlock mutex */
501             if (pthread_mutex_unlock(&lastmsg_mutex) != 0) {
502                 merror(MUTEX_ERROR, ARGV0);
503                 break;
504             }
505
506             if (id) {
507                 read_controlmsg(i, msg);
508             }
509         }
510     }
511
512     return (NULL);
513 }
514
515 /* Should be called before anything here */
516 void manager_init(int isUpdate)
517 {
518     int i;
519
520     _stime = time(0);
521
522     f_files();
523     c_files();
524
525     debug1("%s: DEBUG: Running manager_init", ARGV0);
526
527     modified_agentid = -1;
528
529     for (i = 0; i < MAX_AGENTS + 1; i++) {
530         _keep_alive[i] = NULL;
531         _msg[i] = NULL;
532         _changed[i] = 0;
533     }
534
535     /* Initialize mutexes */
536     if (isUpdate == 0) {
537         pthread_mutex_init(&lastmsg_mutex, NULL);
538         pthread_cond_init(&awake_mutex, NULL);
539     }
540
541     return;
542 }
543