Hi Gilles,

Please find my diff inline to enable "listen on socket" feature that we have
discussed. I have tested the diff with currently two supported listen options
for this listener, mask-sender and filter. Everything seems to be working OK.

These are the summary of the changes:
* Parser was adjusted to support "listen on socket", should be easier to
  extend to new listener types.
* Reusing config_listener().
* struct smtpd has a new member sc_sock_listener to be used by smtp_enqueu()
* If "listen on socket" was not specified in the config file, a default
  socket listener will be created in parse_config()
* I also removed "struct listener l" from parse.y as it was not being used
  anywhere.
* I have tried to stick to the coding style in the source, and tried to keep
  the diff as small as possible. Please let me know if something is off and
  I will fix it.

If these changes look OK to you, I will create a diff for the man page and
send it through.

Thank you!
--peter



Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/parse.y,v
retrieving revision 1.181
diff -u -p -r1.181 parse.y
--- parse.y     18 Jan 2016 09:19:41 -0000      1.181
+++ parse.y     11 Feb 2016 20:59:11 -0000
@@ -97,7 +97,6 @@ static int             errors = 0;
 struct filter_conf     *filter = NULL;
 struct table           *table = NULL;
 struct rule            *rule = NULL;
-struct listener                 l;
 struct mta_limits      *limits;
 static struct pki      *pki;
 static struct ca       *sca;
@@ -139,8 +138,9 @@ static struct listen_opts {
        uint32_t        options;
 } listen_opts;
 
-static void    create_listener(struct listenerlist *,  struct listen_opts *);
-static void    config_listener(struct listener *,  struct listen_opts *);
+static struct listener *create_sock_listener(struct listen_opts *);
+static void             create_if_listener(struct listenerlist *,  struct 
listen_opts *);
+static void             config_listener(struct listener *,  struct listen_opts 
*);
 
 struct listener        *host_v4(const char *, in_port_t);
 struct listener        *host_v6(const char *, in_port_t);
@@ -156,6 +156,9 @@ static struct filter_conf *create_filter
 static struct filter_conf *create_filter_chain(char *);
 static int add_filter_arg(struct filter_conf *, char *);
 
