Hi,

please find below a diff which enhances deliver to LMTP.

Gilles suggested to bring this diff to misc@ to gain a wider audience
and hopefully receive some comments from actual LMTP users.

tl;dr
  "deliver to lmtp" delivers to (system) users only, making it hard to
  be used in common virtual users setups (with single system user).
  Therefore, I provide a diff which adds a parameter to
  specify/expands RCPT TO within LMTP.

This was described earlier already [1], but no solution.

Let me explain the rationale/background of the diff below a bit: One of
my production servers runs Sendmail/Dovecot and I would like to migrate
it to OpenSMTPD/Dovecot.  The server uses virtual users in a common
scenario: with all mail addresses mapped to a single system user/uid/gid
(called vmail in my case).  Dovecot uses a (static) userdb to map the
IMAP maildirs and addresses.  Now I have three options to bring incoming
mails from OpenSMTPD to Dovecot:

1. deliver to maildir
  Unfortunately, not an option in my case, because I heavily use Sieve
  and Quotas on the Dovecot server.  Both require updates/processing on
  delivery.

2. deliver to mda "dovecot-lda -a ${rcpt} ..."
  Would work fine, and is what I have done before with Sendmail as
  well.  But requires me to fiddle with dovecot-lda options, poor
  performance, and expansions and user permissions, as it needs
  adjusting for the "single system user all virtual" setup mentioned
  above... thus a bit annoying to setup.

3. deliver to lmtp "/var/dovecot/lmtp"
  IMHO, the most easy and straight forward option, also preferred
  nowadays, due to better performance [2].  Not useable in my
  scenarios, as deliver_lmtp.c always uses the (system) user in
  RCPT TO.

So the diff below addresses this and makes it possible to
specify/expand the RCPT TO.

Items for Discussion:
-  In a first version of this diff and as suggested in [1], I added a
  new keyword RCPT, e.g. ... deliver to lmtp "..." rcpt "${rcpt}", I
  decided to leave it away as it simplifies things and does not require
  to mess with rule_to_text() and A_LMTP
-  In a second version I added an additional variable to store and
  separate actual lmtp host:port/socket and expanded recipient...
  (similar to r_delivery_user) but this required a lot of more changes
  in several files to copy things around, and even an additional enum
  expand_type might be required: EXPAND_LMTP, or something. So for the
  sake of simplicity I decided against this approach.
-  Another approach to solve this problem, as suggested in Dovecot
  Wiki [3], is to override the RCPT TO with setting
  X-Original-Recipient Header (different approach, different diff).
  I do not like this idea of injecting additional header in LMTP
  session, thus I went with the approach below.

Please: comments, suggestions, other approaches, right/wrong direction,
rants, flames,... ?

Thanks,
Regards,
Joerg

[1] https://www.mail-archive.com/[email protected]/msg00531.html
[2] http://wiki2.dovecot.org/LDA
[3] http://wiki2.dovecot.org/LMTP


----------------------------------------------------------------


smtpd/delivery_lmtp.c | 10 ++++------
smtpd/parse.y         | 22 ++++++++++++++++++++++
smtpd/smtpd.conf.5    | 13 ++++++++++++-
3 files changed, 38 insertions(+), 7 deletions(-)

diff --git a/smtpd/delivery_lmtp.c b/smtpd/delivery_lmtp.c
index 5080c46..6c55994 100644
--- a/smtpd/delivery_lmtp.c
+++ b/smtpd/delivery_lmtp.c
@@ -137,16 +137,14 @@ unix_socket(char *path) {
static void
delivery_lmtp_open(struct deliver *deliver)
{
-     char *buffer;
-     char *lbuf;
+     char *buffer, *lbuf, *rcpt = deliver->to;
    char lhloname[255];
    int s;
-     FILE    *fp;
+     FILE    *fp = NULL;
    enum lmtp_state state = LMTP_BANNER;
    size_t    len;

-     fp = NULL;
-
+     strsep(&rcpt, " ");
    if (deliver->to[0] == '/')
        s = unix_socket(deliver->to);
    else
@@ -183,7 +181,7 @@ delivery_lmtp_open(struct deliver *deliver)
        case LMTP_MAIL_FROM:
            if (buffer[0] != '2')
                errx(1, "MAIL FROM rejected: %s\n", buffer);
-             fprintf(fp, "RCPT TO:<%s>\r\n", deliver->user);
+             fprintf(fp, "RCPT TO:<%s>\r\n", rcpt ? rcpt : deliver->user);
            state = LMTP_RCPT_TO;
            break;
            
diff --git a/smtpd/parse.y b/smtpd/parse.y
index b73ed7f..8523dd4 100644
--- a/smtpd/parse.y
+++ b/smtpd/parse.y
@@ -1161,6 +1161,28 @@ deliver_action    : DELIVER TO MAILDIR            {
               fatal("invalid lmtp destination");
           free($4);
       }
+        | DELIVER TO LMTP STRING STRING deliver_as    {
+            rule->r_action = A_LMTP;
+            if (strchr($4, ':') || $4[0] == '/') {
+                if (strlcpy(rule->r_value.buffer, $4,
+                    sizeof(rule->r_value.buffer))
+                    >= sizeof(rule->r_value.buffer))
+                    fatal("lmtp destination too long");
+            } else
+                fatal("invalid lmtp destination");
+            if (strchr($5, '%')) {
+                if (strlcat(rule->r_value.buffer, " ",
+                    sizeof(rule->r_value.buffer))
+                    >= sizeof(rule->r_value.buffer) ||
+                    strlcat(rule->r_value.buffer, $5,
+                    sizeof(rule->r_value.buffer))
+                    >= sizeof(rule->r_value.buffer))
+                    fatal("lmtp recipient too long");
+            } else
+                fatal("invalid lmtp recipient");
+            free($4);
+            free($5);
+        }
       | DELIVER TO MDA STRING deliver_as       {
           rule->r_action = A_MDA;
           if (strlcpy(rule->r_value.buffer, $4,
diff --git a/smtpd/smtpd.conf.5 b/smtpd/smtpd.conf.5
index 72d3811..eb76ad6 100644
--- a/smtpd/smtpd.conf.5
+++ b/smtpd/smtpd.conf.5
@@ -287,13 +287,22 @@ accept for domain opensmtpd.org forward-only
.Pp
Finally, the method of delivery is specified:
.Bl -tag -width Ds
-.It Ic deliver to lmtp Op Ar host : Ns Ar port | socket
+.It Xo
+.Ic deliver to lmtp
+.Op Ar host : Ns Ar port | socket
+.Op Ar rcpt
+.Xc
Mail is delivered to
.Ar host : Ns Ar port ,
or to the
.Ux
.Ar socket
over LMTP.
+Optionally,
+.Ar rcpt
+might specify a recipient.
+The latter parameter may use conversion specifiers that are expanded before use
+.Pq see Sx FORMAT SPECIFIERS .
.It Ic deliver to maildir Ar path
Mail is added to a maildir.
Its location,
@@ -911,7 +920,9 @@ descriptions.
.Ss FORMAT SPECIFIERS
Some configuration directives support expansion of their parameters at runtime.
Such directives (for example
+.Ic deliver to lmtp ,
.Ic deliver to maildir ,
+and
.Ic deliver to mda )
may use format specifiers which will be expanded before delivery or
relaying.

Reply via email to