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  */
save_controlmsg(unsigned int agentid,char * r_msg)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 */
f_files()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 */
c_files()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  */
send_file_toagent(unsigned int agentid,const char * name,const char * sum)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 */
read_controlmsg(unsigned int agentid,char * msg)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  */
wait_for_msgs(void * none)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 */
manager_init(int isUpdate)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 
544