]> git.ipfire.org Git - thirdparty/mlmmj.git/commitdiff
Isolate functions to send email in order to be able to reuse them
authorBaptiste Daroussin <bapt@FreeBSD.org>
Tue, 27 Dec 2022 16:18:07 +0000 (17:18 +0100)
committerBaptiste Daroussin <bapt@FreeBSD.org>
Tue, 27 Dec 2022 16:21:21 +0000 (17:21 +0100)
While here add a test function for do_bouncemail and fix an issue
which could allow to crash mlmmj-send.
Stop forking in do_bouncemail, it is not necessary

ChangeLog
include/mlmmj-send.h
include/send_mail.h
src/mlmmj-send.c
src/send_mail.c
tests/mlmmj.c

index 4027db297609f6d7d1852d08a8ea8dcfdd22d7a4..bb82ad058ba3a5eb824ed76943297714603ba3b8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,6 @@
 1.4.0-a2
- o Remove perl and php frontends
+ o Fix a crash with forged probe emails
+ o mlmmj-send does not need anymore absolute path
 1.4.0-a1
  o Add a test suite
  o Modernize code (dprintf, posix_spawn, asprintf, getline, daemon, ...)
index 7d4728485ba775a874c498e79b056097d2f38d38..7fd00e25ecf9c08d5d7a9a0a967a28a0e11e7ee2 100644 (file)
 #ifndef MMJML_SEND_H
 #define MMJML_SEND_H
 
-int send_mail(int sockfd, const char *from, const char *to,
-             const char *replyto, char *mailmap, size_t mailsize,
-             int listfd, bool bounce,
-             const char *hdrs, const char *body);
-int send_mail_many_fd(int sockfd, const char *from, const char *replyto,
-                  char *mailmap, size_t mailsize, int subfd,
+#include <sys/types.h>
+#include <stdbool.h>
+#include "send_mail.h"
+
+int send_mail_many_fd(int sockfd, struct mail *mail, int subfd,
                   const char *listaddr, const char *listdelim,
-                  const char *archivefilename, int listfd,
-                  const char *hdrs,
-                  const char *body);
-int send_mail_many_list(int sockfd, const char *from, const char *replyto,
-                  char *mailmap, size_t mailsize, struct strlist *addrs,
+                  const char *archivefilename, int listfd);
+int send_mail_many_list(int sockfd, struct mail *mail, struct strlist *addrs,
                   const char *listaddr, const char *listdelim,
-                  const char *archivefilename, int listfd,
-                  const char *hdrs, const char *body);
-int send_mail_verp(int sockfd, struct strlist *addrs, char *mailmap,
-                  size_t mailsize, const char *from,
-                  const char *hdrs, const char *body, const char *extra);
-int initsmtp(int *sockfd, const char *relayhost, unsigned short port, const char *heloname);
-int endsmtp(int *sockfd);
+                  const char *archivefilename, int listfd);
+int send_mail_verp(int sockfd, struct strlist *addrs, struct mail *mail, const char *extra);
 
 #endif /* MMJML_SEND_H */
index 060981e7e49da1904e7e8a838aba10a12f9913d9..41d4c4b62ccf60f70c299926b6ac3975e2f30e62 100644 (file)
 
 #pragma once
 
+#include <sys/types.h>
+#include <stdbool.h>
+
+struct mail {
+       const char *from;
+       const char *to;
+       const char *replyto;
+       char *map;
+       size_t size;
+       char *hdrs;
+       char *body;
+       bool inmem;
+       bool addtohdr;
+};
+
 int initsmtp(int *sockfd, const char *relayhost, unsigned short port, const char *heloname);
 int endsmtp(int *sockfd);
+int send_mail(int sockfd, struct mail *mail, int listfd, bool bounce);
+int do_bouncemail(int listfd, const char *from);
index 1cb8d9da5a28c9259c051a0108d28353c50a279f..30632bb13809e9020568d30f6678c70f54564308 100644 (file)
@@ -66,8 +66,6 @@
 #include "utils.h"
 #include "send_mail.h"
 
-static int addtohdr = false;
-static int prepmailinmem = 0;
 static int maxverprecips = MAXVERPRECIPS;
 static int gotsigterm = 0;
 
@@ -173,192 +171,8 @@ char *bounce_from_adr(const char *recipient, const char *listadr,
        return bounceaddr;
 }
 
