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