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