-int do_bouncemail(int listfd, const char *from)
-{
-       char *tofree;
-       char *myfrom = xstrdup(from);
-       char *listdelim = fgetlistdelim(listfd);
-       char *addr, *num, *c;
-       pid_t pid = 0;
-
-       tofree = myfrom;
-       if((c = strchr(myfrom, '@')) == NULL) {
-               free(myfrom);
-               free(listdelim);
-               return 0; /* Success when malformed 'from' */
-       }
-       *c = '\0';
-       num = strrchr(myfrom, '-');
-       if (num == NULL) {
-               free(tofree);
-               return (0); /* Success when malformed 'from' */
-       }
-       num++;
-       c = strstr(myfrom, listdelim);
-       if (c == NULL) {
-               free(tofree);
-               return (0); /* Success when malformed 'from' */
-       }
-       myfrom = strchr(c, '-'); /* always true we checked earlier */
-       myfrom++;
-       if (num <= myfrom) {
-               free(tofree);
-               return (0); /* Success when malformed 'from' */
-       }
-       addr = xstrndup(myfrom, num - myfrom - 1);
-       free(listdelim);
-
-       pid = fork();
-       
-       if(pid < 0) {
-               log_error(LOG_ARGS, "fork() failed!");
-               return 1;
-       }
-       
-       if(pid > 0)
-               return 0;
-       
-       bouncemail(listfd, num, addr);
-       return 1;
-}
-
-int send_mail(int sockfd, const char *from, const char *to,
-             const char *replyto, char *mailmap, size_t mailsize,
-             int listfd, bool bounce,
-             const char *hdrs, const char *body)
-{
-       int retval = 0;
-       char *reply, *reply2, *tohdr;
-
-       if(sockfd == -1)
-               return EBADF;
-
-       if(strchr(to, '@') == NULL) {
-               errno = 0;
-               log_error(LOG_ARGS, "No @ in address, ignoring %s",
-                               to);
-               return 0;
-       }
-       
-       retval = write_mail_from(sockfd, from, "");
-       if(retval) {
-               log_error(LOG_ARGS, "Could not write MAIL FROM\n");
-               return retval;
-       }
-       reply = checkwait_smtpreply(sockfd, MLMMJ_FROM);
-       if(reply) {
-               log_error(LOG_ARGS, "Error in MAIL FROM. Reply = [%s]",
-                               reply);
-               free(reply);
-               write_rset(sockfd);
-               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
-               if (reply2 != NULL) free(reply2);
-               return MLMMJ_FROM;
-       }
-       retval = write_rcpt_to(sockfd, to);
-       if(retval) {
-               log_error(LOG_ARGS, "Could not write RCPT TO:\n");
-               return retval;
-       }
-
-       reply = checkwait_smtpreply(sockfd, MLMMJ_RCPTTO);
-       if(reply) {
-               write_rset(sockfd);
-               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
-               if (reply2 != NULL) free(reply2);
-               if(bounce && ((reply[0] == '4') || (reply[0] == '5'))
-                               && (reply[1] == '5')) {
-                       free(reply);
-                       return do_bouncemail(listfd, from);
-               } else {
-                       log_error(LOG_ARGS, "Error in RCPT TO. Reply = [%s]",
-                                       reply);
-                       free(reply);
-                       return MLMMJ_RCPTTO;
-               }
-       }
-
-       retval = write_data(sockfd);
-       if(retval) {
-               log_error(LOG_ARGS, "Could not write DATA\b");
-               return retval;
-       }
-
-       reply = checkwait_smtpreply(sockfd, MLMMJ_DATA);
-       if(reply) {
-               log_error(LOG_ARGS, "Error with DATA. Reply = [%s]", reply);
-               free(reply);
-               write_rset(sockfd);
-               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
-               if (reply2 != NULL) free(reply2);
-               return MLMMJ_DATA;
-       }
-
-       if(replyto) {
-               retval = write_replyto(sockfd, replyto);
-               if(retval) {
-                       log_error(LOG_ARGS, "Could not write reply-to addr.\n");
-                       return retval;
-               }
-       }
-
-       if(addtohdr)
-               tohdr = concatstr(3, "To: ", to, "\r\n");
-       else
-               tohdr = NULL;
-
-       if(prepmailinmem) {
-               retval = dprintf(sockfd, "%s", hdrs);
-               if(retval < 0) {
-                       log_error(LOG_ARGS, "Could not write mailheaders.\n");
-                       return retval;
-               }
-               if(tohdr) {
-                       retval = dprintf(sockfd, "%s", tohdr);
-                       if(retval < 0) {
-                               log_error(LOG_ARGS, "Could not write To:.\n");
-                               return retval;
-                       }
-                       free(tohdr);
-               }
-               retval = dprintf(sockfd, "%s", body);
-               if(retval < 0) {
-                       log_error(LOG_ARGS, "Could not write mailbody.\n");
-                       return retval;
-               }
-       } else {
-               retval = write_mailbody_from_map(sockfd, mailmap, mailsize,
-                                                tohdr);
-               if(retval) {
-                       log_error(LOG_ARGS, "Could not write mail\n");
-                       return retval;
-               }
-       }
-
-       retval = write_dot(sockfd);
-       if(retval) {
-               log_error(LOG_ARGS, "Could not write <CR><LF>.<CR><LF>\n");
-               return retval;
-       }
-
-       reply = checkwait_smtpreply(sockfd, MLMMJ_DOT);
-       if(reply) {
-               log_error(LOG_ARGS, "Mailserver did not ack end of mail.\n"
-                               "<CR><LF>.<CR><LF> was written, to no"
-                               "avail. Reply = [%s]", reply);
-               free(reply);
-               write_rset(sockfd);
-               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
-               if (reply2 != NULL) free(reply2);
-               return MLMMJ_DOT;
-       }
-
-       return 0;
-}
-
-int send_mail_verp(int sockfd, struct strlist *addrs, char *mailmap,
-                  size_t mailsize, const char *from,
-                  const char *hdrs, const char *body, const char *verpextra)
+int send_mail_verp(int sockfd, struct strlist *addrs, struct mail *mail,
+    const char *verpextra)
 {
        int retval, i;
        char *reply, *reply2;
@@ -366,7 +180,7 @@ int send_mail_verp(int sockfd, struct strlist *addrs, char *mailmap,
        if(sockfd == -1)
                return EBADF;
 
-       retval = write_mail_from(sockfd, from, verpextra);
+       retval = write_mail_from(sockfd, mail->from, verpextra);
        if(retval) {
                log_error(LOG_ARGS, "Could not write MAIL FROM\n");
                return retval;
@@ -424,20 +238,19 @@ int send_mail_verp(int sockfd, struct strlist *addrs, char *mailmap,
                return MLMMJ_DATA;
        }
 
-       if(prepmailinmem) {
-               retval = dprintf(sockfd, "%s", hdrs);
+       if(mail->inmem) {
+               retval = dprintf(sockfd, "%s", mail->hdrs);
                if(retval < 0) {
                        log_error(LOG_ARGS, "Could not write mailheaders.\n");
                        return retval;
                }
-               retval = dprintf(sockfd, "%s", body);
+               retval = dprintf(sockfd, "%s", mail->body);
                if(retval < 0) {
                        log_error(LOG_ARGS, "Could not write mailbody.\n");
                        return retval;
                }
        } else {
-               retval = write_mailbody_from_map(sockfd, mailmap, mailsize,
-                                                NULL);
+               retval = write_mailbody_from_map(sockfd, mail->map, mail->size, NULL);
                if(retval) {
                        log_error(LOG_ARGS, "Could not write mail\n");
                        return retval;
@@ -465,12 +278,9 @@ int send_mail_verp(int sockfd, struct strlist *addrs, char *mailmap,
        return 0;
 }
 
-int send_mail_many_fd(int sockfd, const char *from, const char *replyto,
-                     char *mailmap, size_t mailsize, int subfd,
+int send_mail_many_fd(int sockfd, struct mail *mail, int subfd,
                      const char *listaddr, const char *listdelim,
-                     const char *archivefilename, int listfd,
-                     const char *hdrs,
-                     const char *body)
+                     const char *archivefilename, int listfd)
 {
        int res, ret, i;
        struct strlist stl;
@@ -481,10 +291,9 @@ int send_mail_many_fd(int sockfd, const char *from, const char *replyto,
        do {
                res = getaddrsfromfd(&stl, subfd, maxverprecips);
                if(stl.count == maxverprecips) {
-                       ret = send_mail_many_list(sockfd, from, replyto,
-                                       mailmap, mailsize, &stl, listaddr,
-                                       listdelim, archivefilename, listfd,
-                                       hdrs, body);
+                       ret = send_mail_many_list(sockfd, mail, &stl,
+                                       listaddr, listdelim, archivefilename,
+                                       listfd);
                        for(i = 0; i < stl.count; i++)
                                free(stl.strs[i]);
                        if(ret < 0)
@@ -494,9 +303,8 @@ int send_mail_many_fd(int sockfd, const char *from, const char *replyto,
        } while(res > 0);
 
        if(stl.count) {
-               ret = send_mail_many_list(sockfd, from, replyto, mailmap,
-                               mailsize, &stl, listaddr, listdelim,
-                               archivefilename, listfd, hdrs, body);
+               ret = send_mail_many_list(sockfd, mail, &stl, listaddr, listdelim,
+                               archivefilename, listfd);
                for(i = 0; i < stl.count; i++)
                        free(stl.strs[i]);
                stl.count = 0;
@@ -553,10 +361,9 @@ int requeuemail(int listfd, int index, struct strlist *addrs,
        return 0;
 }
 
-int send_mail_many_list(int sockfd, const char *from, const char *replyto,
-                  char *mailmap, size_t mailsize, struct strlist *addrs,
+int send_mail_many_list(int sockfd, struct mail *mail, struct strlist *addrs,
                   const char *listaddr, const char *listdelim,
-                  const char *archivefilename, int listfd, const char *hdrs, const char *body)
+                  const char *archivefilename, int listfd)
 {
        int res = 0, i, status, index;
        char *bounceaddr, *addr;
@@ -577,18 +384,13 @@ int send_mail_many_list(int sockfd, const char *from, const char *replyto,
                        status = requeuemail(listfd, index, addrs, i);
                        return status;
                }
-               if(from) {
-                       res = send_mail(sockfd, from, addr, replyto,
-                                           mailmap, mailsize, listfd,
-                                           false, hdrs, body);
-               } else {
+               if (mail->from == NULL) {
                        bounceaddr = bounce_from_adr(addr, listaddr, listdelim,
-                                                    archivefilename, listfd);
-                       res = send_mail(sockfd, bounceaddr, addr, replyto,
-                                 mailmap, mailsize, listfd, true,
-                                 hdrs, body);
-                       free(bounceaddr);
+                           archivefilename, listfd);
+                       mail->from = bounceaddr;
                }
+               res = send_mail(sockfd, mail, listfd, bounceaddr != NULL);
+               free(bounceaddr);
                if(res && listaddr && archivefilename) {
                        /* we failed, so save the addresses and bail */
                        index = get_index_from_filename(archivefilename);
@@ -597,7 +399,7 @@ int send_mail_many_list(int sockfd, const char *from, const char *replyto,
                }
        }
        return 0;
-}      
+}
 
 static void print_help(const char *prg)
 {
@@ -637,12 +439,12 @@ int main(int argc, char **argv)
        int res;
        char *listaddr = NULL, *listdelim = NULL;
        char *mailfilename = NULL, *subfilename = NULL, *omit = NULL;
-       char *replyto = NULL, *bounceaddr = NULL, *to_addr = NULL;
+       char *bounceaddr = NULL;
        char *relayhost = NULL, *archivefilename = NULL, *tmpstr;
        char *subddirname = NULL, *listdir = NULL;
        char listctrl = 0;
-       char *mailmap, *probefile, *a;
-       char *body = NULL, *hdrs = NULL, *verp = NULL;
+       char *probefile, *a;
+       char *verp = NULL;
        char *listname, *listfqdn, *verpfrom;
        char *reply, *smtphelo, *requeuefilename;
        ssize_t memmailsize = 0;
@@ -654,7 +456,9 @@ int main(int argc, char **argv)
        unsigned short smtpport;
        struct sigaction sigact;
        int listfd;
+       struct mail mail;
 
+       memset(&mail, 0, sizeof(mail));
        log_set_name(argv[0]);
 
        /* install signal handler for SIGTERM */
@@ -699,13 +503,13 @@ int main(int argc, char **argv)
                        relayhost = optarg;
                        break;
                case 'R':
-                       replyto = optarg;
+                       mail.replyto = optarg;
                        break;
                case 's':
                        subfilename = optarg;
                        break;
                case 'T':
-                       to_addr = optarg;
+                       mail.to = optarg;
                        break;
                case 'V':
                        print_version(argv[0]);
@@ -742,7 +546,7 @@ int main(int argc, char **argv)
        }
 
        /* get the list address */
-       if(listctrl == '1' && (bounceaddr == NULL || to_addr == NULL)) {
+       if(listctrl == '1' && (bounceaddr == NULL || mail.to == NULL)) {
                errx(EXIT_FAILURE, "With -l 1 you need -F and -T");
        }
 
@@ -789,30 +593,30 @@ int main(int argc, char **argv)
        }
 
        if(st.st_size > memmailsize) {
-               prepmailinmem = 0;
                errno = 0;
                log_error(LOG_ARGS, "Not preparing in memory. "
                                    "Mail is %ld bytes", (long)st.st_size);
        } else
-               prepmailinmem = 1;
+               mail.inmem = true;
 
-       mailmap = mmap(0, st.st_size, PROT_READ, MAP_SHARED, mailfd, 0);
-       if(mailmap == MAP_FAILED) {
+       mail.map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, mailfd, 0);
+       if(mail.map == MAP_FAILED) {
                log_error(LOG_ARGS, "Could not mmap mailfd");
                exit(EXIT_FAILURE);
        }
+       mail.size = st.st_size;
 
-       if(prepmailinmem) {
-               hdrs = get_preppedhdrs_from_map(mailmap, &hdrslen);
-               if(hdrs == NULL) {
+       if(mail.inmem) {
+               mail.hdrs = get_preppedhdrs_from_map(mail.map, &hdrslen);
+               if(mail.hdrs == NULL) {
                        log_error(LOG_ARGS, "Could not prepare headers");
                        exit(EXIT_FAILURE);
                }
-               body = get_prepped_mailbody_from_map(mailmap, st.st_size,
+               mail.body = get_prepped_mailbody_from_map(mail.map, st.st_size,
                                                     &bodylen);
-               if(body == NULL) {
+               if(mail.body == NULL) {
                        log_error(LOG_ARGS, "Could not prepare mailbody");
-                       free(hdrs);
+                       free(mail.hdrs);
                        exit(EXIT_FAILURE);
                }
        }
@@ -829,8 +633,8 @@ int main(int argc, char **argv)
                if((subfd = open(subfilename, O_RDONLY)) < 0) {
                        log_error(LOG_ARGS, "Could not open '%s':",
                                            subfilename);
-                       free(hdrs);
-                       free(body);
+                       free(mail.hdrs);
+                       free(mail.body);
                        free(subfilename);
                        free(listdelim);
                        /* No moderators is no error. Could be the sysadmin
@@ -840,13 +644,13 @@ int main(int argc, char **argv)
                }
                break;
        case '3':
-               addtohdr = fstatctrl(listfd, "addtohdr");
+               mail.addtohdr = fstatctrl(listfd, "addtohdr");
        case '4': /* sending mails to subfile */
                if((subfd = open(subfilename, O_RDONLY)) < 0) {
                        log_error(LOG_ARGS, "Could not open '%s':",
                                            subfilename);
-                       free(hdrs);
-                       free(body);
+                       free(mail.hdrs);
+                       free(mail.body);
                        free(listdelim);
                        exit(EXIT_FAILURE);
                }
@@ -854,11 +658,11 @@ int main(int argc, char **argv)
        case '6':
                deletewhensent = 0;
                archivefilename = xstrdup(mailfilename);
-               bounceaddr = bounce_from_adr(to_addr, listaddr, listdelim,
+               bounceaddr = bounce_from_adr(mail.to, listaddr, listdelim,
                                                archivefilename, listfd);
                break;
        default: /* normal list mail -- now handled when forking */
-               addtohdr = fstatctrl(listfd, "addtohdr");
+               mail.addtohdr = fstatctrl(listfd, "addtohdr");
                break;
        }
 
@@ -885,9 +689,8 @@ int main(int argc, char **argv)
        case '1': /* A single mail is to be sent */
        case '6':
                initsmtp(&sockfd, relayhost, smtpport, smtphelo);
-               if(send_mail(sockfd, bounceaddr, to_addr, replyto,
-                               mailmap, st.st_size, listfd, false,
-                               hdrs, body)) {
+               mail.from = bounceaddr;
+               if(send_mail(sockfd, &mail,listfd, false)) {
                        close(sockfd);
                        sockfd = -1;
                        /* error, so keep it in the queue */
@@ -915,10 +718,10 @@ int main(int argc, char **argv)
                                                S_IRUSR|S_IWUSR);
                        free(tmpstr);
                        if(tmpfd >= 0) {
-                               dprintf(tmpfd, "%s", to_addr);
+                               dprintf(tmpfd, "%s", mail.to);
                        }
                        close(tmpfd);
-                       if(replyto) {
+                       if(mail.replyto) {
                                tmpstr = concatstr(2, mailfilename,
                                                      ".reply-to");
                                if(stat(tmpstr, &st) == 0) {
@@ -929,7 +732,7 @@ int main(int argc, char **argv)
                                                        S_IRUSR|S_IWUSR);
                                free(tmpstr);
                                if(tmpfd >= 0) {
-                                       dprintf(tmpfd, "%s", replyto);
+                                       dprintf(tmpfd, "%s", mail.replyto);
                                }
                                close(tmpfd);
                        }
@@ -939,9 +742,9 @@ int main(int argc, char **argv)
                break;
        case '2': /* Moderators */
                initsmtp(&sockfd, relayhost, smtpport, smtphelo);
-               if(send_mail_many_fd(sockfd, bounceaddr, NULL, mailmap,
-                                    st.st_size, subfd, NULL, NULL, NULL,
-                                    listfd, hdrs, body)) {
+               mail.from = bounceaddr;
+               mail.replyto = NULL;
+               if(send_mail_many_fd(sockfd, &mail, subfd, NULL, NULL, NULL, listfd)) {
                        close(sockfd);
                        sockfd = -1;
                } else {
@@ -950,9 +753,10 @@ int main(int argc, char **argv)
                break;
        case '3': /* resending earlier failed mails */
                initsmtp(&sockfd, relayhost, smtpport, smtphelo);
-               if(send_mail_many_fd(sockfd, NULL, NULL, mailmap, st.st_size,
-                               subfd, listaddr, listdelim, mailfilename,
-                               listfd, hdrs, body)) {
+               mail.from = NULL;
+               mail.replyto = NULL;
+               if(send_mail_many_fd(sockfd, &mail, subfd, listaddr, listdelim,
+                               mailfilename, listfd)) {
                        close(sockfd);
                        sockfd = -1;
                } else {
@@ -962,9 +766,10 @@ int main(int argc, char **argv)
                break;
        case '4': /* send mails to owner */
                initsmtp(&sockfd, relayhost, smtpport, smtphelo);
-               if(send_mail_many_fd(sockfd, bounceaddr, NULL, mailmap,
-                               st.st_size, subfd, listaddr, listdelim,
-                               mailfilename, listfd, hdrs, body)) {
+               mail.from = bounceaddr;
+               mail.replyto = NULL;
+               if(send_mail_many_fd(sockfd, &mail, subfd, listaddr, listdelim,
+                               mailfilename, listfd)) {
                        close(sockfd);
                        sockfd = -1;
                } else {
@@ -973,13 +778,12 @@ int main(int argc, char **argv)
                break;
        case '5': /* bounceprobe - handle relayhost local users bouncing*/
                initsmtp(&sockfd, relayhost, smtpport, smtphelo);
-               if(send_mail(sockfd, bounceaddr, to_addr, replyto,
-                               mailmap, st.st_size, listfd,
-                               false, hdrs, body)) {
+               mail.from = bounceaddr;
+               if(send_mail(sockfd, &mail, listfd, false)) {
                        close(sockfd);
                        sockfd = -1;
                        /* error, so remove the probefile */
-                       tmpstr = xstrdup(to_addr);
+                       tmpstr = xstrdup(mail.to);
                        a = strchr(tmpstr, '@');
                        MY_ASSERT(a);
                        *a = '=';
@@ -994,7 +798,7 @@ int main(int argc, char **argv)
                break;
        case '7':
                digest = 1;
-               addtohdr = true;
+               mail.addtohdr = true;
                archivefilename = "digest";
                /* fall through */
        default: /* normal list mail */
@@ -1008,8 +812,8 @@ int main(int argc, char **argv)
                                            subddirname);
                        free(listdelim);
                        free(subddirname);
-                       free(hdrs);
-                       free(body);
+                       free(mail.hdrs);
+                       free(mail.body);
                        exit(EXIT_FAILURE);
                }
 
@@ -1029,7 +833,7 @@ int main(int argc, char **argv)
                        verp = xstrdup("XVERP=-=");
                }
 
-               if(addtohdr && verp) {
+               if(mail.addtohdr && verp) {
                        log_error(LOG_ARGS, "Cannot use VERP and add "
                                        "To: header. Not sending with "
                                        "VERP.");
@@ -1103,28 +907,25 @@ int main(int argc, char **argv)
                                if(stl.count == maxverprecips) {
                                        initsmtp(&sockfd, relayhost, smtpport, smtphelo);
                                        if(verp) {
+                                               mail.from = verpfrom;
+                                               mail.replyto = NULL;
                                                sendres = send_mail_verp(
                                                                sockfd, &stl,
-                                                               mailmap,
-                                                               st.st_size,
-                                                               verpfrom,
-                                                               hdrs,
-                                                               body, verp);
+                                                               &mail,
+                                                               verp);
                                                if(sendres)
                                                        requeuemail(listfd,
                                                                mindex,
                                                                &stl, 0);
                                        } else {
+                                               mail.from = NULL;
+                                               mail.replyto = NULL;
                                                sendres = send_mail_many_list(
-                                                               sockfd, NULL,
-                                                               NULL, mailmap,
-                                                               st.st_size,
-                                                               &stl,
-                                                               listaddr,
+                                                               sockfd, &mail,
+                                                               &stl, listaddr,
                                                                listdelim,
                                                                archivefilename,
-                                                               listfd,
-                                                               hdrs, body);
+                                                               listfd);
                                        }
                                        if (sendres) {
                                                close(sockfd);
@@ -1144,17 +945,17 @@ int main(int argc, char **argv)
                if(stl.count) {
                        initsmtp(&sockfd, relayhost, smtpport, smtphelo);
                        if(verp) {
-                               sendres = send_mail_verp(sockfd, &stl, mailmap,
-                                               st.st_size, verpfrom,
-                                               hdrs, body, verp);
+                               mail.from = verpfrom;
+                               mail.replyto = NULL;
+                               sendres = send_mail_verp(sockfd, &stl, &mail, verp);
                                if(sendres)
                                        requeuemail(listfd, mindex, &stl, 0);
                        } else {
-                               sendres = send_mail_many_list(sockfd, NULL,
-                                               NULL, mailmap, st.st_size,
+                               mail.from = NULL;
+                               mail.replyto = NULL;
+                               sendres = send_mail_many_list(sockfd, &mail,
                                                &stl, listaddr, listdelim,
-                                               archivefilename, listfd,
-                                               hdrs, body);
+                                               archivefilename, listfd);
                        }
                        if (sendres) {
                                close(sockfd);
@@ -1174,9 +975,9 @@ int main(int argc, char **argv)
        }
        
        free(listdelim);
-       free(hdrs);
-       free(body);
-       munmap(mailmap, st.st_size);
+       free(mail.hdrs);
+       free(mail.body);
+       munmap(mail.map, mail.size);
        close(mailfd);
        free(verp);
        free(smtphelo);
index 47d2c979b5f7707a9bbe91e238fe0d83afe69d5b..0b091444f94c56d0111b9e250fea06e7688e2c71 100644 (file)
@@ -26,6 +26,8 @@
 
 #include "checkwait_smtpreply.h"
 #include "mail-functions.h"
+#include "getlistaddr.h"
+#include "getlistdelim.h"
 #include "send_mail.h"
 #include "log_error.h"
 #include "init_sockfd.h"
@@ -179,3 +181,177 @@ endsmtp(int *sockfd)
        return retval;
 }
 
+int do_bouncemail(int listfd, const char *from)
+{
+       /* expected format for the from: "something+anything-<number>-anything@anything" */
+       char *tofree;
+       char *myfrom = xstrdup(from);
+       char *listdelim = fgetlistdelim(listfd);
+       char *addr, *num, *c;
+
+       tofree = myfrom;
+       if((c = strchr(myfrom, '@')) == NULL) {
+               free(myfrom);
+               free(listdelim);
+               return 0; /* Success when malformed 'from' */
+       }
+       *c = '\0';
+       num = strrchr(myfrom, '-');
+       if (num == NULL) {
+               free(tofree);
+               return (0); /* Success when malformed 'from' */
+       }
+       num++;
+       c = strstr(myfrom, listdelim);
+       if (c == NULL) {
+               free(tofree);
+               return (0); /* Success when malformed 'from' */
+       }
+       myfrom = strchr(c, '-'); /* malformed entry with delimiter after the -num */
+       if (myfrom == NULL) {
+               free(tofree);
+               return (0);
+       }
+       myfrom++;
+       if (num <= myfrom) {
+               free(tofree);
+               return (0); /* Success when malformed 'from' */
+       }
+       addr = xstrndup(myfrom, num - myfrom - 1);
+       free(listdelim);
+
+       bouncemail(listfd, num, addr);
+       return 1;
+}
+
+int
+send_mail(int sockfd, struct mail *mail, int listfd, bool bounce)
+{
+       int retval = 0;
+       char *reply, *reply2, *tohdr;
+
+       if(sockfd == -1)
+               return EBADF;
+
+       if(strchr(mail->to, '@') == NULL) {
+               errno = 0;
+               log_error(LOG_ARGS, "No @ in address, ignoring %s",
+                   mail->to);
+               return 0;
+       }
+       
+       retval = write_mail_from(sockfd, mail->from, "");
+       if(retval) {
+               log_error(LOG_ARGS, "Could not write MAIL FROM\n");
+               return retval;
+       }
+       reply = checkwait_smtpreply(sockfd, MLMMJ_FROM);
+       if(reply) {
+               log_error(LOG_ARGS, "Error in MAIL FROM. Reply = [%s]",
+                               reply);
+               free(reply);
+               write_rset(sockfd);
+               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               if (reply2 != NULL) free(reply2);
+               return MLMMJ_FROM;
+       }
+       retval = write_rcpt_to(sockfd, mail->to);
+       if(retval) {
+               log_error(LOG_ARGS, "Could not write RCPT TO:\n");
+               return retval;
+       }
+
+       reply = checkwait_smtpreply(sockfd, MLMMJ_RCPTTO);
+       if(reply) {
+               write_rset(sockfd);
+               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               if (reply2 != NULL) free(reply2);
+               if(bounce && ((reply[0] == '4') || (reply[0] == '5'))
+                               && (reply[1] == '5')) {
+                       free(reply);
+                       return do_bouncemail(listfd, mail->from);
+               } else {
+                       log_error(LOG_ARGS, "Error in RCPT TO. Reply = [%s]",
+                                       reply);
+                       free(reply);
+                       return MLMMJ_RCPTTO;
+               }
+       }
+
+       retval = write_data(sockfd);
+       if(retval) {
+               log_error(LOG_ARGS, "Could not write DATA\b");
+               return retval;
+       }
+
+       reply = checkwait_smtpreply(sockfd, MLMMJ_DATA);
+       if(reply) {
+               log_error(LOG_ARGS, "Error with DATA. Reply = [%s]", reply);
+               free(reply);
+               write_rset(sockfd);
+               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               if (reply2 != NULL) free(reply2);
+               return MLMMJ_DATA;
+       }
+
+       if(mail->replyto) {
+               retval = write_replyto(sockfd, mail->replyto);
+               if(retval) {
+                       log_error(LOG_ARGS, "Could not write reply-to addr.\n");
+                       return retval;
+               }
+       }
+
+       if(mail->addtohdr)
+               xasprintf(&tohdr, "To: %s\r\n", mail->to);
+       else
+               tohdr = NULL;
+
+       if(mail->inmem) {
+               retval = dprintf(sockfd, "%s", mail->hdrs);
+               if(retval < 0) {
+                       log_error(LOG_ARGS, "Could not write mailheaders.\n");
+                       return retval;
+               }
+               if(tohdr) {
+                       retval = dprintf(sockfd, "%s", tohdr);
+                       if(retval < 0) {
+                               log_error(LOG_ARGS, "Could not write To:.\n");
+                               return retval;
+                       }
+                       free(tohdr);
+               }
+               retval = dprintf(sockfd, "%s", mail->body);
+               if(retval < 0) {
+                       log_error(LOG_ARGS, "Could not write mailbody.\n");
+                       return retval;
+               }
+       } else {
+               retval = write_mailbody_from_map(sockfd, mail->map, mail->size,
+                                                tohdr);
+               if(retval) {
+                       log_error(LOG_ARGS, "Could not write mail\n");
+                       return retval;
+               }
+       }
+
+       retval = write_dot(sockfd);
+       if(retval) {
+               log_error(LOG_ARGS, "Could not write <CR><LF>.<CR><LF>\n");
+               return retval;
+       }
+
+       reply = checkwait_smtpreply(sockfd, MLMMJ_DOT);
+       if(reply) {
+               log_error(LOG_ARGS, "Mailserver did not ack end of mail.\n"
+                               "<CR><LF>.<CR><LF> was written, to no"
+                               "avail. Reply = [%s]", reply);
+               free(reply);
+               write_rset(sockfd);
+               reply2 = checkwait_smtpreply(sockfd, MLMMJ_RSET);
+               if (reply2 != NULL) free(reply2);
+               return MLMMJ_DOT;
+       }
+
+       return 0;
+}
index 2732cbf1a841db1e254d047f10b91403e5a214f2..57b94de5ba23b0050ccd196cc033e6801935a4ca 100644 (file)
@@ -85,6 +85,7 @@ ATF_TC_WITHOUT_HEAD(smtp_bad_greetings);
 ATF_TC_WITHOUT_HEAD(smtp_bad_ehlo);
 ATF_TC_WITHOUT_HEAD(smtp_no_ehlo);
 ATF_TC_WITHOUT_HEAD(endsmtp);
+ATF_TC_WITHOUT_HEAD(do_bouncemail);
 
 #ifndef NELEM
 #define NELEM(array)    (sizeof(array) / sizeof((array)[0]))
@@ -1187,6 +1188,34 @@ ATF_TC_BODY(endsmtp, tc)
        ATF_REQUIRE_EQ(endsmtp(&sock), 0);
 }
 
+ATF_TC_BODY(do_bouncemail, tc)
+{
+       init_ml(true);
+       int lfd = open("list", O_DIRECTORY);
+       /* malformed */
+       ATF_REQUIRE_EQ(do_bouncemail(lfd, "plop"), 0);
+
+       /* malformed, missing number */
+       ATF_REQUIRE_EQ(do_bouncemail(lfd, "plop@meh"), 0);
+
+       /* malformed, empty numbr */
+       ATF_REQUIRE_EQ(do_bouncemail(lfd, "plop-@meh"), 0);
+
+       /* no listdelim */
+       ATF_REQUIRE_EQ(do_bouncemail(lfd, "plop-0@meh"), 0);
+
+       /* listdelim before */
+       ATF_REQUIRE_EQ(do_bouncemail(lfd, "plop+-0@meh"), 0);
+
+       /* listdelim before */
+       ATF_REQUIRE_EQ(do_bouncemail(lfd, "plop-0+@meh"), 0);
+
+       /* 2 ticks */
+       ATF_REQUIRE_EQ(do_bouncemail(lfd, "plop+--bla@meh"), 1);
+
+       close(lfd);
+}
+
 ATF_TP_ADD_TCS(tp)
 {
        ATF_TP_ADD_TC(tp, random_int);
@@ -1225,6 +1254,7 @@ ATF_TP_ADD_TCS(tp)
        ATF_TP_ADD_TC(tp, smtp_bad_ehlo);
        ATF_TP_ADD_TC(tp, smtp_no_ehlo);
        ATF_TP_ADD_TC(tp, endsmtp);
+       ATF_TP_ADD_TC(tp, do_bouncemail);
 
        return (atf_no_error());
 }