]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.11.9 v2.11.9
authorWietse Venema <wietse@porcupine.org>
Sun, 1 Jan 2017 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <postfix-users@dukhovni.org>
Mon, 2 Jan 2017 18:28:51 +0000 (13:28 -0500)
12 files changed:
postfix/HISTORY
postfix/src/global/mail_version.h
postfix/src/postscreen/postscreen.c
postfix/src/postscreen/postscreen.h
postfix/src/postscreen/postscreen_early.c
postfix/src/postscreen/postscreen_misc.c
postfix/src/postscreen/postscreen_state.c
postfix/src/postscreen/postscreen_tests.c
postfix/src/postsuper/postsuper.c
postfix/src/smtpd/smtpd.c
postfix/src/smtpd/smtpd_check.c
postfix/src/virtual/mailbox.c

index 14cd86f428e7de5c6ab1594cbed4b837f48ea11f..7738a494ffb154526fe232ae7fce44166b672397 100644 (file)
@@ -19750,3 +19750,33 @@ Apologies for any names omitted.
 20160515
 
        Portability: OpenBSD 6.0. Files: makedefs, util/sys_defs.h.
+
+20160717
+
+       Bugfix (introduced: Postfix 1.1): the virtual(8) delivery
+       agent discarded the error result from vstream_fseek().
+       File: virtual/mailbox.c.
+
+20160730
+
+       Bugfix (introduced: 20090614): with concurrent connections
+       from the same client IP address, and after-220 tests enabled,
+       postscreen could overwrite the cached "all tests completed"
+       result of one connection that completed the after-220 tests,
+       with the "some tests not completed" result of a concurrent
+       connection where the client hung up later, without completing
+       the after-220 tests.
+
+20161105
+
+       Bugfix (introduced: Postfix 1.1): the postsuper command did
+       not count a successful rename operation after error recovery.
+       Problem reported by Markus Schönhaber. File: postsuper/postsuper.c.
+
+20161220
+
+       Bugfix (introduced: Postfix 2.1.0): the Postfix SMTP daemon
+       did not query sender_canonical_maps when rejecting unknown
+       senders with "smtpd_reject_unlisted_recipient = yes" or
+       with reject_unlisted_sender.  Stephen R. van den Berg (Mr.
+       procmail).  Files: smtpd/smtpd.c, smtpd/smtpd_check.c.
index 2596354859c040e4dde58c718b3c26a44a4eb302..2047081717e88e80586ff15cd0212d4d61646950 100644 (file)
@@ -20,8 +20,8 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20150515"
-#define MAIL_VERSION_NUMBER    "2.11.8"
+#define MAIL_RELEASE_DATE      "20170101"
+#define MAIL_VERSION_NUMBER    "2.11.9"
 
 #ifdef SNAPSHOT
 #define MAIL_VERSION_DATE      "-" MAIL_RELEASE_DATE
