1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #ifndef WIN32
6 #include <unistd.h>
7 #else
8 #include <winsock2.h>
9 #endif
10 
11 #include "config.h"
12 #include "sockio.h"
13 #include "variables.h"
14 #include "core.h"
15 #include "hooks.h"
16 #include "compat.h"
17 #include "mystring.h"
18 
19 #define CAPS_MIME	0x01
20 #define CAPS_DSN	0x02
21 
22 
23 
24 const char *cfg_user_notify = "DELAY,FAILURE";
25 
26 LSOCKET my_socket = -1;
27 int servercaps;
28 int receipients;
29 
30 int notify_type;
31 
try_connect_EHLO(const char * hostname)32 int try_connect_EHLO(const char *hostname)
33 {
34     char dbg_hostname[BIG_BUF];
35     char dbg_version[BIG_BUF];
36     char buf[BIG_BUF];
37     char testme[BIG_BUF];
38     int read_data = 0;
39 
40     if(my_socket != -1)
41         sock_close(my_socket);
42 
43     log_printf(9, "Attempting to connect to %s\n", get_string("mailserver"));
44 
45     if (sock_open(get_string("mailserver"), get_number("smtp-socket"), &my_socket))
46         return 0;
47 
48     while(sock_readline(my_socket, buf, sizeof(buf)) != 0) {
49         int val;
50         char ch;
51 
52         read_data = 1;
53         log_printf(9,"Server sent: %s\n", buf);
54 
55         sscanf(buf, "%d%c%s %s", &val, &ch, &dbg_hostname[0], &dbg_version[0]);
56         if(val != 220) {
57              return 0;
58         }
59         if(ch != '-') {
60             log_printf(9, "Connected: %s (%s)\n", dbg_hostname, dbg_version);
61             break;
62         }
63     }
64     if(!read_data)
65         return 0;
66 
67     sock_printf(my_socket, "EHLO %s\r\n", hostname);
68     if(sock_readline(my_socket, buf, sizeof(buf)) == 0)
69         return 0;
70 
71     /* Check for valid response */
72     if(!sscanf(buf, "250-%s", testme))
73         return 0;
74 
75     /* Okay, we have a valid ESMTP server.  Read the server caps */
76     while(sock_readline(my_socket, buf, sizeof(buf)) != 0) {
77         int val;
78         char ch;
79 
80         log_printf(9,"Server sent: %s\n", buf);
81 
82         sscanf(buf, "%d%c%s", &val, &ch, testme);
83         if(val != 250) {
84              return 0;
85         }
86         if(ch != '-')
87             break;
88         else {
89             if (!strcmp(testme,"DSN")) {
90                 servercaps &= CAPS_DSN;
91                 log_printf(9, "Server caps: server supports DSN\n");
92             } else if (!strcmp(testme,"8BITMIME")) {
93                 servercaps &= CAPS_MIME;
94                 log_printf(9, "Server caps: server supports MIME\n");
95             }
96         }
97     }
98     return 1;
99 }
100 
try_connect_HELO(const char * hostname)101 int try_connect_HELO(const char *hostname)
102 {
103     char dbg_hostname[BIG_BUF];
104     char dbg_version[BIG_BUF];
105     char buf[BIG_BUF];
106     char testme[BIG_BUF];
107 
108     /* Try the HELO protocal */
109     if(my_socket != -1)
110         sock_close(my_socket);
111 
112     if (sock_open(get_string("mailserver"), get_number("smtp-socket"), &my_socket))
113         return 0;
114 
115     if (sock_readline(my_socket, buf, sizeof(buf)) == 0)
116         return 0;
117 
118     if(!sscanf(buf,"220 %s %s", &dbg_hostname[0], &dbg_version[0]))
119         return 0;
120     log_printf(9, "Connected: %s (%s)\n", dbg_hostname, dbg_version);
121 
122     sock_printf(my_socket, "HELO %s\r\n", hostname);
123     if(sock_readline(my_socket, buf, sizeof(buf)) == 0)
124         return 0;
125     if(!sscanf(buf, "250 %s", testme))
126         return 0;
127     return 1;
128 }
129 
smtp_start(int notify)130 int smtp_start(int notify)
131 {
132     char hostname[BIG_BUF];
133 
134     clean_var("smtp-last-error", VAR_TEMP);
135     notify_type = notify;
136 
137     my_socket = -1;
138     servercaps = 0;
139     receipients = 0;
140 
141     build_hostname(hostname,sizeof(hostname));
142 
143     if(!try_connect_EHLO(hostname)) {
144         if(!try_connect_HELO(hostname)) {
145             if(my_socket != -1)
146                 sock_close(my_socket);
147             my_socket = -1;
148             set_var("smtp-last-error", "Error connecting to SMTP server.", VAR_TEMP);
149             return 0;
150         }
151     }
152     return 1;
153 }
154 
smtp_from(const char * fromaddy)155 int smtp_from(const char *fromaddy)
156 {
157     int result, final;
158     char buf[BIG_BUF];
159     int maxretries;
160 
161     maxretries = get_number("max-rcpt-tries");
162     if (!maxretries) maxretries = 5;
163 
164     clean_var("smtp-last-error", VAR_TEMP);
165     final = sock_printf(my_socket,"MAIL FROM:<%s>", fromaddy);
166 
167     log_printf(9, "Mail from set to %s\n", fromaddy);
168 
169     if (servercaps & CAPS_DSN) {
170         result = sock_printf(my_socket," RET=%s",
171                              (notify_type ? "FULL" : "HDRS"));
172         final += result;
173     }
174 
175     final += sock_printf(my_socket, "\r\n");
176     if (!final) {
177         set_var("smtp-last-error", "Error setting SMTP from address.", VAR_TEMP);
178         return 0;
179     }
180 
181     if (!get_bool("smtp-blind-blast")) {
182        memset(buf, 0, sizeof(buf));
183           result = 0;
184        if (get_bool("smtp-retry-forever")) {
185 
186           while (!result) {
187              result = sock_readline(my_socket, buf, sizeof(buf));
188           }
189        } else {
190           int tries = 0;
191 
192           log_printf(9, "sock_readline maxretries=%d\n", maxretries);
193 
194           while(!result && (tries < maxretries)) {
195              result = sock_readline(my_socket, buf, sizeof(buf));
196              tries++;
197           }
198        }
199 
200        if (result) {
201            log_printf(9, "Response: %s\n", buf);
202 
203            if (strncmp(buf,"250",3)) {
204                result = 0;
205                log_printf(9, "Sender '%s' rejected!\n", fromaddy);
206                set_var("smtp-last-error", buf, VAR_TEMP);
207            } else {
208                 log_printf(9, "Sender '%s' accepted.\n", fromaddy);
209            }
210         } else {
211             log_printf(9,"IO Err: Read timeout on MAIL FROM.");
212             set_var("smtp-last-error", "Error setting SMTP from address.",
213                   VAR_TEMP);
214         }
215         return (result != 0);
216     }
217     else return 1;
218 }
219 
smtp_to(const char * toaddy)220 int smtp_to(const char *toaddy)
221 {
222     char buf[BIG_BUF];
223     int result, final;
224     int maxretries;
225 
226     result = 0;
227     maxretries = get_number("max-rcpt-tries");
228     if (!maxretries) maxretries = 5;
229 
230     clean_var("smtp-last-error", VAR_TEMP);
231     final = sock_printf(my_socket, "RCPT TO:<%s>", toaddy);
232 
233     log_printf(9, "Mail sent to %s\n", toaddy);
234 
235     if (servercaps & CAPS_DSN) {
236         result = sock_printf(my_socket, " NOTIFY=%s", cfg_user_notify);
237         final += result;
238 
239         result = sock_printf(my_socket, " ORCPT=%s", toaddy);
240         final += result;
241     }
242 
243     final += sock_printf(my_socket, "\r\n");
244 
245     if (!final) {
246         set_var("smtp-last-error","Can't send to SMTP server (RCPT TO)", VAR_TEMP);
247         return 0;
248     }
249 
250     if (!get_bool("smtp-blind-blast")) {
251        int tries;
252        int tryforever = 0;
253 
254        tries = 0; result = 0;
255 
256        while (!result && (tryforever ? 1 : tries < maxretries)) {
257           result = sock_readline(my_socket, buf, sizeof(buf));
258        }
259 
260        if (result > 0) {
261            log_printf(9, "Response: %s\n", buf);
262 
263            if (strncmp(buf,"25",2)) {
264                result = 0;
265                log_printf(9, "Receipient '%s' rejected!\n", toaddy);
266                set_var("smtp-last-error", buf, VAR_TEMP);
267                set_var("bounce-error", buf, VAR_TEMP);
268                set_var("bounce-address", toaddy, VAR_TEMP);
269                (void)do_hooks("LOCAL-BOUNCE");
270            } else {
271                receipients++;
272                log_printf(9, "Receipient '%s' accepted. (%d total)\n",
273                  toaddy, receipients);
274            }
275         }
276     }
277 
278     if (get_bool("sendmail-sleep")) {
279         int sleeplen;
280 
281         sleeplen = get_seconds("sendmail-sleep-length");
282         do_sleep(sleeplen);
283     }
284 
285     return (result != 0);
286 }
287 
smtp_body_start()288 int smtp_body_start()
289 {
290     char buf[BIG_BUF];
291     int tryforever;
292     int maxretries;
293 
294     maxretries = get_number("max-rcpt-tries");
295     if (!maxretries) maxretries = 5;
296 
297     tryforever = get_bool("smtp-retry-forever");
298 
299     clean_var("smtp-last-error", VAR_TEMP);
300     log_printf(9, "Data transmit starting.\n");
301     if (!sock_printf(my_socket,"DATA\r\n")) {
302         set_var("smtp-last-error", "Unable to write to SMTP server (DATA).", VAR_TEMP);
303         return 0;
304     }
305 
306     if (!get_bool("smtp-blind-blast")) {
307        int result, tries;
308 
309        tries = 0; result = 0;
310 
311        while(!result && (tryforever ? 1 : tries < maxretries)) {
312            result = sock_readline(my_socket, buf, sizeof(buf));
313            tries++;
314        }
315 
316        if (!result) {
317            set_var("smtp-last-error", "No response from SMTP server (DATA).", VAR_TEMP);
318            return 0;
319        }
320 
321        log_printf(9, "Response: %s\n", buf);
322 
323        if (strncmp(buf,"354",3)) {
324            log_printf(9, "Unable to start message body!\n");
325            set_var("smtp-last-error", buf, VAR_TEMP);
326            return 0;
327        }
328    }
329 
330    return 1;
331 }
332 
smtp_body_822bis(const char * src,char * dest,size_t size)333 void smtp_body_822bis(const char *src, char *dest, size_t size)
334 {
335     const char *ptr1;
336     char *ptr2, *end;
337     int lastcr;
338 
339     lastcr = 0;
340 
341     ptr1 = src;
342     ptr2 = dest;
343     end = dest + size - 2;
344 
345     while(*ptr1 && ptr2 < end) {
346        if ((*ptr1 == '\n') && (!lastcr)) {
347           *ptr2++ = '\r';
348        } else if (*ptr1 == '\r') {
349           lastcr = 1;
350        } else if (*ptr1 == '.') {
351           /* Handle escaping of single periods on a line */
352           if((ptr2 == dest) || (*(ptr2-1) == '\n')) {
353              *ptr2++ = '.';
354           }
355        }
356 
357        if (lastcr && (*ptr1 != '\r')) {
358           lastcr = 0;
359        }
360 
361        *ptr2++ = *ptr1++;
362     }
363 
364     *ptr2 = 0;
365 }
366 
smtp_body_text(const char * line)367 int smtp_body_text(const char *line)
368 {
369     char buffer[HUGE_BUF];
370 
371     smtp_body_822bis(line,&buffer[0], sizeof(buffer));
372 
373     clean_var("smtp-last-error", VAR_TEMP);
374     if (!sock_printf(my_socket,"%s",buffer)) {
375         set_var("smtp-last-error", "Unable to write to SMTP server (message body).", VAR_TEMP);
376         return 0;
377     }
378 
379     return 1;
380 }
381 
smtp_body_line(const char * line)382 int smtp_body_line(const char *line)
383 {
384     char buffer[HUGE_BUF];
385     char buffer2[HUGE_BUF];
386 
387     buffer_printf(buffer2, sizeof(buffer2) - 1, "%s\r\n", line);
388 
389     smtp_body_822bis(buffer2,&buffer[0], sizeof(buffer));
390 
391     clean_var("smtp-last-error", VAR_TEMP);
392     if (!sock_printf(my_socket,"%s",buffer)) {
393         set_var("smtp-last-error", "Unable to write to SMTP server (message body).", VAR_TEMP);
394         return 0;
395     }
396 
397     return 1;
398 }
399 
smtp_body_end()400 int smtp_body_end()
401 {
402     char buf[BIG_BUF], buf2[BIG_BUF];
403     int tryforever;
404     int maxretries;
405 
406     maxretries = get_number("max-rcpt-tries");
407     if (!maxretries) maxretries = 5;
408 
409     tryforever = get_bool("smtp-retry-forever");
410 
411     clean_var("smtp-last-error", VAR_TEMP);
412     log_printf(9, "Data transmit ending.\n");
413     if (!sock_printf(my_socket,"\r\n.\r\n")) {
414         set_var("smtp-last-error", "Unable to write to SMTP server (message end).", VAR_TEMP);
415         return 0;
416     }
417 
418     if (!get_bool("smtp-blind-blast")) {
419        int tries, result;
420 
421        tries = 0; result = 0;
422 
423        while(!result && (tryforever ? 1 : tries < maxretries)) {
424            result = sock_readline(my_socket, buf, sizeof(buf));
425            tries++;
426        }
427 
428        if (!result) {
429            set_var("smtp-last-error", "No response from SMTP server. (message end)", VAR_TEMP);
430            return 0;
431        }
432 
433        log_printf(9, "Response: %s\n", buf);
434 
435        if (!strncmp(&buf[0],"250",3)) {
436            if (sscanf(buf, "250 %s Message accepted for delivery.", &buf2[0]) == 1)
437               log_printf(9, "Message accepted and queued as %s.\n", buf2);
438        } else {
439            log_printf(9, "Message rejected.\n");
440            set_var("smtp-last-error", buf, VAR_TEMP);
441            return 0;
442        }
443     }
444 
445     return 1;
446 }
447 
smtp_end()448 int smtp_end()
449 {
450     clean_var("smtp-last-error", VAR_TEMP);
451     log_printf(9, "Disconnecting.\n");
452     if (!sock_printf(my_socket, "QUIT\r\n")) {
453         set_var("smtp-last-error", "Unable to write to SMTP server (QUIT).", VAR_TEMP);
454         return 0;
455     }
456 
457     sock_close(my_socket);
458     my_socket = -1;
459     log_printf(9, "Disconnected.\n");
460 
461     return 1;
462 }
463