izmjene licence
[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 thishour = 0;
199
200     int n_errs = 0;
201
202     file_queue *fileq;
203
204
205     /* Getting currently time before starting */
206     tm = time(NULL);
207     p = localtime(&tm);
208     thishour = p->tm_hour;
209
210
211     /* Init file queue */
212     i = 0;
213     i |= CRALERT_MAIL_SET;
214     os_calloc(1, sizeof(file_queue), fileq);
215     Init_FileQueue(fileq, p, i);
216
217
218     /* Creating the list */
219     OS_CreateMailList(MAIL_LIST_SIZE);
220
221
222     /* Setting default timeout */
223     mail_timeout = DEFAULT_TIMEOUT;
224
225
226     /* Clearing global vars */
227     _g_subject_level = 0;
228     memset(_g_subject, '\0', SUBJECT_SIZE +2);
229
230
231     while(1)
232     {
233         tm = time(NULL);
234         p = localtime(&tm);
235
236
237         /* SMS messages are sent without delay */
238         if(msg_sms)
239         {
240             pid_t pid;
241
242             pid = fork();
243
244             if(pid < 0)
245             {
246                 merror("%s: Fork failed. cause: %d - %s", ARGV0, errno, strerror(errno));
247                 merror(FORK_ERROR, ARGV0);
248                 sleep(30);
249                 continue;
250             }
251             else if (pid == 0)
252             {
253                 if(OS_Sendsms(mail, p, msg_sms) < 0)
254                     merror(SNDMAIL_ERROR, ARGV0, mail->smtpserver);
255
256                 exit(0);
257             }
258
259
260             /* Freeing sms structure */
261             FreeMailMsg(msg_sms);
262             msg_sms = NULL;
263
264
265             /* Increasing child count */
266             childcount++;
267         }
268
269
270         /* If mail_timeout == NEXTMAIL_TIMEOUT, we will try to get
271          * more messages, before sending anything
272          */
273         if((mail_timeout == NEXTMAIL_TIMEOUT) && (p->tm_hour == thishour))
274         {
275             /* getting more messages */
276         }
277
278
279         /* Hour changed. Send all supressed mails */
280         else if(((mailtosend < mail->maxperhour) && (mailtosend != 0))||
281                 ((p->tm_hour != thishour) && (childcount < MAXCHILDPROCESS)))
282         {
283             MailNode *mailmsg;
284             pid_t pid;
285
286             /* Checking if we have anything to sent */
287             mailmsg = OS_CheckLastMail();
288             if(mailmsg == NULL)
289             {
290                 /* dont fork in here */
291                 goto snd_check_hour;
292             }
293
294             pid = fork();
295             if(pid < 0)
296             {
297                 merror("%s: Fork failed. cause: %d - %s", ARGV0, errno, strerror(errno));
298                 merror(FORK_ERROR, ARGV0);
299                 sleep(30);
300                 continue;
301             }
302             else if (pid == 0)
303             {
304                 if(OS_Sendmail(mail, p) < 0)
305                     merror(SNDMAIL_ERROR,ARGV0,mail->smtpserver);
306
307                 exit(0);
308             }
309
310             /* Cleaning the memory */
311             mailmsg = OS_PopLastMail();
312             do
313             {
314                 FreeMail(mailmsg);
315                 mailmsg = OS_PopLastMail();
316             }while(mailmsg);
317
318
319             /* Increasing child count */
320             childcount++;
321
322
323             /* Clearing global vars */
324             _g_subject[0] = '\0';
325             _g_subject[SUBJECT_SIZE -1] = '\0';
326             _g_subject_level = 0;
327
328
329             /* Cleaning up set values */
330             if(mail->gran_to)
331             {
332                 i = 0;
333                 while(mail->gran_to[i] != NULL)
334                 {
335                     if(s_msg && mail->gran_set[i] == DONOTGROUP)
336                     {
337                         mail->gran_set[i] = FULL_FORMAT;
338                     }
339                     else
340                     {
341                         mail->gran_set[i] = 0;
342                     }
343                     i++;
344                 }
345             }
346
347             snd_check_hour:
348             /* If we sent everything */
349             if(p->tm_hour != thishour)
350             {
351                 thishour = p->tm_hour;
352
353                 mailtosend = 0;
354             }
355         }
356
357         /* Saved message for the do_not_group option.
358          */
359         if(s_msg)
360         {
361             /* We need to set the remaining do no group to
362              * full format.
363              */
364             if(mail->gran_to)
365             {
366                 i = 0;
367                 while(mail->gran_to[i] != NULL)
368                 {
369                     if(mail->gran_set[i] == DONOTGROUP)
370                     {
371                         mail->gran_set[i] = FULL_FORMAT;
372                     }
373                     i++;
374                 }
375             }
376
377             OS_AddMailtoList(s_msg);
378
379             s_msg = NULL;
380             mailtosend++;
381             continue;
382         }
383
384
385         /* Receive message from queue */
386         if((msg = OS_RecvMailQ(fileq, p, mail, &msg_sms)) != NULL)
387         {
388             /* If the e-mail priority is do_not_group, we first will
389              * flush all previous entries and then send it.
390              * We use s_msg to hold the pointer to the message
391              * while we flush it.
392              */
393             if(mail->priority == DONOTGROUP)
394             {
395                 s_msg = msg;
396             }
397             else
398             {
399                 OS_AddMailtoList(msg);
400             }
401
402
403             /* Change timeout to see if any new message is coming shortly */
404             if(mail->groupping)
405             {
406                 /* If priority is set, send email now */
407                 if(mail->priority)
408                 {
409                     mail_timeout = DEFAULT_TIMEOUT;
410
411                     /* If do_not_group is set, we do not increase the
412                      * list count in here.
413                      */
414                     if(mail->priority != DONOTGROUP)
415                     {
416                         mailtosend++;
417                     }
418                 }
419                 else
420                 {
421                     /* 5 seconds only */
422                     mail_timeout = NEXTMAIL_TIMEOUT;
423                 }
424             }
425             else
426             {
427                 /* Send message by itself */
428                 mailtosend++;
429             }
430         }
431         else
432         {
433             if(mail_timeout == NEXTMAIL_TIMEOUT)
434             {
435                 mailtosend++;
436
437                 /* Default timeout */
438                 mail_timeout = DEFAULT_TIMEOUT;
439             }
440         }
441
442
443         /* Waiting for the childs .. */
444         while (childcount)
445         {
446             int wp;
447             int p_status;
448             wp = waitpid((pid_t) -1, &p_status, WNOHANG);
449             if (wp < 0)
450             {
451                 merror(WAITPID_ERROR, ARGV0);
452                 n_errs++;
453             }
454
455             /* if = 0, we still need to wait for the child process */
456             else if (wp == 0)
457                 break;
458             else
459             {
460                 if(p_status != 0)
461                 {
462                     merror(CHLDWAIT_ERROR,ARGV0,p_status);
463                     merror(SNDMAIL_ERROR,ARGV0,mail->smtpserver);
464                     n_errs++;
465                 }
466                 childcount--;
467             }
468
469             /* Too many errors */
470             if(n_errs > 6)
471             {
472                 merror(TOOMANY_WAIT_ERROR,ARGV0);
473                 merror(SNDMAIL_ERROR,ARGV0,mail->smtpserver);
474                 exit(1);
475             }
476         }
477
478     }
479 }
480
481 /* EOF */