index 711cad8361c310401b7086d8fa8353ddcac21fea..b62aac33662698509a630555fdda5dbf65257aff 100644 (file)
@@ -754,6 +754,7 @@ static void psc_endpt_lookup_done(int endpt_status,
      * valid.
      */
     if ((state->flags & PSC_STATE_MASK_ANY_FAIL) == 0
+       && state->client_info->concurrency == 1
        && psc_cache_map != 0
        && (stamp_str = psc_cache_lookup(psc_cache_map, state->smtp_client_addr)) != 0) {
        saved_flags = state->flags;
@@ -767,6 +768,13 @@ static void psc_endpt_lookup_done(int endpt_status,
            psc_conclude(state);
            return;
        }
+    } else if (state->client_info->concurrency > 1) {
+       saved_flags = state->flags;
+       psc_todo_tests(state, event_time());
+       state->flags |= saved_flags;
+       if (msg_verbose)
+           msg_info("%s: new + recent flags: %s",
+                    myname, psc_print_state_flags(state->flags, myname));
     } else {
        saved_flags = state->flags;
        psc_new_tests(state);
@@ -818,6 +826,7 @@ static int psc_cache_validator(const char *client_addr,
                                       char *unused_context)
 {
     PSC_STATE dummy;
+    PSC_CLIENT_INFO dummy_client_info;
 
     /*
      * This function is called by the cache cleanup pseudo thread.
@@ -827,6 +836,7 @@ static int psc_cache_validator(const char *client_addr,
      * silly logging we remove the cache entry only after all tests have
      * expired longer ago than the cache retention time.
      */
+    dummy.client_info = &dummy_client_info;
     psc_parse_tests(&dummy, stamp_str, event_time() - var_psc_cache_ret);
     return ((dummy.flags & PSC_STATE_MASK_ANY_TODO) == 0);
 }
index ebc048a0225ccd5d8c40ff2bdc54c5c9d7206dab..68e8f37df65cdf1a0153d5d5ec16c45990fb2d88 100644 (file)
 
 #define PSC_TINDX_BYTNAME(tname) (PSC_TINDX_ ## tname)
 
+ /*
+  * Per-client shared state.
+  */
+typedef struct {
+    int     concurrency;               /* per-client */
+    int     pass_new_count;            /* per-client */
+    time_t  expire_time[PSC_TINDX_COUNT];      /* per-test expiration */
+} PSC_CLIENT_INFO;
+
  /*
   * Per-session state.
   */
@@ -66,13 +75,12 @@ typedef struct {
     char   *smtp_client_port;          /* client port */
     char   *smtp_server_addr;          /* server address */
     char   *smtp_server_port;          /* server port */
-    int     client_concurrency;                /* per-client */
     const char *final_reply;           /* cause for hanging up */
     VSTRING *send_buf;                 /* pending output */
     /* Test context. */
     struct timeval start_time;         /* start of current test */
     const char *test_name;             /* name of current test */
-    time_t  expire_time[PSC_TINDX_COUNT];      /* per-test expiration */
+    PSC_CLIENT_INFO *client_info;      /* shared client state */
     VSTRING *dnsbl_reply;              /* dnsbl reject text */
     int     dnsbl_score;               /* saved DNSBL score */
     const char *dnsbl_name;            /* DNSBL name with largest weight */
@@ -94,11 +102,14 @@ typedef struct {
   * Emulate legacy ad-hoc variables on top of indexable time stamps. This
   * avoids massive scar tissue during initial feature development.
   */
-#define pregr_stamp    expire_time[PSC_TINDX_PREGR]
-#define dnsbl_stamp    expire_time[PSC_TINDX_DNSBL]
-#define pipel_stamp    expire_time[PSC_TINDX_PIPEL]
-#define nsmtp_stamp    expire_time[PSC_TINDX_NSMTP]
-#define barlf_stamp    expire_time[PSC_TINDX_BARLF]
+#define pregr_stamp    client_info->expire_time[PSC_TINDX_PREGR]
+#define dnsbl_stamp    client_info->expire_time[PSC_TINDX_DNSBL]
+#define pipel_stamp    client_info->expire_time[PSC_TINDX_PIPEL]
+#define nsmtp_stamp    client_info->expire_time[PSC_TINDX_NSMTP]
+#define barlf_stamp    client_info->expire_time[PSC_TINDX_BARLF]
+
+ /* Minize the patch size for stable releases. */
+#define client_concurrency client_info->concurrency
 
  /*
   * Special expiration time values.
@@ -489,17 +500,21 @@ extern int psc_dnsbl_request(const char *, void (*) (int, char *), char *);
 #define PSC_INIT_TESTS(dst) do { \
        time_t *_it_stamp_p; \
        (dst)->flags = 0; \
-       for (_it_stamp_p = (dst)->expire_time; \
-           _it_stamp_p < (dst)->expire_time + PSC_TINDX_COUNT; \
+       for (_it_stamp_p = (dst)->client_info->expire_time; \
+           _it_stamp_p < (dst)->client_info->expire_time + PSC_TINDX_COUNT; \
            _it_stamp_p++) \
            *_it_stamp_p = PSC_TIME_STAMP_INVALID; \
     } while (0)
+#define PSC_INIT_TEST_FLAGS_ONLY(dst) do { \
+       (dst)->flags = 0; \
+    } while (0)
 #define PSC_BEGIN_TESTS(state, name) do { \
        (state)->test_name = (name); \
        GETTIMEOFDAY(&(state)->start_time); \
     } while (0)
 extern void psc_new_tests(PSC_STATE *);
 extern void psc_parse_tests(PSC_STATE *, const char *, time_t);
+extern void psc_todo_tests(PSC_STATE *, time_t);
 extern char *psc_print_tests(VSTRING *, PSC_STATE *);
 extern char *psc_print_grey_key(VSTRING *, const char *, const char *,
                                        const char *, const char *);
index 4595847153038edc620676531405910eabf6adc1..9ec6a3d8aa2ba4cca7aefb12a8311836257ae433 100644 (file)
@@ -87,8 +87,8 @@ static void psc_whitelist_non_dnsbl(PSC_STATE *state)
                state->flags |= PSC_STATE_FLAG_BYTINDX_PASS(tindx);
            }
            /* Update expiration even if the test was completed or disabled. */
-           if (state->expire_time[tindx] < now + var_psc_dnsbl_ttl)
-               state->expire_time[tindx] = now + var_psc_dnsbl_ttl;
+           if (state->client_info->expire_time[tindx] < now + var_psc_dnsbl_ttl)
+               state->client_info->expire_time[tindx] = now + var_psc_dnsbl_ttl;
        }
     }
 }
index 57a1bb67ddcf82adce9c1971c4bc6bc6c443856f..d54b24f9df057472e6c5b1d02c9ff4fb0947d1b5 100644 (file)
@@ -105,13 +105,17 @@ void    psc_conclude(PSC_STATE *state)
     if ((state->flags & PSC_STATE_MASK_ANY_PASS) != 0
        && (state->flags & PSC_STATE_MASK_ANY_PASS) ==
        PSC_STATE_FLAGS_TODO_TO_PASS(state->flags & PSC_STATE_MASK_ANY_TODO))
-       msg_info("PASS %s [%s]:%s", (state->flags & PSC_STATE_FLAG_NEW) == 0 ?
+       msg_info("PASS %s [%s]:%s", (state->flags & PSC_STATE_FLAG_NEW) == 0
+                || state->client_info->pass_new_count++ > 0 ?
                 "OLD" : "NEW", PSC_CLIENT_ADDR_PORT(state));
 
     /*
      * Update the postscreen cache. This still supports a scenario where a
      * client gets whitelisted in the course of multiple sessions, as long as
-     * that client does not "fail" any test.
+     * that client does not "fail" any test. Don't try to optimize away cache
+     * updates; we want cached information to be up-to-date even if a test
+     * result is renewed during overlapping SMTP sessions, and even if
+     * 'postfix reload' happens in the middle of that.
      */
     if ((state->flags & PSC_STATE_MASK_ANY_UPDATE) != 0
        && psc_cache_map != 0) {
index c7472cc627d9bffb0139456df943fcf76f53c2ef..2e768dfa4213875ba0e99bd7e935e3f8389cb12e 100644 (file)
@@ -61,7 +61,8 @@
 /*     psc_new_session_state() creates a new session state object
 /*     for the specified client stream, and increments the
 /*     psc_check_queue_length counter.  The flags and per-test time
-/*     stamps are initialized with PSC_INIT_TESTS().  The addr and
+/*     stamps are initialized with PSC_INIT_TESTS(), or for concurrent
+/*     sessions, with PSC_INIT_TEST_FLAGS_ONLY().  The addr and
 /*     port arguments are null-terminated strings with the remote
 /*     SMTP client endpoint. The _reply members are set to
 /*     polite "try again" SMTP replies. The protocol member is set
@@ -149,10 +150,8 @@ PSC_STATE *psc_new_session_state(VSTREAM *stream,
                                         const char *server_port)
 {
     PSC_STATE *state;
-    HTABLE_INFO *ht;
 
     state = (PSC_STATE *) mymalloc(sizeof(*state));
-    PSC_INIT_TESTS(state);
     if ((state->smtp_client_stream = stream) != 0)
        psc_check_queue_length++;
     state->smtp_server_fd = (-1);
@@ -188,10 +187,19 @@ PSC_STATE *psc_new_session_state(VSTREAM *stream,
     /*
      * Update the per-client session count.
      */
-    if ((ht = htable_locate(psc_client_concurrency, client_addr)) == 0)
-       ht = htable_enter(psc_client_concurrency, client_addr, (char *) 0);
-    ht->value += 1;
-    state->client_concurrency = CAST_CHAR_PTR_TO_INT(ht->value);
+    if ((state->client_info = (PSC_CLIENT_INFO *)
+        htable_find(psc_client_concurrency, client_addr)) == 0) {
+       state->client_info = (PSC_CLIENT_INFO *)
+           mymalloc(sizeof(state->client_info[0]));
+       (void) htable_enter(psc_client_concurrency, client_addr,
+                           (void *) state->client_info);
+       PSC_INIT_TESTS(state);
+       state->client_info->concurrency = 1;
+       state->client_info->pass_new_count = 0;
+    } else {
+       PSC_INIT_TEST_FLAGS_ONLY(state);
+       state->client_info->concurrency += 1;
+    }
 
     return (state);
 }
@@ -210,9 +218,8 @@ void    psc_free_session_state(PSC_STATE *state)
                            state->smtp_client_addr)) == 0)
        msg_panic("%s: unknown client address: %s",
                  myname, state->smtp_client_addr);
