new upstream release (3.3.0); modify package compatibility for Stretch
[ossec-hids.git] / src / os_maild / sendcustomemail.c
1 /* Copyright (C) 2009 Trend Micro Inc.
2  * All rights reserved.
3  *
4  * This program is a free software; you can redistribute it
5  * and/or modify it under the terms of the GNU General Public
6  * License (version 2) as published by the FSF - Free Software
7  * Foundation
8  */
9
10 /* Basic e-mailing operations */
11
12 #include "shared.h"
13 #include "os_net/os_net.h"
14
15 /* Return codes (from SMTP server) */
16 #define VALIDBANNER     "220"
17 #define VALIDMAIL       "250"
18 #define VALIDDATA       "354"
19
20 /* Default values used to connect */
21 #define SMTP_DEFAULT_PORT   "25"
22 #define HELOMSG             "Helo notify.ossec.net\r\n"
23 #define MAILFROM            "Mail From: <%s>\r\n"
24 #define RCPTTO              "Rcpt To: <%s>\r\n"
25 #define DATAMSG             "DATA\r\n"
26 #define FROM                "From: OSSEC HIDS <%s>\r\n"
27 #define REPLYTO             "Reply-To: OSSEC HIDS <%s>\r\n"
28 #define TO                  "To: <%s>\r\n"
29 #define CC                  "Cc: <%s>\r\n"
30 #define SUBJECT             "Subject: %s\r\n"
31 #define ENDHEADER           "\r\n"
32 #define ENDDATA             "\r\n.\r\n"
33 #define QUITMSG             "QUIT\r\n"
34 #define XHEADER             "X-IDS-OSSEC: %s\r\n"
35
36 /* Error messages - Can be translated */
37 #define INTERNAL_ERROR  "os_maild (1760): ERROR: Memory/configuration error"
38 #define BANNER_ERROR    "os_sendmail(1762): WARN: Banner not received from server"
39 #define HELO_ERROR      "os_sendmail(1763): WARN: Hello not accepted by server"
40 #define FROM_ERROR      "os_sendmail(1764): WARN: Mail from not accepted by server"
41 #define TO_ERROR        "os_sendmail(1765): WARN: RCPT TO not accepted by server - '%s'."
42 #define DATA_ERROR      "os_sendmail(1766): WARN: DATA not accepted by server"
43 #define END_DATA_ERROR  "os_sendmail(1767): WARN: End of DATA not accepted by server"
44
45 #define MAIL_DEBUG_FLAG     0
46 #define MAIL_DEBUG(x,y,z) if(MAIL_DEBUG_FLAG) merror(x,y,z)
47
48
49 int OS_SendCustomEmail(char **to, char *subject, char *smtpserver, char *from, char *replyto, char *idsname, char *fname, const struct tm *p)
50 {
51     FILE *sendmail = NULL;
52     int socket = -1, i = 0;
53     char *msg;
54     char snd_msg[128];
55     char buffer[2049];
56
57     buffer[2048] = '\0';
58
59     if (smtpserver[0] == '/') {
60         sendmail = popen(smtpserver, "w");
61         if (!sendmail) {
62             return (OS_INVALID);
63         }
64     } else {
65         /* Connect to the SMTP server */
66         socket = OS_ConnectTCP(SMTP_DEFAULT_PORT, smtpserver);
67         if (socket < 0) {
68             return (socket);
69         }
70
71         /* Receive the banner */
72         msg = OS_RecvTCP(socket, OS_SIZE_1024);
73         if ((msg == NULL) || (!OS_Match(VALIDBANNER, msg))) {
74             merror(BANNER_ERROR);
75             if (msg) {
76                 free(msg);
77             }
78             close(socket);
79             return (OS_INVALID);
80         }
81         MAIL_DEBUG("DEBUG: Received banner: '%s' %s", msg, "");
82         free(msg);
83
84         /* Send HELO message */
85         OS_SendTCP(socket, HELOMSG);
86         msg = OS_RecvTCP(socket, OS_SIZE_1024);
87         if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) {
88             if (msg) {
89                 /* In some cases (with virus scans in the middle)
90                  * we may get two banners. Check for that in here.
91                  */
92                 if (OS_Match(VALIDBANNER, msg)) {
93                     free(msg);
94
95                     /* Try again */
96                     msg = OS_RecvTCP(socket, OS_SIZE_1024);
97                     if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) {
98                         merror("%s:%s", HELO_ERROR, msg != NULL ? msg : "null");
99                         if (msg) {
100                             free(msg);
101                         }
102                         close(socket);
103                         return (OS_INVALID);
104                     }
105                 } else {
106                     merror("%s:%s", HELO_ERROR, msg);
107                     free(msg);
108                     close(socket);
109                     return (OS_INVALID);
110                 }
111             } else {
112                 merror("%s:%s", HELO_ERROR, "null");
113                 close(socket);
114                 return (OS_INVALID);
115             }
116         }
117
118         MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", HELOMSG, msg);
119         free(msg);
120
121         /* Build "Mail from" msg */
122         memset(snd_msg, '\0', 128);
123         snprintf(snd_msg, 127, MAILFROM, from);
124         OS_SendTCP(socket, snd_msg);
125         msg = OS_RecvTCP(socket, OS_SIZE_1024);
126         if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) {
127             merror(FROM_ERROR);
128             if (msg) {
129                 free(msg);
130             }
131             close(socket);
132             return (OS_INVALID);
133         }
134         MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg);
135         free(msg);
136
137         /* Build "RCPT TO" msg */
138         while (to[i]) {
139             memset(snd_msg, '\0', 128);
140             snprintf(snd_msg, 127, RCPTTO, to[i]);
141             OS_SendTCP(socket, snd_msg);
142             msg = OS_RecvTCP(socket, OS_SIZE_1024);
143             if ((msg == NULL) || (!OS_Match(VALIDMAIL, msg))) {
144                 merror(TO_ERROR, to[i]);
145                 if (msg) {
146                     free(msg);
147                 }
148                 close(socket);
149                 return (OS_INVALID);
150             }
151             MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", snd_msg, msg);
152             free(msg);
153
154             i++;
155         }
156
157         /* Send the "DATA" msg */
158         OS_SendTCP(socket, DATAMSG);
159         msg = OS_RecvTCP(socket, OS_SIZE_1024);
160         if ((msg == NULL) || (!OS_Match(VALIDDATA, msg))) {
161             merror(DATA_ERROR);
162             if (msg) {
163                 free(msg);
164             }
165             close(socket);
166             return (OS_INVALID);
167         }
168         MAIL_DEBUG("DEBUG: Sent '%s', received: '%s'", DATAMSG, msg);
169         free(msg);
170     }
171
172     /* Build "From" and "To" in the e-mail header */
173     memset(snd_msg, '\0', 128);
174     snprintf(snd_msg, 127, TO, to[0]);
175
176     if (sendmail) {
177         fprintf(sendmail, "%s", snd_msg);
178     } else {
179         OS_SendTCP(socket, snd_msg);
180     }
181
182     memset(snd_msg, '\0', 128);
183     snprintf(snd_msg, 127, FROM, from);
184
185     if (sendmail) {
186         fprintf(sendmail, "%s", snd_msg);
187     } else {
188         OS_SendTCP(socket, snd_msg);
189     }
190
191     if (replyto) {
192         memset(snd_msg, '\0', 128);
193         snprintf(snd_msg, 127, REPLYTO, replyto);
194         if(sendmail) {
195             fprintf(sendmail, "%s", snd_msg);
196         } else {
197             OS_SendTCP(socket, snd_msg);
198         }
199     }
200
201     /* Add CCs */
202     if (to[1]) {
203         i = 1;
204         while (1) {
205             if (to[i] == NULL) {
206                 break;
207             }
208
209             memset(snd_msg, '\0', 128);
210             snprintf(snd_msg, 127, TO, to[i]);
211
212             if (sendmail) {
213                 fprintf(sendmail, "%s", snd_msg);
214             } else {
215                 OS_SendTCP(socket, snd_msg);
216             }
217
218             i++;
219         }
220     }
221
222     /* Send date */
223     memset(snd_msg, '\0', 128);
224
225     /* Solaris doesn't have the "%z", so we set the timezone to 0 */
226 #ifdef SOLARIS
227     strftime(snd_msg, 127, "Date: %a, %d %b %Y %T -0000\r\n", p);
228 #else
229     strftime(snd_msg, 127, "Date: %a, %d %b %Y %T %z\r\n", p);
230 #endif
231
232     if (sendmail) {
233         fprintf(sendmail, "%s", snd_msg);
234     } else {
235         OS_SendTCP(socket, snd_msg);
236     }
237
238     if (idsname) {
239         /* Send server name header */
240         memset(snd_msg, '\0', 128);
241         snprintf(snd_msg, 127, XHEADER, idsname);
242
243         if (sendmail) {
244             fprintf(sendmail, "%s", snd_msg);
245         } else {
246             OS_SendTCP(socket, snd_msg);
247         }
248     }
249
250     /* Send subject */
251     memset(snd_msg, '\0', 128);
252     snprintf(snd_msg, 127, SUBJECT, subject);
253
254     if (sendmail) {
255         fprintf(sendmail, "%s", snd_msg);
256         fprintf(sendmail, ENDHEADER);
257     } else {
258         OS_SendTCP(socket, snd_msg);
259         OS_SendTCP(socket, ENDHEADER);
260     }
261
262     /* Send body */
263     FILE *fp;
264     fp = fopen(fname, "r");
265     if(!fp) {
266         merror("%s: ERROR: Cannot open %s: %s", __local_name, fname, strerror(errno));
267         if(socket >= 0) {
268             close(socket);
269         }
270         if(sendmail) {
271             pclose(sendmail);
272         }
273         return(1);
274     }
275
276
277     struct stat sb;
278     int sr;
279     sr = stat(fname, &sb);
280     if(sr < 0) {
281         merror("Cannot stat %s: %s", fname, strerror(errno));
282     }
283     if(sb.st_size == 0) {
284         merror("Report is empty");
285         if(socket >= 0) {
286             close(socket);
287         }
288         if(sendmail) {
289             pclose(sendmail);
290         }
291         if(fp) {
292             fclose(fp);
293         }
294         return(0);
295     }
296     while (fgets(buffer, 2048, fp) != NULL) {
297         if (sendmail) {
298             fprintf(sendmail, "%s", buffer);
299         } else {
300             OS_SendTCP(socket, buffer);
301         }
302     }
303     fclose(fp);
304
305     if (sendmail) {
306         if (pclose(sendmail) == -1) {
307             merror(WAITPID_ERROR, ARGV0, errno, strerror(errno));
308         }
309     } else {
310         /* Send end of data \r\n.\r\n */
311         OS_SendTCP(socket, ENDDATA);
312         msg = OS_RecvTCP(socket, OS_SIZE_1024);
313
314         /* Check msg, since it may be null */
315         if (msg) {
316             free(msg);
317         }
318
319         /* Quit and close socket */
320         OS_SendTCP(socket, QUITMSG);
321         msg = OS_RecvTCP(socket, OS_SIZE_1024);
322
323         if (msg) {
324             free(msg);
325         }
326
327         close(socket);
328     }
329
330     memset_secure(snd_msg, '\0', 128);
331     return (0);
332 }
333