Imported Upstream version 2.5.1
[ossec-hids.git] / src / os_maild / sendmail.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
12
13 /* Basic e-mailing operations */
14
15
16 #include "shared.h"
17 #include "os_net/os_net.h"
18 #include "maild.h"
19 #include "mail_list.h"
20
21
22 /* Return codes (from SMTP server) */
23 #define VALIDBANNER             "220"
24 #define VALIDMAIL               "250"
25 #define VALIDDATA               "354"
26
27
28 /* Default values use to connect */
29 #define SMTP_DEFAULT_PORT       25
30 #define HELOMSG                 "Helo notify.ossec.net\r\n"
31 #define MAILFROM                "Mail From: <%s>\r\n"
32 #define RCPTTO                  "Rcpt To: <%s>\r\n"
33 #define DATAMSG                 "DATA\r\n"
34 #define FROM                    "From: OSSEC HIDS <%s>\r\n"
35 #define TO                          "To: <%s>\r\n"
36 #define CC                          "Cc: <%s>\r\n"
37 #define SUBJECT                 "Subject: %s\r\n"
38 #define ENDDATA                 "\r\n.\r\n"
39 #define QUITMSG                 "QUIT\r\n"
40
41
42 /* Error messages - Can be translated */
43 #define INTERNAL_ERROR  "os_maild (1760): ERROR: Memory/configuration error"
44 #define BANNER_ERROR    "os_sendmail(1762): WARN: Banner not received from server"
45 #define HELO_ERROR          "os_sendmail(1763): WARN: Hello not accepted by server"
46 #define FROM_ERROR          "os_sendmail(1764): WARN: Mail from not accepted by server"
47 #define TO_ERROR            "os_sendmail(1765): WARN: RCPT TO not accepted by server - '%s'."
48 #define DATA_ERROR          "os_sendmail(1766): WARN: DATA not accepted by server"
49 #define END_DATA_ERROR  "os_sendmail(1767): WARN: End of DATA not accepted by server"
50
51
52 #define MAIL_DEBUG_FLAG     0
53 #define MAIL_DEBUG(x,y,z) if(MAIL_DEBUG_FLAG) merror(x,y,z)
54
55
56 /* OS_Sendsms.
57  */
58 int OS_Sendsms(MailConfig *mail, struct tm *p, MailMsg *sms_msg)
59 {
60     int socket, i = 0, final_to_sz;
61     char *msg;
62     char snd_msg[128];
63     char final_to[512];
64
65
66     /* Connecting to the smtp server */ 
67     socket = OS_ConnectTCP(SMTP_DEFAULT_PORT, mail->smtpserver);
68     if(socket < 0)
69     {
70         return(socket);
71     }
72
73
74     /* Receiving the banner */
75     msg = OS_RecvTCP(socket, OS_SIZE_1024);
76     if((msg == NULL)||(!OS_Match(VALIDBANNER, msg)))
77     {
78         merror(BANNER_ERROR);
79         if(msg)
80             free(msg);
81         close(socket);
82         return(OS_INVALID);     
83     }
84     MAIL_DEBUG("DEBUG: Received banner: '%s' %s", msg, "");
85     free(msg);
86
87
88
89     /* Sending HELO message */
90     OS_SendTCP(socket,HELOMSG);
91     msg = OS_RecvTCP(socket, OS_SIZE_1024);
92     if((msg == NULL)||(!OS_Match(VALIDMAIL, msg)))
93     {
94         if(msg)
95         {
96             /* Ugly fix warning :) */
97             /* In some cases (with virus scans in the middle)
98              * we may get two banners. Check for that in here.
99              */
100             if(OS_Match(VALIDBANNER, msg))
101             {
102                 free(msg);
103
104                 /* Try again */
105                 msg = OS_RecvTCP(socket, OS_SIZE_1024);
106                 if((msg == NULL)||(!OS_Match(VALIDMAIL, msg)))
107                 {
108                     merror("%s:%s",HELO_ERROR,msg!= NULL?msg:"null");
109                     if(msg)
110                         free(msg);
111                     close(socket);
112                     return(OS_INVALID);    
113                 }
114             }
115             else
116             {
117                 merror("%s:%s",HELO_ERROR,msg);
118                 free(msg);
119                 close(socket);
120                 return(OS_INVALID);
121             }
122         }
123         else
124         {
125             merror("%s:%s",HELO_ERROR,"null");
126             close(socket);
127             return(OS_INVALID);
128         }
129     }
130
131     MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", HELOMSG, msg);
132     free(msg);  
133
134
135     /* Building "Mail from" msg */
136     memset(snd_msg,'\0',128);
137     snprintf(snd_msg,127, MAILFROM, mail->from);
138     OS_SendTCP(socket, snd_msg);
139     msg = OS_RecvTCP(socket, OS_SIZE_1024);
140     if((msg == NULL)||(!OS_Match(VALIDMAIL, msg)))
141     {
142         merror(FROM_ERROR);
143         if(msg)
144             free(msg);
145         close(socket);
146         return(OS_INVALID);     
147     }
148     MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg);
149     free(msg);  
150
151
152     /* Additional RCPT to */
153     final_to[0] = '\0';
154     final_to_sz = sizeof(final_to) -2;
155     
156     if(mail->gran_to)
157     {
158         i = 0;
159         while(mail->gran_to[i] != NULL)
160         {
161             if(mail->gran_set[i] != SMS_FORMAT)
162             {
163                 i++;
164                 continue;
165             }
166
167             memset(snd_msg,'\0',128);
168             snprintf(snd_msg,127, RCPTTO, mail->gran_to[i]);
169             OS_SendTCP(socket, snd_msg);
170             msg = OS_RecvTCP(socket, OS_SIZE_1024);
171             if((msg == NULL)||(!OS_Match(VALIDMAIL, msg)))
172             {
173                 merror(TO_ERROR, mail->gran_to[i]);
174                 if(msg)
175                     free(msg);
176                 close(socket);
177                 return(OS_INVALID);
178             }
179             MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg);
180             free(msg);
181
182
183             /* Creating header for to */
184             memset(snd_msg,'\0',128);
185             snprintf(snd_msg,127, TO, mail->gran_to[i]);
186             strncat(final_to, snd_msg, final_to_sz);
187             final_to_sz -= strlen(snd_msg) +2;
188             
189             i++;
190             continue;
191         }
192     }
193
194
195     /* Sending the "DATA" msg */
196     OS_SendTCP(socket,DATAMSG);
197     msg = OS_RecvTCP(socket, OS_SIZE_1024);
198     if((msg == NULL)||(!OS_Match(VALIDDATA, msg)))
199     {
200         merror(DATA_ERROR);
201         if(msg)
202             free(msg);
203         close(socket);
204         return(OS_INVALID);     
205     }
206     MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", DATAMSG, msg);
207     free(msg);
208
209
210     /* Building "From" and "To" in the e-mail header */
211     OS_SendTCP(socket, final_to);
212
213
214     memset(snd_msg,'\0',128);
215     snprintf(snd_msg,127, FROM, mail->from);
216     OS_SendTCP(socket, snd_msg);
217
218
219     /* Sending date */
220     memset(snd_msg,'\0',128);
221     
222
223     /* Solaris doesn't have the "%z", so we set the timezone to 0. */
224     #ifdef SOLARIS
225     strftime(snd_msg, 127, "Date: %a, %d %b %Y %T -0000\r\n",p);
226     #else
227     strftime(snd_msg, 127, "Date: %a, %d %b %Y %T %z\r\n",p);
228     #endif
229     
230     OS_SendTCP(socket,snd_msg);
231
232
233     /* Sending subject */
234     memset(snd_msg,'\0',128);
235     snprintf(snd_msg, 127, SUBJECT, sms_msg->subject);
236     OS_SendTCP(socket,snd_msg);
237
238
239
240     /* Sending body */
241     OS_SendTCP(socket, sms_msg->body);
242
243
244     /* Sending end of data \r\n.\r\n */
245     OS_SendTCP(socket,ENDDATA); 
246     msg = OS_RecvTCP(socket, OS_SIZE_1024);
247     if(mail->strict_checking && ((msg == NULL)||(!OS_Match(VALIDMAIL, msg))))
248     {
249         merror(END_DATA_ERROR);
250         if(msg)
251             free(msg);
252         close(socket);
253         return(OS_INVALID);     
254     }
255     /* Checking msg in here, since it may be null */
256     if(msg)
257         free(msg);
258
259
260     /* quitting and closing socket */
261     OS_SendTCP(socket,QUITMSG);
262     msg = OS_RecvTCP(socket, OS_SIZE_1024);
263
264     if(msg)
265         free(msg);
266
267     memset(snd_msg,'\0',128);   
268
269
270     /* Returning 0 (success) */
271     close(socket);
272
273     return(0);
274 }
275
276
277
278 /* OS_Sendmail v0.1: 2005/03/18
279  */
280 int OS_Sendmail(MailConfig *mail, struct tm *p)
281 {
282     int socket,i=0;
283     char *msg;
284     char snd_msg[128];
285     char additional_to[512];
286
287     MailNode *mailmsg;
288
289     additional_to[0] = '\0';
290     
291     /* If there is no sms message, we attempt to get from the
292      * email list.
293      */
294     mailmsg = OS_PopLastMail();
295
296     if(mailmsg == NULL)
297     {
298         merror("%s: No email to be sent. Inconsistent state.",ARGV0);
299     }
300     
301
302     /* Connecting to the smtp server */ 
303     socket = OS_ConnectTCP(SMTP_DEFAULT_PORT, mail->smtpserver);
304     if(socket < 0)
305     {
306         return(socket);
307     }
308
309
310     /* Receiving the banner */
311     msg = OS_RecvTCP(socket, OS_SIZE_1024);
312     if((msg == NULL)||(!OS_Match(VALIDBANNER, msg)))
313     {
314         merror(BANNER_ERROR);
315         if(msg)
316             free(msg);
317         close(socket);
318         return(OS_INVALID);     
319     }
320     MAIL_DEBUG("DEBUG: Received banner: '%s' %s", msg, "");
321     free(msg);
322
323
324
325     /* Sending HELO message */
326     OS_SendTCP(socket,HELOMSG);
327     msg = OS_RecvTCP(socket, OS_SIZE_1024);
328     if((msg == NULL)||(!OS_Match(VALIDMAIL, msg)))
329     {
330         if(msg)
331         {
332             /* Ugly fix warning :) */
333             /* In some cases (with virus scans in the middle)
334              * we may get two banners. Check for that in here.
335              */
336             if(OS_Match(VALIDBANNER, msg))
337             {
338                 free(msg);
339
340                 /* Try again */
341                 msg = OS_RecvTCP(socket, OS_SIZE_1024);
342                 if((msg == NULL)||(!OS_Match(VALIDMAIL, msg)))
343                 {
344                     merror("%s:%s",HELO_ERROR,msg!= NULL?msg:"null");
345                     if(msg)
346                         free(msg);
347                     close(socket);
348                     return(OS_INVALID);    
349                 }
350             }
351             else
352             {
353                 merror("%s:%s",HELO_ERROR,msg);
354                 free(msg);
355                 close(socket);
356                 return(OS_INVALID);
357             }
358         }
359         else
360         {
361             merror("%s:%s",HELO_ERROR,"null");
362             close(socket);
363             return(OS_INVALID);
364         }
365     }
366
367     MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", HELOMSG, msg);
368     free(msg);  
369
370
371     /* Building "Mail from" msg */
372     memset(snd_msg,'\0',128);
373     snprintf(snd_msg,127, MAILFROM, mail->from);
374     OS_SendTCP(socket, snd_msg);
375     msg = OS_RecvTCP(socket, OS_SIZE_1024);
376     if((msg == NULL)||(!OS_Match(VALIDMAIL, msg)))
377     {
378         merror(FROM_ERROR);
379         if(msg)
380             free(msg);
381         close(socket);
382         return(OS_INVALID);     
383     }
384     MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg);
385     free(msg);  
386
387
388     /* Building "RCPT TO" msg */
389     while(1)
390     {
391         if(mail->to[i] == NULL)
392         {
393             if(i == 0)
394             {
395                 merror(INTERNAL_ERROR);
396                 close(socket);
397                 return(OS_INVALID);
398             }
399             break;
400         }
401         memset(snd_msg,'\0',128);
402         snprintf(snd_msg,127,RCPTTO, mail->to[i++]);
403         OS_SendTCP(socket,snd_msg);
404         msg = OS_RecvTCP(socket, OS_SIZE_1024);
405         if((msg == NULL)||(!OS_Match(VALIDMAIL, msg)))
406         {
407             merror(TO_ERROR, mail->to[i -1]);
408             if(msg)
409                 free(msg);
410             close(socket);
411             return(OS_INVALID); 
412         }
413         MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg);
414         free(msg);
415     }
416
417
418     /* Additional RCPT to */
419     if(mail->gran_to)
420     {
421         i = 0;
422         while(mail->gran_to[i] != NULL)
423         {
424             if(mail->gran_set[i] != FULL_FORMAT)
425             {
426                 i++;
427                 continue;
428             }
429
430             memset(snd_msg,'\0',128);
431             snprintf(snd_msg,127,RCPTTO, mail->gran_to[i]);
432             OS_SendTCP(socket,snd_msg);
433             msg = OS_RecvTCP(socket, OS_SIZE_1024);
434             if((msg == NULL)||(!OS_Match(VALIDMAIL, msg)))
435             {
436                 merror(TO_ERROR, mail->gran_to[i]);
437                 if(msg)
438                     free(msg);
439
440                 i++;
441                 continue;    
442             }
443             
444             MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg);
445             free(msg);
446             i++;
447             continue;
448         }
449     }
450
451
452     /* Sending the "DATA" msg */
453     OS_SendTCP(socket,DATAMSG);
454     msg = OS_RecvTCP(socket, OS_SIZE_1024);
455     if((msg == NULL)||(!OS_Match(VALIDDATA, msg)))
456     {
457         merror(DATA_ERROR);
458         if(msg)
459             free(msg);
460         close(socket);
461         return(OS_INVALID);     
462     }
463     MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", DATAMSG, msg);
464     free(msg);
465
466
467     /* Building "From" and "To" in the e-mail header */
468     memset(snd_msg,'\0',128);
469     snprintf(snd_msg,127, TO, mail->to[0]);
470     OS_SendTCP(socket, snd_msg);
471
472     memset(snd_msg,'\0',128);
473     snprintf(snd_msg,127, FROM, mail->from);
474     OS_SendTCP(socket, snd_msg);
475
476
477     /* Adding CCs */
478     if(mail->to[1])
479     {
480         i = 1;
481         while(1)
482         {
483             if(mail->to[i] == NULL)
484             {
485                 break;
486             }
487             
488             memset(snd_msg,'\0',128);
489             snprintf(snd_msg,127, TO, mail->to[i]);
490             OS_SendTCP(socket,snd_msg);
491
492             i++;
493         }
494     }
495
496
497     /* More CCs - from granular options */
498     if(mail->gran_to)
499     {
500         i = 0;
501         while(mail->gran_to[i] != NULL)
502         {
503             if(mail->gran_set[i] != FULL_FORMAT)
504             {
505                 i++;
506                 continue;
507             }
508
509             memset(snd_msg,'\0',128);
510             snprintf(snd_msg,127, TO, mail->gran_to[i]);
511             OS_SendTCP(socket, snd_msg);
512             i++;
513             continue;
514         }
515     }
516
517
518     /* Sending date */
519     memset(snd_msg,'\0',128);
520
521
522     /* Solaris doesn't have the "%z", so we set the timezone to 0. */
523     #ifdef SOLARIS
524     strftime(snd_msg, 127, "Date: %a, %d %b %Y %T -0000\r\n",p);
525     #else
526     strftime(snd_msg, 127, "Date: %a, %d %b %Y %T %z\r\n",p);
527     #endif
528                             
529     OS_SendTCP(socket,snd_msg);
530
531
532     /* Sending subject */
533     memset(snd_msg,'\0',128);
534
535
536     /* Checking if global subject is available */
537     if((_g_subject_level != 0) && (_g_subject[0] != '\0'))
538     {
539         snprintf(snd_msg, 127, SUBJECT, _g_subject);    
540
541         /* Clearing global values */
542         _g_subject[0] = '\0';
543         _g_subject_level = 0;
544     }
545     else
546     {
547         snprintf(snd_msg, 127, SUBJECT, mailmsg->mail->subject);
548     }
549     OS_SendTCP(socket,snd_msg);
550
551
552
553     /* Sending body */
554
555     /* Sending multiple emails together if we have to */
556     do
557     {
558         OS_SendTCP(socket, mailmsg->mail->body);
559         mailmsg = OS_PopLastMail();
560     }while(mailmsg);
561
562
563     /* Sending end of data \r\n.\r\n */
564     OS_SendTCP(socket,ENDDATA); 
565     msg = OS_RecvTCP(socket, OS_SIZE_1024);
566     if(mail->strict_checking && ((msg == NULL)||(!OS_Match(VALIDMAIL, msg))))
567     {
568         merror(END_DATA_ERROR);
569         if(msg)
570             free(msg);
571         close(socket);
572         return(OS_INVALID);     
573     }
574     /* Checking msg in here, since it may be null */
575     if(msg)
576         free(msg);
577
578
579     /* quitting and closing socket */
580     OS_SendTCP(socket,QUITMSG);
581     msg = OS_RecvTCP(socket, OS_SIZE_1024);
582
583     if(msg)
584         free(msg);
585
586     memset(snd_msg,'\0',128);   
587
588
589     /* Returning 0 (success) */
590     close(socket);
591
592     return(0);
593 }
594 /* EOF */