Imported Upstream version 2.7
[ossec-hids.git] / src / remoted / manager.c
1 /* @(#) $Id: ./src/remoted/manager.c, 2011/09/08 dcid Exp $
2  */
3
4 /* Copyright (C) 2009 Trend Micro Inc.
5  * All right reserved.
6  *
7  * This program is a free software; you can redistribute it
8  * and/or modify it under the terms of the GNU General Public
9  * License (version 2) as published by the FSF - Free Software
10  * Foundation
11  */
12
13 #include "shared.h"
14 #include <pthread.h>
15
16 #include "remoted.h"
17 #include "os_net/os_net.h"
18 #include "os_crypto/md5/md5_op.h"
19
20
21 /* Internal structures */
22 typedef struct _file_sum
23 {
24     int mark;
25     char *name;
26     os_md5 sum;
27 }file_sum;
28
29
30
31 /* Internal functions prototypes */
32 void read_controlmsg(int agentid, char *msg);
33
34
35
36
37 /* Global vars, acessible every where */
38 file_sum **f_sum;
39
40 time_t _ctime;
41 time_t _stime;
42
43
44
45 /* For the last message tracking */
46 char *_msg[MAX_AGENTS +1];
47 char *_keep_alive[MAX_AGENTS +1];
48 int _changed[MAX_AGENTS +1];
49 int modified_agentid;
50
51
52 /* pthread mutex variables */
53 pthread_mutex_t lastmsg_mutex;
54 pthread_cond_t awake_mutex;
55
56
57
58 /* save_controlmsg: Save a control message received
59  * from an agent. read_contromsg (other thread) is going
60  * to deal with it (only if message changed).
61  */
62 void save_controlmsg(int agentid, char *r_msg)
63 {
64     char msg_ack[OS_FLSIZE +1];
65
66
67     /* Replying to the agent. */
68     snprintf(msg_ack, OS_FLSIZE, "%s%s", CONTROL_HEADER, HC_ACK);
69     send_msg(agentid, msg_ack);
70
71
72     /* Checking if there is a keep alive already for this agent. */
73     if(_keep_alive[agentid] && _msg[agentid] &&
74        (strcmp(_msg[agentid], r_msg) == 0))
75     {
76         utimes(_keep_alive[agentid], NULL);
77     }
78
79     else if(strcmp(r_msg, HC_STARTUP) == 0)
80     {
81         return;
82     }
83
84     else
85     {
86         FILE *fp;
87         char *uname = r_msg;
88         char *random_leftovers;
89
90
91         /* locking mutex. */
92         if(pthread_mutex_lock(&lastmsg_mutex) != 0)
93         {
94             merror(MUTEX_ERROR, ARGV0);
95             return;
96         }
97
98
99         /* Update rmsg. */
100         if(_msg[agentid])
101         {
102             free(_msg[agentid]);
103         }
104         os_strdup(r_msg, _msg[agentid]);
105
106
107         /* Unlocking mutex. */
108         if(pthread_mutex_unlock(&lastmsg_mutex) != 0)
109         {
110             merror(MUTEX_ERROR, ARGV0);
111             return;
112         }
113
114
115         r_msg = strchr(r_msg, '\n');
116         if(!r_msg)
117         {
118             merror("%s: WARN: Invalid message from agent id: '%d'(uname)",
119                     ARGV0,
120                     agentid);
121             return;
122         }
123
124
125         *r_msg = '\0';
126         random_leftovers = strchr(r_msg, '\n');
127         if(random_leftovers)
128         {
129             *random_leftovers = '\0';
130         }
131
132
133         /* Updating the keep alive. */
134         if(!_keep_alive[agentid])
135         {
136             char agent_file[OS_SIZE_1024 +1];
137             agent_file[OS_SIZE_1024] = '\0';
138
139             /* Writting to the agent file */
140             snprintf(agent_file, OS_SIZE_1024, "%s/%s-%s",
141                     AGENTINFO_DIR,
142                     keys.keyentries[agentid]->name,
143                     keys.keyentries[agentid]->ip->ip);
144
145             os_strdup(agent_file, _keep_alive[agentid]);
146         }
147
148
149         /* Writing to the file. */
150         fp = fopen(_keep_alive[agentid], "w");
151         if(fp)
152         {
153             fprintf(fp, "%s\n", uname);
154             fclose(fp);
155         }
156     }
157
158
159     /* Locking now to notify of change.  */
160     if(pthread_mutex_lock(&lastmsg_mutex) != 0)
161     {
162         merror(MUTEX_ERROR, ARGV0);
163         return;
164     }
165
166
167     /* Assign new values */
168     _changed[agentid] = 1;
169     modified_agentid = agentid;
170
171
172     /* Signal that new data is available */
173     pthread_cond_signal(&awake_mutex);
174
175
176     /* Unlocking mutex */
177     if(pthread_mutex_unlock(&lastmsg_mutex) != 0)
178     {
179         merror(MUTEX_ERROR, ARGV0);
180         return;
181     }
182
183
184     return;
185 }
186
187
188
189 /* f_files: Free the files memory
190  */
191 void f_files()
192 {
193     int i;
194     if(!f_sum)
195         return;
196     for(i = 0;;i++)
197     {
198         if(f_sum[i] == NULL)
199             break;
200
201         if(f_sum[i]->name)
202             free(f_sum[i]->name);
203
204         free(f_sum[i]);
205         f_sum[i] = NULL;
206     }
207
208     free(f_sum);
209     f_sum = NULL;
210 }
211
212
213
214 /* c_files: Create the structure with the files and checksums
215  * Returns void
216  */
217 void c_files()
218 {
219     DIR *dp;
220
221     struct dirent *entry;
222
223     os_md5 md5sum;
224
225     int f_size = 0;
226
227
228     f_sum = NULL;
229
230
231     /* Creating merged file. */
232     os_realloc(f_sum, (f_size +2) * sizeof(file_sum *), f_sum);
233     os_calloc(1, sizeof(file_sum), f_sum[f_size]);
234     f_sum[f_size]->mark = 0;
235     f_sum[f_size]->name = NULL;
236     f_sum[f_size]->sum[0] = '\0';
237     MergeAppendFile(SHAREDCFG_FILE, NULL);
238     f_size++;
239
240
241
242     /* Opening the directory given */
243     dp = opendir(SHAREDCFG_DIR);
244     if(!dp)
245     {
246         merror("%s: Error opening directory: '%s': %s ",
247                 ARGV0,
248                 SHAREDCFG_DIR,
249                 strerror(errno));
250         return;
251     }
252
253
254     /* Reading directory */
255     while((entry = readdir(dp)) != NULL)
256     {
257         char tmp_dir[512];
258
259         /* Just ignore . and ..  */
260         if((strcmp(entry->d_name,".") == 0) ||
261            (strcmp(entry->d_name,"..") == 0))
262         {
263             continue;
264         }
265
266         snprintf(tmp_dir, 512, "%s/%s", SHAREDCFG_DIR, entry->d_name);
267
268
269         /* Leaving the shared config file for later. */
270         if(strcmp(tmp_dir, SHAREDCFG_FILE) == 0)
271         {
272             continue;
273         }
274
275
276         if(OS_MD5_File(tmp_dir, md5sum) != 0)
277         {
278             merror("%s: Error accessing file '%s'",ARGV0, tmp_dir);
279             continue;
280         }
281
282
283         f_sum = (file_sum **)realloc(f_sum, (f_size +2) * sizeof(file_sum *));
284         if(!f_sum)
285         {
286             ErrorExit(MEM_ERROR,ARGV0);
287         }
288
289         f_sum[f_size] = calloc(1, sizeof(file_sum));
290         if(!f_sum[f_size])
291         {
292             ErrorExit(MEM_ERROR,ARGV0);
293         }
294
295
296         strncpy(f_sum[f_size]->sum, md5sum, 32);
297         os_strdup(entry->d_name, f_sum[f_size]->name);
298         f_sum[f_size]->mark = 0;
299
300
301         MergeAppendFile(SHAREDCFG_FILE, tmp_dir);
302         f_size++;
303     }
304
305     if(f_sum != NULL)
306         f_sum[f_size] = NULL;
307
308     closedir(dp);
309
310
311     if(OS_MD5_File(SHAREDCFG_FILE, md5sum) != 0)
312     {
313         merror("%s: Error accessing file '%s'",ARGV0, SHAREDCFG_FILE);
314         f_sum[0]->sum[0] = '\0';
315     }
316     strncpy(f_sum[0]->sum, md5sum, 32);
317
318
319     os_strdup(SHAREDCFG_FILENAME, f_sum[0]->name);
320
321     return;
322 }
323
324
325
326 /* send_file_toagent: Sends a file to the agent.
327  * Returns -1 on error
328  */
329 int send_file_toagent(int agentid, char *name, char *sum)
330 {
331     int i = 0, n = 0;
332     char file[OS_SIZE_1024 +1];
333     char buf[OS_SIZE_1024 +1];
334
335     FILE *fp;
336
337
338     snprintf(file, OS_SIZE_1024, "%s/%s",SHAREDCFG_DIR, name);
339     fp = fopen(file, "r");
340     if(!fp)
341     {
342         merror(FOPEN_ERROR, ARGV0, file);
343         return(-1);
344     }
345
346
347     /* Sending the file name first */
348     snprintf(buf, OS_SIZE_1024, "%s%s%s %s\n",
349                              CONTROL_HEADER, FILE_UPDATE_HEADER, sum, name);
350
351     if(send_msg(agentid, buf) == -1)
352     {
353         merror(SEC_ERROR,ARGV0);
354         fclose(fp);
355         return(-1);
356     }
357
358
359     /* Sending the file content */
360     while((n = fread(buf, 1, 900, fp)) > 0)
361     {
362         buf[n] = '\0';
363
364         if(send_msg(agentid, buf) == -1)
365         {
366             merror(SEC_ERROR,ARGV0);
367             fclose(fp);
368             return(-1);
369         }
370
371         /* Sleep 1 every 30 messages -- no flood */
372         if(i > 30)
373         {
374             sleep(1);
375             i = 0;
376         }
377         i++;
378     }
379
380
381     /* Sending the message to close the file */
382     snprintf(buf, OS_SIZE_1024, "%s%s", CONTROL_HEADER, FILE_CLOSE_HEADER);
383     if(send_msg(agentid, buf) == -1)
384     {
385         merror(SEC_ERROR,ARGV0);
386         fclose(fp);
387         return(-1);
388     }
389
390
391     fclose(fp);
392
393     return(0);
394 }
395
396
397
398 /** void read_contromsg(int agentid, char *msg) v0.2.
399  * Reads the available control message from
400  * the agent.
401  */
402 void read_controlmsg(int agentid, char *msg)
403 {
404     int i;
405
406
407     /* Remove uname */
408     msg = strchr(msg,'\n');
409     if(!msg)
410     {
411         merror("%s: Invalid message from '%d' (uname)",ARGV0, agentid);
412         return;
413     }
414
415
416     *msg = '\0';
417     msg++;
418
419
420     if(!f_sum)
421     {
422         /* Nothing to share with agent */
423         return;
424     }
425
426
427     /* Parse message */
428     while(*msg != '\0')
429     {
430         char *md5;
431         char *file;
432
433         md5 = msg;
434         file = msg;
435
436         msg = strchr(msg, '\n');
437         if(!msg)
438         {
439             merror("%s: Invalid message from '%s' (strchr \\n)",
440                         ARGV0,
441                         keys.keyentries[agentid]->ip->ip);
442             break;
443         }
444
445         *msg = '\0';
446         msg++;
447
448         file = strchr(file, ' ');
449         if(!file)
450         {
451             merror("%s: Invalid message from '%s' (strchr ' ')",
452                         ARGV0,
453                         keys.keyentries[agentid]->ip->ip);
454             break;
455         }
456
457         *file = '\0';
458         file++;
459
460
461         /* New agents only have merged.mg. */
462         if(strcmp(file, SHAREDCFG_FILENAME) == 0)
463         {
464             if(strcmp(f_sum[0]->sum, md5) != 0)
465             {
466                 debug1("%s: DEBUG Sending file '%s' to agent.", ARGV0,
467                        f_sum[0]->name);
468                 if(send_file_toagent(agentid,f_sum[0]->name,f_sum[0]->sum)<0)
469                 {
470                     merror("%s: ERROR: Unable to send file '%s' to agent.",
471                             ARGV0,
472                             f_sum[0]->name);
473                 }
474             }
475
476             i = 0;
477             while(f_sum[i])
478             {
479                 f_sum[i]->mark = 0;
480                 i++;
481             }
482
483             return;
484         }
485
486
487         for(i = 1;;i++)
488         {
489             if(f_sum[i] == NULL)
490                 break;
491
492             else if(strcmp(f_sum[i]->name, file) != 0)
493                 continue;
494
495             else if(strcmp(f_sum[i]->sum, md5) != 0)
496                 f_sum[i]->mark = 1; /* Marked to update */
497
498             else
499             {
500                 f_sum[i]->mark = 2;
501             }
502             break;
503         }
504     }
505
506
507     /* Updating each file marked */
508     for(i = 1;;i++)
509     {
510         if(f_sum[i] == NULL)
511             break;
512
513         if((f_sum[i]->mark == 1) ||
514            (f_sum[i]->mark == 0))
515         {
516
517             debug1("%s: Sending file '%s' to agent.", ARGV0, f_sum[i]->name);
518             if(send_file_toagent(agentid,f_sum[i]->name,f_sum[i]->sum) < 0)
519             {
520                 merror("%s: Error sending file '%s' to agent.",
521                         ARGV0,
522                         f_sum[i]->name);
523             }
524         }
525
526         f_sum[i]->mark = 0;
527     }
528
529
530     return;
531 }
532
533
534
535 /** void *wait_for_msgs(void *none) v0.1
536  * Wait for new messages to read.
537  * The messages are going to be sent from save_controlmsg.
538  */
539 void *wait_for_msgs(void *none)
540 {
541     int id, i;
542     char msg[OS_SIZE_1024 +2];
543
544
545     /* Initializing the memory */
546     memset(msg, '\0', OS_SIZE_1024 +2);
547
548
549     /* should never leave this loop */
550     while(1)
551     {
552         /* Every NOTIFY * 30 minutes, re read the files.
553          * If something changed, notify all agents
554          */
555         _ctime = time(0);
556         if((_ctime - _stime) > (NOTIFY_TIME*30))
557         {
558             f_files();
559             c_files();
560
561             _stime = _ctime;
562         }
563
564
565         /* locking mutex */
566         if(pthread_mutex_lock(&lastmsg_mutex) != 0)
567         {
568             merror(MUTEX_ERROR, ARGV0);
569             return(NULL);
570         }
571
572         /* If no agent changed, wait for signal */
573         if(modified_agentid == -1)
574         {
575             pthread_cond_wait(&awake_mutex, &lastmsg_mutex);
576         }
577
578         /* Unlocking mutex */
579         if(pthread_mutex_unlock(&lastmsg_mutex) != 0)
580         {
581             merror(MUTEX_ERROR, ARGV0);
582             return(NULL);
583         }
584
585
586         /* Checking if any agent is ready */
587         for(i = 0;i<keys.keysize; i++)
588         {
589             /* If agent wasn't changed, try next */
590             if(_changed[i] != 1)
591             {
592                 continue;
593             }
594
595             id = 0;
596
597             /* locking mutex */
598             if(pthread_mutex_lock(&lastmsg_mutex) != 0)
599             {
600                 merror(MUTEX_ERROR, ARGV0);
601                 break;
602             }
603
604             if(_msg[i])
605             {
606                 /* Copying the message to be analyzed */
607                 strncpy(msg, _msg[i], OS_SIZE_1024);
608                 _changed[i] = 0;
609
610                 if(modified_agentid >= i)
611                 {
612                     modified_agentid = -1;
613                 }
614
615                 id = 1;
616             }
617
618             /* Unlocking mutex */
619             if(pthread_mutex_unlock(&lastmsg_mutex) != 0)
620             {
621                 merror(MUTEX_ERROR, ARGV0);
622                 break;
623             }
624
625             if(id)
626             {
627                 read_controlmsg(i, msg);
628             }
629         }
630     }
631
632     return(NULL);
633 }
634
635
636
637 /* manager_init: Should be called before anything here */
638 void manager_init(int isUpdate)
639 {
640     int i;
641     _stime = time(0);
642
643     f_files();
644     c_files();
645
646     debug1("%s: DEBUG: Running manager_init", ARGV0);
647
648     for(i=0; i<MAX_AGENTS +1; i++)
649     {
650         _keep_alive[i] = NULL;
651         _msg[i] = NULL;
652         _changed[i] = 0;
653     }
654
655     /* Initializing mutexes */
656     if(isUpdate == 0)
657     {
658         pthread_mutex_init(&lastmsg_mutex, NULL);
659         pthread_cond_init(&awake_mutex, NULL);
660     }
661
662     modified_agentid = -1;
663
664     return;
665 }
666
667
668
669 /* EOF */