+static int config_lo_filter(struct listen_opts *, char *);
+static int config_lo_mask_source(struct listen_opts *);
+
 typedef struct {
        union {
                int64_t          number;
@@ -175,7 +178,7 @@ typedef struct {
 %token ACCEPT REJECT INCLUDE ERROR MDA FROM FOR SOURCE MTA PKI SCHEDULER
 %token ARROW AUTH TLS LOCAL VIRTUAL TAG TAGGED ALIAS FILTER KEY CA DHPARAMS
 %token AUTH_OPTIONAL TLS_REQUIRE USERBASE SENDER SENDERS MASK_SOURCE VERIFY 
FORWARDONLY RECIPIENT
-%token CIPHERS RECEIVEDAUTH MASQUERADE ENQUEUER
+%token CIPHERS RECEIVEDAUTH MASQUERADE SOCKET
 %token <v.string>      STRING
 %token  <v.number>     NUMBER
 %type  <v.table>       table
@@ -403,7 +406,19 @@ pki                : opt_pki pki
                | /* empty */
                ;
 
-opt_listen             : INET4                 {
+opt_sock_listen : FILTER STRING {
+                       if (config_lo_filter(&listen_opts, $2)) {
+                               YYERROR;
+                       }
+               }
+               | MASK_SOURCE {
+                       if (config_lo_mask_source(&listen_opts)) {
+                               YYERROR;
+                       }
+               }
+               ;
+
+opt_if_listen : INET4 {
                        if (listen_opts.options & LO_FAMILY) {
                                yyerror("address family already specified");
                                YYERROR;
@@ -451,13 +466,10 @@ opt_listen        : INET4                 {
                        listen_opts.port = $2;
                }
                | FILTER STRING                 {
-                       if (listen_opts.options & LO_FILTER) {
-                               yyerror("filter already specified");
+                       if (config_lo_filter(&listen_opts, $2)) {
                                YYERROR;
                        }
-                       listen_opts.options |= LO_FILTER;
-                       listen_opts.filtername = $2;
-               }
+}
                | SMTPS                         {
                        if (listen_opts.options & LO_SSL) {
                                yyerror("TLS mode already specified");
@@ -596,12 +608,9 @@ opt_listen         : INET4                 {
                        listen_opts.hostnametable = t;
                }
                | MASK_SOURCE   {
-                       if (listen_opts.options & LO_MASKSOURCE) {
-                               yyerror("mask-source already specified");
+                       if (config_lo_mask_source(&listen_opts)) {
                                YYERROR;
                        }
-                       listen_opts.options |= LO_MASKSOURCE;
-                       listen_opts.flags |= F_MASK_SOURCE;
                }
                | RECEIVEDAUTH  {
                        if (listen_opts.options & LO_RECEIVEDAUTH) {
@@ -653,7 +662,33 @@ opt_listen         : INET4                 {
                }
                ;
 
-listen         : opt_listen listen
+listener_type  : socket_listener
+               | interface_listener
+               ;
+
+socket_listener        : SOCKET sock_listen {
+                       if (conf->sc_sock_listener) {
+                               yyerror("socket listener already configured");
+                               YYERROR;
+                       }
+                       conf->sc_sock_listener = 
create_sock_listener(&listen_opts);
+               }
+               ;
+
+interface_listener:
+               STRING if_listen {
+                       listen_opts.family = AF_UNSPEC;
+                       listen_opts.flags |= F_EXT_DSN;
+                       listen_opts.ifx = $1;
+                       create_if_listener(conf->sc_listeners, &listen_opts);
+               }
+               ;
+
+sock_listen    : opt_sock_listen sock_listen
+               | /* empty */
+               ;
+
+if_listen      : opt_if_listen if_listen
                | /* empty */
                ;
 
@@ -846,28 +881,8 @@ main               : BOUNCEWARN {
                } limits_mta
                | LIMIT SCHEDULER limits_scheduler
                | LISTEN {
-                       memset(&l, 0, sizeof l);
                        memset(&listen_opts, 0, sizeof listen_opts);
-                       listen_opts.family = AF_UNSPEC;
-                       listen_opts.flags |= F_EXT_DSN;
-               } ON STRING listen {
-                       listen_opts.ifx = $4;
-                       create_listener(conf->sc_listeners, &listen_opts);
-               }
-               | ENQUEUER FILTER STRING {
-                       if (dict_get(&conf->sc_filters, $3) == NULL) {
-                               yyerror("undefined filter \"%s\"", $3);
-                               free($3);
-                               YYERROR;
-                       }
-                       if (strlcpy(conf->sc_enqueue_filter, $3,
-                               sizeof conf->sc_enqueue_filter)
-                           >= sizeof conf->sc_enqueue_filter) {
-                               free($3);
-                               YYERROR;
-                       }
-                       free($3);
-               }
+               } ON listener_type
                | FILTER STRING STRING {
                        if (!strcmp($3, "chain")) {
                                free($3);
@@ -1449,7 +1464,6 @@ lookup(char *s)
                { "dhparams",           DHPARAMS },
                { "domain",             DOMAIN },
                { "encryption",         ENCRYPTION },
-               { "enqueuer",           ENQUEUER },
                { "expire",             EXPIRE },
                { "filter",             FILTER },
                { "for",                FOR },
@@ -1489,6 +1503,7 @@ lookup(char *s)
                { "senders",            SENDERS },
                { "session",            SESSION },
                { "smtps",              SMTPS },
+               { "socket",             SOCKET },
                { "source",             SOURCE },
                { "table",              TABLE },
                { "tag",                TAG },
@@ -1945,6 +1960,12 @@ parse_config(struct smtpd *x_conf, const
        popfile();
        endservent();
 
+       /* If the socket listener was not configured, create a default one. */
+       if (!conf->sc_sock_listener) {
+               memset(&listen_opts, 0, sizeof listen_opts);
+               conf->sc_sock_listener = create_sock_listener(&listen_opts);
+       }
+
        /* Free macros and check which have not been used. */
        for (sym = TAILQ_FIRST(&symhead); sym != NULL; sym = next) {
                next = TAILQ_NEXT(sym, entry);
@@ -2046,8 +2067,21 @@ symget(const char *nam)
        return (NULL);
 }
 
+static struct listener *
+create_sock_listener(struct listen_opts *lo)
+{
+       struct listener *l = xcalloc(1, sizeof(*l), "create_sock_listener");
+       lo->tag = "local";
+       lo->hostname = conf->sc_hostname;
+       l->ss.ss_family = AF_LOCAL;
+       l->ss.ss_len = sizeof(struct sockaddr *);
+       config_listener(l, lo);
+
+       return (l);
+}
+
 static void
-create_listener(struct listenerlist *ll,  struct listen_opts *lo)
+create_if_listener(struct listenerlist *ll,  struct listen_opts *lo)
 {
        uint16_t        flags;
 
@@ -2560,3 +2594,28 @@ add_filter_arg(struct filter_conf *f, ch
 
        return (1);
 }
+
+static int
+config_lo_filter(struct listen_opts *lo, char *filter_name) {
+       if (lo->options & LO_FILTER) {
+               yyerror("filter already specified");
+               return -1;
+       }
+       lo->options |= LO_FILTER;
+       lo->filtername = filter_name;
+
+       return 0;
+}
+
+static int
+config_lo_mask_source(struct listen_opts *lo) {
+       if (lo->options & LO_MASKSOURCE) {
+               yyerror("mask-source already specified");
+               return -1;
+       }
+       lo->options |= LO_MASKSOURCE;
+       lo->flags |= F_MASK_SOURCE;
+
+       return 0;
+}
+
Index: smtp.c
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtp.c,v
retrieving revision 1.152
diff -u -p -r1.152 smtp.c
--- smtp.c      8 Jan 2016 21:31:06 -0000       1.152
+++ smtp.c      11 Feb 2016 20:59:11 -0000
@@ -219,20 +219,9 @@ smtp_resume(void)
 static int
 smtp_enqueue(uid_t *euid)
 {
-       static struct listener   local, *listener = NULL;
-       char                     buf[HOST_NAME_MAX+1], *hostname;
-       int                      fd[2];
-
-       if (listener == NULL) {
-               listener = &local;
-               (void)strlcpy(listener->tag, "local", sizeof(listener->tag));
-               listener->ss.ss_family = AF_LOCAL;
-               listener->ss.ss_len = sizeof(struct sockaddr *);
-               (void)strlcpy(listener->hostname, env->sc_hostname,
-                   sizeof(listener->hostname));
-               (void)strlcpy(listener->filter, env->sc_enqueue_filter,
-                   sizeof listener->filter);
-       }
+       struct listener  *listener = env->sc_sock_listener;
+       char             buf[HOST_NAME_MAX+1], *hostname;
+       int              fd[2];
 
        /*
         * Some enqueue requests buffered in IMSG may still arrive even after
Index: smtpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/smtpd/smtpd.h,v
retrieving revision 1.511
diff -u -p -r1.511 smtpd.h
--- smtpd.h     5 Feb 2016 19:21:04 -0000       1.511
+++ smtpd.h     11 Feb 2016 20:59:11 -0000
@@ -613,6 +613,9 @@ struct smtpd {
 
        time_t                                   sc_uptime;
 
+       /* This is a listener for a local socket used by smtp_enqueue(). */
+       struct listener                         *sc_sock_listener;
+
        TAILQ_HEAD(listenerlist, listener)      *sc_listeners;
 
        TAILQ_HEAD(rulelist, rule)              *sc_rules;

Reply via email to