-    if (--(ht->value) == 0)
-       htable_delete(psc_client_concurrency, state->smtp_client_addr,
-                     (void (*) (char *)) 0);
+    if (--(state->client_info->concurrency) == 0)
+       htable_delete(psc_client_concurrency, state->smtp_client_addr, myfree);
 
     if (state->smtp_client_stream != 0) {
        event_server_disconnect(state->smtp_client_stream);
index 17b7a3926149a951c637d6a160d72a03c0c6a10c..f8b92a9888ece7200c9733b3147edf4d158074af 100644 (file)
 /*     const char *stamp_text;
 /*     time_t time_value;
 /*
+/*     void    psc_todo_tests(state, time_value)
+/*     PSC_STATE *state;
+/*     const char *stamp_text;
+/*     time_t time_value;
+/*
 /*     char    *psc_print_tests(buffer, state)
 /*     VSTRING *buffer;
 /*     PSC_STATE *state;
 /*     zeroes all the flags bits. These values are not meant to
 /*     be stored into the postscreen(8) cache.
 /*
+/*     PSC_INIT_TEST_FLAGS_ONLY() zeroes all the flag bits.  It
+/*     should be used when the time stamps are already initialized.
+/*
 /*     psc_new_tests() sets all test expiration time stamps to
-/*     PSC_TIME_STAMP_NEW, and overwrites all flags bits. Only
-/*     enabled tests are flagged with PSC_STATE_FLAG_TODO; the
-/*     object is flagged with PSC_STATE_FLAG_NEW.
+/*     PSC_TIME_STAMP_NEW, and invokes psc_todo_tests().
+/*
+/*     psc_parse_tests() parses a cache file record and invokes
+/*     psc_todo_tests().
 /*
-/*     psc_parse_tests() parses a cache file record and overwrites
-/*     all flags bits. Tests are considered "expired" when they
+/*     psc_todo_tests() overwrites all per-session flag bits, and
+/*     populates the flags based on test expiration time stamp
+/*     information.  Tests are considered "expired" when they
 /*     would be expired at the specified time value. Only enabled
 /*     tests are flagged as "expired"; the object is flagged as
 /*     "new" if some enabled tests have "new" time stamps.
 void    psc_new_tests(PSC_STATE *state)
 {
 
-    /*
-     * We know this client is brand new.
-     */
-    state->flags = PSC_STATE_FLAG_NEW;
-
     /*
      * Give all tests a PSC_TIME_STAMP_NEW time stamp, so that we can later
      * recognize cache entries that haven't passed all enabled tests. When we
@@ -142,19 +147,9 @@ void    psc_new_tests(PSC_STATE *state)
     state->barlf_stamp = PSC_TIME_STAMP_NEW;
 
     /*
-     * Don't flag disabled tests as "todo", because there would be no way to
-     * make those bits go away.
+     * Determine what tests need to be completed.
      */
-    if (PSC_PREGR_TEST_ENABLE())
-       state->flags |= PSC_STATE_FLAG_PREGR_TODO;
-    if (PSC_DNSBL_TEST_ENABLE())
-       state->flags |= PSC_STATE_FLAG_DNSBL_TODO;
-    if (var_psc_pipel_enable)
-       state->flags |= PSC_STATE_FLAG_PIPEL_TODO;
-    if (var_psc_nsmtp_enable)
-       state->flags |= PSC_STATE_FLAG_NSMTP_TODO;
-    if (var_psc_barlf_enable)
-       state->flags |= PSC_STATE_FLAG_BARLF_TODO;
+    psc_todo_tests(state, PSC_TIME_STAMP_NEW + 1);
 }
 
 /* psc_parse_tests - parse test results from cache */
