[Exim] [patch] LMTP over a unix socket

Top Page
Delete this message
Reply to this message
Author: Matt Bernstein
Date:  
To: exim-users
Subject: [Exim] [patch] LMTP over a unix socket
I developed this with Cyrus admins in mind--Cyrus 2.1 lmtpd listens on a
unix socket (or a TCP socket, but that's a little heavier)--but it may
well be useful for other systems too. My patch will allow a transport like
the following:

lmtpsock:
driver = lmtp
socket = /var/lib/cyrus/socket/lmtp

It alters the lmtp transport to require either a "command" or a "socket".
Philip will look at it when he has time; perhaps any minor deities on the
list can spot any horrible errors to save him some time :)

The patch doesn't apply cleanly to Exim 3: it could be back-ported, but
otoh that might be no less effort than running convert4r4..

diff -ur exim-4.10.pristine/src/transports/lmtp.c exim-4.10.rogered/src/transports/lmtp.c
--- exim-4.10.pristine/src/transports/lmtp.c    Mon Jul 22 09:59:51 2002
+++ exim-4.10.rogered/src/transports/lmtp.c    Fri Jul 26 11:26:48 2002
@@ -8,6 +8,7 @@


#include "../exim.h"
#include "lmtp.h"
+#include <sys/un.h>

#define PENDING_OK 256

@@ -26,6 +27,8 @@
       (void *)offsetof(transport_instance, batch_max) },
   { "command",           opt_stringptr,
       (void *)offsetof(lmtp_transport_options_block, cmd) },
+  { "socket",            opt_stringptr,
+      (void *)offsetof(lmtp_transport_options_block, skt) },
   { "timeout",           opt_time,
       (void *)offsetof(lmtp_transport_options_block, timeout) }
 };
@@ -40,6 +43,7 @@


 lmtp_transport_options_block lmtp_transport_option_defaults = {
   NULL,           /* cmd */
+  NULL,           /* skt */
   5*60,           /* timeout */
   0               /* options */
 };
@@ -60,11 +64,11 @@
 lmtp_transport_options_block *ob =
   (lmtp_transport_options_block *)(tblock->options_block);


-/* The command field must be set */
+/* Either the command field or the socket field must be set */

-if (ob->cmd == NULL)
+if ((ob->cmd == NULL) && (ob->skt == NULL))
   log_write(0, LOG_PANIC_DIE|LOG_CONFIG,
-    "command must be set for the %s transport", tblock->name);
+    "command or socket must be set for the %s transport", tblock->name);


/* If a fixed uid field is set, then a gid field must also be set. */

@@ -451,6 +455,8 @@
address_item *addr;
uschar buffer[256];
uschar **argv;
+struct sockaddr_un sun;
+int addrlen;

DEBUG(D_transport) debug_printf("%s transport entered\n", tblock->name);

@@ -459,9 +465,35 @@
fails, copy the error information into the second and subsequent addresses. */

 sprintf(CS buffer, "%.50s transport", tblock->name);
-if (!transport_set_up_command(&argv, ob->cmd, TRUE, PANIC, addrlist, buffer,
-     NULL))
-  return FALSE;
+if (ob->cmd != NULL)
+  {
+  DEBUG(D_transport) debug_printf("using command %s\n", ob->cmd);
+  if (!transport_set_up_command(&argv, ob->cmd, TRUE, PANIC, addrlist,
+       buffer, NULL))
+    return FALSE;
+  }
+else
+  {
+  DEBUG(D_transport) debug_printf("using socket %s\n", ob->skt);
+
+  if ((fd_in = fd_out = socket(PF_UNIX, SOCK_STREAM, 0)) == -1)
+    {
+    addrlist->message = string_sprintf(
+      "Failed to set up socket %s for %s transport: %s",
+        sun.sun_path, tblock->name, strerror(errno));
+    return FALSE;
+    }
+  sun.sun_family = AF_UNIX;
+  strncpy(sun.sun_path, ob->skt, 108);
+  addrlen = sizeof(sun);
+  if(connect(fd_out, (struct sockaddr *) &sun, addrlen) == -1)
+    {
+    addrlist->message = string_sprintf(
+      "Failed to connect to socket %s for %s transport: %s",
+        sun.sun_path, tblock->name, strerror(errno));
+    return FALSE;
+    }
+  }


/* If the -N option is set, can't do any more. Presume all has gone well. */

@@ -479,8 +511,8 @@
change. Request that the new process be a process group leader, so we
can kill it and all its children on an error. */

-if ((pid = child_open(argv, NULL, 0, NULL, NULL, &fd_in, &fd_out,
-    NULL, TRUE)) < 0)
+if ((ob->cmd != NULL) && ((pid = child_open(argv, NULL, 0, NULL, NULL,
+    &fd_in, &fd_out, NULL, TRUE)) < 0))
   {
   addrlist->message = string_sprintf(
     "Failed to create child process for %s transport: %s", tblock->name,
diff -ur exim-4.10.pristine/src/transports/lmtp.h exim-4.10.rogered/src/transports/lmtp.h
--- exim-4.10.pristine/src/transports/lmtp.h    Mon Jul 22 09:59:51 2002
+++ exim-4.10.rogered/src/transports/lmtp.h    Fri Jul 26 10:32:28 2002
@@ -9,6 +9,7 @@


typedef struct {
uschar *cmd;
+ uschar *skt;
int timeout;
int options;
} lmtp_transport_options_block;