]> git.ipfire.org Git - people/ms/dma.git/blobdiff - mail.c
dma - Fix security hole (#46)
[people/ms/dma.git] / mail.c
diff --git a/mail.c b/mail.c
index 0058e89b71b5775d6273d6a211da3ce961b8dd44..a6d11fcae685a9dd1440fd4782de4a5628826cee 100644 (file)
--- a/mail.c
+++ b/mail.c
@@ -1,8 +1,9 @@
 /*
+ * Copyright (c) 2008-2014, Simon Schubert <2@0x2c.org>.
  * Copyright (c) 2008 The DragonFly Project.  All rights reserved.
  *
  * This code is derived from software contributed to The DragonFly Project
- * by Simon 'corecode' Schubert <corecode@fs.ei.tum.de>.
+ * by Simon Schubert <2@0x2c.org>.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -33,6 +34,8 @@
  */
 
 #include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
 #include <syslog.h>
 #include <unistd.h>
 
@@ -49,13 +52,13 @@ bounce(struct qitem *it, const char *reason)
        /* Don't bounce bounced mails */
        if (it->sender[0] == 0) {
                syslog(LOG_INFO, "can not bounce a bounce message, discarding");
-               exit(1);
+               exit(EX_SOFTWARE);
        }
 
        bzero(&bounceq, sizeof(bounceq));
        LIST_INIT(&bounceq.queue);
        bounceq.sender = "";
-       if (add_recp(&bounceq, it->sender, 1) != 0)
+       if (add_recp(&bounceq, it->sender, EXPAND_WILDCARD) != 0)
                goto fail;
 
        if (newspoolf(&bounceq) != 0)
@@ -67,7 +70,7 @@ bounce(struct qitem *it, const char *reason)
        error = fprintf(bounceq.mailf,
                "Received: from MAILER-DAEMON\n"
                "\tid %s\n"
-               "\tby %s (%s)\n"
+               "\tby %s (%s);\n"
                "\t%s\n"
                "X-Original-To: <%s>\n"
                "From: MAILER-DAEMON <>\n"
@@ -94,7 +97,7 @@ bounce(struct qitem *it, const char *reason)
                VERSION, hostname(),
                it->addr,
                reason,
-               config->features & FULLBOUNCE ?
+               config.features & FULLBOUNCE ?
                    "Original message follows." :
                    "Message headers follow.");
        if (error < 0)
@@ -102,7 +105,7 @@ bounce(struct qitem *it, const char *reason)
 
        if (fseek(it->mailf, 0, SEEK_SET) != 0)
                goto fail;
-       if (config->features & FULLBOUNCE) {
+       if (config.features & FULLBOUNCE) {
                while ((pos = fread(line, 1, sizeof(line), it->mailf)) > 0) {
                        if (fwrite(line, 1, pos, bounceq.mailf) != pos)
                                goto fail;
@@ -130,7 +133,7 @@ bounce(struct qitem *it, const char *reason)
 fail:
        syslog(LOG_CRIT, "error creating bounce: %m");
        delqueue(it);
-       exit(1);
+       exit(EX_IOERR);
 }
 
 struct parse_state {
@@ -268,7 +271,9 @@ again:
                        goto skip;
 
                case '<':
+                       /* this is the real address now */
                        ps->brackets = 1;
+                       ps->pos = 0;
                        goto skip;
 
                case '>':
@@ -286,6 +291,16 @@ again:
 
                case ',':
                case ';':
+                       /*
+                        * Next address, copy previous one.
+                        * However, we might be directly after
+                        * a <address>, or have two consecutive
+                        * commas.
+                        * Skip the comma unless there is
+                        * really something to copy.
+                        */
+                       if (ps->pos == 0)
+                               goto skip;
                        s++;
                        goto newaddr;
 
@@ -318,10 +333,11 @@ newaddr:
        ps->pos = 0;
        addr = strdup(ps->addr);
        if (addr == NULL)
-               errlog(1, NULL);
+               errlog(EX_SOFTWARE, NULL);
+
+       if (add_recp(queue, addr, EXPAND_WILDCARD) != 0)
+               errlogx(EX_DATAERR, "invalid recipient `%s'", addr);
 
-       add_recp(queue, addr, 1);
-       fprintf(stderr, "parsed `%s'\n", addr);
        goto again;
 }
 
@@ -336,6 +352,7 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
        int had_from = 0;
        int had_messagid = 0;
        int had_date = 0;
+       int had_last_line = 0;
        int nocopy = 0;
 
        parse_state.state = NONE;
@@ -344,9 +361,9 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
                "Received: from %s (uid %d)\n"
                "\t(envelope-from %s)\n"
                "\tid %s\n"
-               "\tby %s (%s)\n"
+               "\tby %s (%s);\n"
                "\t%s\n",
-               username, getuid(),
+               username, useruid,
                queue->sender,
                queue->id,
                hostname(), VERSION,
@@ -355,12 +372,22 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
                return (-1);
 
        while (!feof(stdin)) {
-               if (fgets(line, sizeof(line), stdin) == NULL)
+               if (fgets(line, sizeof(line) - 1, stdin) == NULL)
                        break;
+               if (had_last_line)
+                       errlogx(EX_DATAERR, "bad mail input format:"
+                               " from %s (uid %d) (envelope-from %s)",
+                               username, useruid, queue->sender);
                linelen = strlen(line);
                if (linelen == 0 || line[linelen - 1] != '\n') {
-                       errno = EINVAL;         /* XXX mark permanent errors */
-                       return (-1);
+                       /*
+                        * This line did not end with a newline character.
+                        * If we fix it, it better be the last line of
+                        * the file.
+                        */
+                       line[linelen] = '\n';
+                       line[linelen + 1] = 0;
+                       had_last_line = 1;
                }
                if (!had_headers) {
                        /*
@@ -381,7 +408,7 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
 
                        if (parse_state.state != NONE) {
                                if (parse_addrs(&parse_state, line, queue) < 0) {
-                                       errlogx(1, "invalid address in header\n");
+                                       errlogx(EX_DATAERR, "invalid address in header\n");
                                        /* NOTREACHED */
                                }
                        }
@@ -392,7 +419,7 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
                                        strprefixcmp(line, "Bcc:") == 0)) {
                                parse_state.state = START;
                                if (parse_addrs(&parse_state, line, queue) < 0) {
-                                       errlogx(1, "invalid address in header\n");
+                                       errlogx(EX_DATAERR, "invalid address in header\n");
                                        /* NOTREACHED */
                                }
                        }
@@ -405,10 +432,13 @@ readmail(struct queue *queue, int nodot, int recp_from_header)
                                        had_date = 1;
                                        snprintf(line, sizeof(line), "Date: %s\n", rfc822date());
                                } else if (!had_messagid) {
-                                       /* XXX better msgid, assign earlier and log? */
+                                       /* XXX msgid, assign earlier and log? */
                                        had_messagid = 1;
-                                       snprintf(line, sizeof(line), "Message-Id: <%s@%s>\n",
-                                                queue->id, hostname());
+                                       snprintf(line, sizeof(line), "Message-Id: <%"PRIxMAX".%s.%"PRIxMAX"@%s>\n",
+                                                (uintmax_t)time(NULL),
+                                                queue->id,
+                                                (uintmax_t)random(),
+                                                hostname());
                                } else if (!had_from) {
                                        had_from = 1;
                                        snprintf(line, sizeof(line), "From: <%s>\n", queue->sender);