@@ -165,29 +160,18 @@ void    psc_parse_tests(PSC_STATE *state,
 {
     const char *start = stamp_str;
     char   *cp;
-    time_t *time_stamps = state->expire_time;
+    time_t *time_stamps = state->client_info->expire_time;
     time_t *sp;
 
-    /*
-     * We don't know what tests have expired or have never passed.
-     */
-    state->flags = 0;
-
     /*
      * Parse the cache entry, and allow for older postscreen versions that
      * implemented fewer tests. We pretend that the newer tests were disabled
      * at the time that the cache entry was written.
-     * 
-     * Flag the cache entry as "new" when the cache entry has fields for all
-     * enabled tests, but the remote SMTP client has not yet passed all those
-     * tests.
      */
     for (sp = time_stamps; sp < time_stamps + PSC_TINDX_COUNT; sp++) {
        *sp = strtoul(start, &cp, 10);
        if (*start == 0 || (*cp != '\0' && *cp != ';') || errno == ERANGE)
            *sp = PSC_TIME_STAMP_DISABLED;
-       if (*sp == PSC_TIME_STAMP_NEW)
-           state->flags |= PSC_STATE_FLAG_NEW;
        if (msg_verbose)
            msg_info("%s -> %lu", start, (unsigned long) *sp);
        if (*cp == ';')
@@ -196,6 +180,34 @@ void    psc_parse_tests(PSC_STATE *state,
            start = cp;
     }
 
+    /*
+     * Determine what tests need to be completed.
+     */
+    psc_todo_tests(state, time_value);
+}
+
+/* psc_todo_tests - determine what tests to perform */
+
+void    psc_todo_tests(PSC_STATE *state, time_t time_value)
+{
+    time_t *time_stamps = state->client_info->expire_time;
+    time_t *sp;
+
+    /*
+     * Reset all per-session flags.
+     */
+    state->flags = 0;
+
+    /*
+     * Flag the tests as "new" when the cache entry has fields for all
+     * enabled tests, but the remote SMTP client has not yet passed all those
+     * tests.
+     */
+    for (sp = time_stamps; sp < time_stamps + PSC_TINDX_COUNT; sp++) {
+       if (*sp == PSC_TIME_STAMP_NEW)
+           state->flags |= PSC_STATE_FLAG_NEW;
+    }
+
     /*
      * Don't flag disabled tests as "todo", because there would be no way to
      * make those bits go away.
index 9dabb5dc4c92b36308bbd76a24bd7e73a7730da0..468d3993664508b0830dd813a945873392226450 100644 (file)
@@ -430,7 +430,7 @@ static int postrename(const char *old, const char *new)
     if ((ret = sane_rename(old, new)) < 0) {
        if (errno != ENOENT
            || mail_queue_mkdirs(new) < 0
-           || sane_rename(old, new) < 0)
+           || (ret = sane_rename(old, new)) < 0)
            if (errno != ENOENT)
                msg_fatal("rename file %s as %s: %m", old, new);
     } else {
index 0bade14826725e2a2bb849ea427e2a7210f824df..55a39b73f28df337a6ccd800fd3b7139506e46f2 100644 (file)
@@ -1172,6 +1172,7 @@ char   *var_rest_classes;
 int     var_strict_rfc821_env;
 bool    var_disable_vrfy_cmd;
 char   *var_canonical_maps;
+char   *var_send_canon_maps;
 char   *var_rcpt_canon_maps;
 char   *var_virt_alias_maps;
 char   *var_virt_mailbox_maps;
@@ -5382,6 +5383,7 @@ int     main(int argc, char **argv)
        VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
        VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes, 0, 0,
        VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps, 0, 0,
+       VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps, 0, 0,
        VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps, 0, 0,
        VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps, 0, 0,
        VAR_VIRT_MAILBOX_MAPS, DEF_VIRT_MAILBOX_MAPS, &var_virt_mailbox_maps, 0, 0,
index 2ee533387be9b9aeff59ae0c8f6844bc00630a70..1b08f08116ca8e97744680da48a537a04854c012 100644 (file)
@@ -274,6 +274,7 @@ static CTABLE *smtpd_rbl_byte_cache;
   * trivial-rewrite resolver.
   */
 static MAPS *local_rcpt_maps;
+static MAPS *send_canon_maps;
 static MAPS *rcpt_canon_maps;
 static MAPS *canonical_maps;
 static MAPS *virt_alias_maps;
@@ -610,6 +611,8 @@ void    smtpd_check_init(void)
      */
     local_rcpt_maps = maps_create(VAR_LOCAL_RCPT_MAPS, var_local_rcpt_maps,
                                  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
+    send_canon_maps = maps_create(VAR_SEND_CANON_MAPS, var_send_canon_maps,
+                                 DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
     rcpt_canon_maps = maps_create(VAR_RCPT_CANON_MAPS, var_rcpt_canon_maps,
                                  DICT_FLAG_LOCK | DICT_FLAG_FOLD_FIX);
     canonical_maps = maps_create(VAR_CANONICAL_MAPS, var_canonical_maps,
@@ -4716,7 +4719,7 @@ static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient,
     DSN_SPLIT dp;
 
     if (msg_verbose)
-       msg_info(">>> CHECKING RECIPIENT MAPS <<<");
+       msg_info(">>> CHECKING %s VALIDATION MAPS <<<", reply_class);
 
     /*
      * Resolve the address.
@@ -4742,6 +4745,8 @@ static int check_rcpt_maps(SMTPD_STATE *state, const char *recipient,
      * domains.
      */
     if (MATCH(rcpt_canon_maps, CONST_STR(reply->recipient))
+       || (strcmp(reply_class, SMTPD_NAME_SENDER) == 0
+           && MATCH(send_canon_maps, CONST_STR(reply->recipient)))
        || MATCH(canonical_maps, CONST_STR(reply->recipient))
        || MATCH(virt_alias_maps, CONST_STR(reply->recipient)))
        return (0);
@@ -5071,6 +5076,7 @@ char   *var_proxy_interfaces;
 char   *var_rcpt_delim;
 char   *var_rest_classes;
 char   *var_alias_maps;
+char   *var_send_canon_maps;
 char   *var_rcpt_canon_maps;
 char   *var_canonical_maps;
 char   *var_virt_alias_maps;
@@ -5121,6 +5127,7 @@ static const STRING_TABLE string_table[] = {
     VAR_RCPT_DELIM, DEF_RCPT_DELIM, &var_rcpt_delim,
     VAR_REST_CLASSES, DEF_REST_CLASSES, &var_rest_classes,
     VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps,
+    VAR_SEND_CANON_MAPS, DEF_SEND_CANON_MAPS, &var_send_canon_maps,
     VAR_RCPT_CANON_MAPS, DEF_RCPT_CANON_MAPS, &var_rcpt_canon_maps,
     VAR_CANONICAL_MAPS, DEF_CANONICAL_MAPS, &var_canonical_maps,
     VAR_VIRT_ALIAS_MAPS, DEF_VIRT_ALIAS_MAPS, &var_virt_alias_maps,
@@ -5643,6 +5650,22 @@ int     main(int argc, char **argv)
                resp = 0;
                break;
            }
+           if (strcasecmp(args->argv[0], VAR_SEND_CANON_MAPS) == 0) {
+               UPDATE_STRING(var_send_canon_maps, args->argv[1]);
+               UPDATE_MAPS(send_canon_maps, VAR_SEND_CANON_MAPS,
+                           var_send_canon_maps, DICT_FLAG_LOCK
+                           | DICT_FLAG_FOLD_FIX);
+               resp = 0;
+               break;
+           }
+           if (strcasecmp(args->argv[0], VAR_RCPT_CANON_MAPS) == 0) {
+               UPDATE_STRING(var_rcpt_canon_maps, args->argv[1]);
+               UPDATE_MAPS(rcpt_canon_maps, VAR_RCPT_CANON_MAPS,
+                           var_rcpt_canon_maps, DICT_FLAG_LOCK
+                           | DICT_FLAG_FOLD_FIX);
+               resp = 0;
+               break;
+           }
            if (strcasecmp(args->argv[0], VAR_RBL_REPLY_MAPS) == 0) {
                UPDATE_STRING(var_rbl_reply_maps, args->argv[1]);
                UPDATE_MAPS(rbl_reply_maps, VAR_RBL_REPLY_MAPS,
index e04c42682c1208de33662a48c11dc98b8f04fa0f..51e646de7af1e487d0902745030a39714249e540 100644 (file)
@@ -80,7 +80,6 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
     int     mail_copy_status;
     int     deliver_status;
     int     copy_flags;
-    long    end;
     struct stat st;
 
     /*
@@ -132,7 +131,9 @@ static int deliver_mailbox_file(LOCAL_STATE state, USER_ATTR usr_attr)
            msg_warn("specify \"%s = no\" to ignore mailbox ownership mismatch",
                     VAR_STRICT_MBOX_OWNER);
        } else {
-           end = vstream_fseek(mp->fp, (off_t) 0, SEEK_END);
+           if (vstream_fseek(mp->fp, (off_t) 0, SEEK_END) < 0)
+               msg_fatal("%s: seek queue file %s: %m",
+                         myname, VSTREAM_PATH(mp->fp));
            mail_copy_status = mail_copy(COPY_ATTR(state.msg_attr), mp->fp,
                                         copy_flags, "\n", why);
        }