0f6501a7af52c2077ef87a51573f55e7a80b8917
[ossec-hids.git] / src / os_maild / maild.c
1 /* @(#) $Id$ */
2
3 /* Copyright (C) 2009 Trend Micro Inc.
4  * All rights 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  * License details at the LICENSE file included with OSSEC or 
12  * online at: http://www.ossec.net/en/licensing.html
13  */
14
15
16 #ifndef MAILD
17    #define MAILD
18 #endif
19
20 #ifndef ARGV0
21    #define ARGV0 "ossec-maild"
22 #endif
23
24 #include "shared.h"
25 #include "maild.h"
26 #include "mail_list.h"
27
28
29 void OS_Run(MailConfig *mail);
30
31 int main(int argc, char **argv)
32 {
33     int c, test_config = 0,run_foreground = 0;
34     int uid = 0,gid = 0;
35     char *dir  = DEFAULTDIR;
36     char *user = MAILUSER;
37     char *group = GROUPGLOBAL;
38     char *cfg = DEFAULTCPATH;
39
40     /* Mail Structure */
41     MailConfig mail;
42
43
44     /* Setting the name */
45     OS_SetName(ARGV0);
46         
47
48     while((c = getopt(argc, argv, "Vdhtfu:g:D:c:")) != -1){
49         switch(c){
50             case 'V':
51                 print_version();
52                 break;
53             case 'h':
54                 help(ARGV0);
55                 break;
56             case 'd':
57                 nowDebug();
58                 break;
59             case 'f':
60                 run_foreground = 1;
61                 break;
62             case 'u':
63                 if(!optarg)
64                     ErrorExit("%s: -u needs an argument",ARGV0);
65                 user=optarg;
66                 break;
67             case 'g':
68                 if(!optarg)
69                     ErrorExit("%s: -g needs an argument",ARGV0);
70                 group=optarg;
71                 break;
72             case 'D':
73                 if(!optarg)
74                     ErrorExit("%s: -D needs an argument",ARGV0);
75                 dir=optarg;
76             case 'c':
77                 if(!optarg)
78                     ErrorExit("%s: -c needs an argument",ARGV0);
79                 cfg = optarg;
80                 break;
81             case 't':
82                 test_config = 1;    
83                 break;
84             default:
85                 help(ARGV0);
86                 break;
87         }
88
89     }
90
91     /* Starting daemon */
92     debug1(STARTED_MSG,ARGV0);
93
94     /*Check if the user/group given are valid */
95     uid = Privsep_GetUser(user);
96     gid = Privsep_GetGroup(group);
97     if((uid < 0)||(gid < 0))
98         ErrorExit(USER_ERROR,ARGV0,user,group);
99
100
101     /* Reading configuration */
102     if(MailConf(test_config, cfg, &mail) < 0)
103         ErrorExit(CONFIG_ERROR, ARGV0, cfg);
104
105
106     /* Reading internal options */
107     mail.strict_checking = getDefine_Int("maild",
108                                          "strict_checking",
109                                           0, 1);
110     
111     /* Get groupping */
112     mail.groupping = getDefine_Int("maild",
113                                    "groupping",
114                                     0, 1);
115     
116     /* Getting subject type */
117     mail.subject_full = getDefine_Int("maild",
118                                       "full_subject",
119                                       0, 1);
120     
121     
122     /* Exit here if test config is set */
123     if(test_config)
124         exit(0);
125
126         
127     if(!run_foreground) 
128     {
129         nowDaemon();
130         goDaemon();
131     }
132
133     
134     /* Privilege separation */  
135     if(Privsep_SetGroup(gid) < 0)
136         ErrorExit(SETGID_ERROR,ARGV0,group);
137
138     
139     /* chrooting */
140     if(Privsep_Chroot(dir) < 0)
141         ErrorExit(CHROOT_ERROR,ARGV0,dir);
142
143     nowChroot();
144
145
146     
147     /* Changing user */        
148     if(Privsep_SetUser(uid) < 0)
149         ErrorExit(SETUID_ERROR,ARGV0,user);
150
151
152     debug1(PRIVSEP_MSG,ARGV0,dir,user);
153
154
155
156     /* Signal manipulation */
157     StartSIG(ARGV0);
158
159     
160
161     /* Creating PID files */
162     if(CreatePID(ARGV0, getpid()) < 0)
163         ErrorExit(PID_ERROR, ARGV0);
164
165     
166     /* Start up message */
167     verbose(STARTUP_MSG, ARGV0, (int)getpid());
168     
169
170     /* the real daemon now */   
171     OS_Run(&mail);
172     exit(0);
173 }
174
175
176 /* OS_Run: Read the queue and send the appropriate alerts.
177  * not supposed to return..
178  */
179 void OS_Run(MailConfig *mail)
180 {
181     MailMsg *msg;
182     MailMsg *s_msg = NULL;
183     MailMsg *msg_sms = NULL;
184
185     time_t tm;     
186     struct tm *p;       
187
188     int i = 0;
189     int mailtosend = 0;
190     int childcount = 0;
191     int today = 0;                      
192     int thishour = 0;
193
194     int n_errs = 0;
195
196     file_queue *fileq;
197
198
199     /* Getting currently time before starting */
200     tm = time(NULL);
201     p = localtime(&tm); 
202     today = p->tm_mday;
203     thishour = p->tm_hour;
204
205
206     /* Init file queue */
207     i = 0;
208     i |= CRALERT_MAIL_SET;
209     os_calloc(1, sizeof(file_queue), fileq);
210     Init_FileQueue(fileq, p, i);
211
212
213     /* Creating the list */
214     OS_CreateMailList(MAIL_LIST_SIZE);    
215     
216  
217     /* Setting default timeout */
218     mail_timeout = DEFAULT_TIMEOUT;
219
220     
221     /* Clearing global vars */
222     _g_subject_level = 0;
223     memset(_g_subject, '\0', SUBJECT_SIZE +2);
224
225
226     while(1)
227     {
228         tm = time(NULL);
229         p = localtime(&tm);
230
231         
232         /* SMS messages are sent without delay */
233         if(msg_sms)
234         {
235             pid_t pid;
236             
237             pid = fork();
238             
239             if(pid < 0)
240             {
241                 merror("%s: Fork failed. cause: %d - %s", ARGV0, errno, strerror(errno));
242                 merror(FORK_ERROR, ARGV0);
243                 sleep(30);
244                 continue;
245             }
246             else if (pid == 0)
247             {
248                 if(OS_Sendsms(mail, p, msg_sms) < 0)
249                     merror(SNDMAIL_ERROR, ARGV0, mail->smtpserver);
250
251                 exit(0);
252             }
253
254
255             /* Freeing sms structure */
256             FreeMailMsg(msg_sms);
257             msg_sms = NULL;
258
259
260             /* Increasing child count */
261             childcount++;
262         }
263         
264
265         /* If mail_timeout == NEXTMAIL_TIMEOUT, we will try to get
266          * more messages, before sending anything
267          */
268         if((mail_timeout == NEXTMAIL_TIMEOUT) && (p->tm_hour == thishour))
269         {
270             /* getting more messages */
271         }
272         
273         
274         /* Hour changed. Send all supressed mails */ 
275         else if(((mailtosend < mail->maxperhour) && (mailtosend != 0))||
276                 ((p->tm_hour != thishour) && (childcount < MAXCHILDPROCESS)))
277         {
278             MailNode *mailmsg;
279             pid_t pid;
280
281             /* Checking if we have anything to sent */
282             mailmsg = OS_CheckLastMail();
283             if(mailmsg == NULL)
284             {
285                 /* dont fork in here */
286                 goto snd_check_hour;
287             }
288
289             pid = fork();
290             if(pid < 0)
291             {
292                 merror("%s: Fork failed. cause: %d - %s", ARGV0, errno, strerror(errno));
293                 merror(FORK_ERROR, ARGV0);
294                 sleep(30);
295                 continue;
296             }
297             else if (pid == 0)
298             {
299                 if(OS_Sendmail(mail, p) < 0)
300                     merror(SNDMAIL_ERROR,ARGV0,mail->smtpserver);
301                 
302                 exit(0);    
303             }
304           
305             /* Cleaning the memory */
306             mailmsg = OS_PopLastMail(); 
307             do
308             {
309                 FreeMail(mailmsg); 
310                 mailmsg = OS_PopLastMail();
311             }while(mailmsg);
312     
313     
314             /* Increasing child count */        
315             childcount++; 
316
317
318             /* Clearing global vars */
319             _g_subject[0] = '\0';
320             _g_subject[SUBJECT_SIZE -1] = '\0';
321             _g_subject_level = 0;
322             
323            
324             /* Cleaning up set values */
325             if(mail->gran_to)
326             {
327                 i = 0;
328                 while(mail->gran_to[i] != NULL)
329                 {
330                     if(s_msg && mail->gran_set[i] == DONOTGROUP)
331                     {
332                         mail->gran_set[i] = FULL_FORMAT;
333                     }
334                     else
335                     {
336                         mail->gran_set[i] = 0;
337                     }
338                     i++;
339                 }
340             }
341
342             snd_check_hour:
343             /* If we sent everything */
344             if(p->tm_hour != thishour)
345             {
346                 thishour = p->tm_hour;    
347
348                 mailtosend = 0;
349             }
350         }
351         
352         /* Saved message for the do_not_group option.
353          */
354         if(s_msg)
355         {
356             /* We need to set the remaining do no group to
357              * full format.
358              */
359             if(mail->gran_to)
360             {
361                 i = 0;
362                 while(mail->gran_to[i] != NULL)
363                 {
364                     if(mail->gran_set[i] == DONOTGROUP)
365                     {
366                         mail->gran_set[i] = FULL_FORMAT;
367                     }
368                     i++;
369                 }
370             }
371             
372             OS_AddMailtoList(s_msg);
373
374             s_msg = NULL;
375             mailtosend++;
376             continue;
377         }
378         
379         
380         /* Receive message from queue */
381         if((msg = OS_RecvMailQ(fileq, p, mail, &msg_sms)) != NULL)
382         {
383             /* If the e-mail priority is do_not_group, we first will
384              * flush all previous entries and then send it.
385              * We use s_msg to hold the pointer to the message
386              * while we flush it.
387              */
388             if(mail->priority == DONOTGROUP)
389             {
390                 s_msg = msg;
391             }
392             else
393             {
394                 OS_AddMailtoList(msg);
395             }
396             
397
398             /* Change timeout to see if any new message is coming shortly */
399             if(mail->groupping)
400             {
401                 /* If priority is set, send email now */
402                 if(mail->priority)
403                 {
404                     mail_timeout = DEFAULT_TIMEOUT;
405
406                     /* If do_not_group is set, we do not increase the
407                      * list count in here.
408                      */
409                     if(mail->priority != DONOTGROUP)
410                     {
411                         mailtosend++;
412                     }
413                 }
414                 else
415                 {
416                     /* 5 seconds only */
417                     mail_timeout = NEXTMAIL_TIMEOUT;
418                 }
419             }
420             else
421             {
422                 /* Send message by itself */
423                 mailtosend++;
424             }
425         }
426         else
427         {
428             if(mail_timeout == NEXTMAIL_TIMEOUT)
429             {
430                 mailtosend++;
431
432                 /* Default timeout */
433                 mail_timeout = DEFAULT_TIMEOUT;
434             }
435         }
436
437
438         /* Waiting for the childs .. */
439         while (childcount) 
440         {
441             int wp;
442             int p_status;
443             wp = waitpid((pid_t) -1, &p_status, WNOHANG);
444             if (wp < 0)
445             {
446                 merror(WAITPID_ERROR, ARGV0);  
447                 n_errs++;
448             }
449
450             /* if = 0, we still need to wait for the child process */    
451             else if (wp == 0) 
452                 break;
453             else
454             {
455                 if(p_status != 0)
456                 {
457                     merror(SNDMAIL_ERROR,ARGV0,mail->smtpserver);
458                     n_errs++;
459                 }
460                 childcount--;
461             }
462
463             /* Too many errors */
464             if(n_errs > 6)
465             {
466                 merror(SNDMAIL_ERROR,ARGV0,mail->smtpserver);
467                 exit(1);
468             }
469         }
470             
471     }
472 }
473
474 /* EOF */