[exim-dev] [PATCH] Implement redirect

Top Page
Delete this message
Reply to this message
Author: Robert Millan
Date:  
To: exim-dev
Subject: [exim-dev] [PATCH] Implement redirect

Hi!

The attached patch implements code 551 as described in RFC 2821 section 3.4.

The idea is that the originator MTA is told via DSN which address is the final
destination of this email, instead of transparently forwarding it.

The following code is returned by server:

551 User not local; please try <foo@???>

The main advantage with this is that it circumvents problems originated with SPF
and forwarding.

In order to activate it, system users just need to:

echo foo@??? > ~/.redirect

--
Robert Millan
Only in exim4-4.62.old/: Local
diff -ur exim4-4.62.old/src/smtp_in.c exim4-4.62/src/smtp_in.c
--- exim4-4.62.old/src/smtp_in.c    2006-04-28 12:32:23.000000000 +0200
+++ exim4-4.62/src/smtp_in.c    2006-06-28 20:17:04.188691672 +0200
@@ -3064,6 +3064,88 @@
         }
       }


+    /*
+      251/551 codes as described in RFC 2821
+
+      When ~/.redirect is present, we grab an email address from it.  Then:
+        - If ~/.forward exists, issue: "251 User not local; will forward to <address>"
+        - If it doesn't, issue: "551 User not local; please try <address>"
+    */
+    {
+      int fd;
+      struct passwd *p;
+      char *user, *filename;
+      struct stat st;
+
+      int rc;
+      BOOL yield;
+      struct stat statbuf;
+      address_item *generated = NULL;
+      uschar *error, *filebuf;
+
+      user = strdup (recipient);
+      *(parse_find_at (user)) = '\0';
+      p = getpwnam (user);
+      free (user);
+      if (p == NULL)
+        goto end;
+
+      asprintf (&filename, "%s/.redirect", p->pw_dir);
+      fd = open (filename, O_RDONLY);
+      free (filename);
+
+      if (fd == -1)
+        goto end;
+
+      if (fstat(fd, &statbuf) != 0)
+        goto end;
+
+      filebuf = store_get(statbuf.st_size + 1);
+      rc = read(fd, filebuf, statbuf.st_size);
+      close(fd);
+
+      if (rc != statbuf.st_size)
+        goto end;
+
+      filebuf[statbuf.st_size] = 0;
+
+      /* .redirect file syntax is like plain .forward */
+
+      yield = parse_forward_list(filebuf,
+        RDO_REWRITE,
+        &generated,                     /* for generated addresses */
+        &error,                         /* for errors */
+        deliver_domain,                 /* incoming domain for \name */
+        NULL,                           /* no check on includes */
+        NULL);                          /* fail on syntax errors */
+
+      switch(yield)
+        {
+        case FF_FAIL:
+        case FF_BLACKHOLE:
+        case FF_ERROR:
+        goto end;
+        }
+
+      if (generated == NULL)
+        goto end;
+
+      asprintf (&filename, "%s/.forward", p->pw_dir);
+      if (stat (filename, &st) == 0)
+         {
+            smtp_printf("251 User not local; will forward to <%s>\r\n", generated->address);
+            receive_add_recipient(recipient, -1);
+         }
+      else
+         {
+           smtp_printf("551 User not local; please try <%s>\r\n", generated->address);
+         }
+      free (filename);
+
+      break;
+    }
+    end:
+
     /* Check maximum allowed */


     if (rcpt_count > recipients_max && recipients_max > 0)
Only in exim4-4.62/src: smtp_in.c~