]> git.ipfire.org Git - thirdparty/postfix.git/commitdiff
postfix-2.3-20060403
authorWietse Venema <wietse@porcupine.org>
Mon, 3 Apr 2006 05:00:00 +0000 (00:00 -0500)
committerViktor Dukhovni <viktor@dukhovni.org>
Tue, 5 Feb 2013 06:32:15 +0000 (06:32 +0000)
18 files changed:
postfix/HISTORY
postfix/README_FILES/SASL_README
postfix/html/SASL_README.html
postfix/html/pipe.8.html
postfix/html/postconf.5.html
postfix/man/man5/postconf.5
postfix/man/man8/pipe.8
postfix/mantools/postlink
postfix/proto/SASL_README.html
postfix/proto/postconf.proto
postfix/src/global/Makefile.in
postfix/src/global/db_common.c
postfix/src/global/mail_params.h
postfix/src/global/mail_version.h
postfix/src/global/pipe_command.c
postfix/src/global/pipe_command.h
postfix/src/pipe/pipe.c
postfix/src/util/myflock.c

index 76965c7d1ffdba63c60343373f74378142105f2d..5f96028e918b62f9275379346da89cbe9dd65b8c 100644 (file)
@@ -12064,6 +12064,34 @@ Apologies for any names omitted.
        test. A filter timeout was mis-reported as lost connection.
        Found in code review.  File: smtpd/smtpd_proxy.c.
 
+20060327
+
+       Cleanup: the SQL and LDAP clients now log a warning when
+       they skip an empty lookup result, so that humans don't have
+       to wonder why Postfix doesn't find all the database entries.
+       File: global/db_common.c.
+
+20060328
+
+       Feature: configurable chroot directive for the pipe(8)
+       delivery agent, by Przemyslaw Wegrzyn. Files:
+       global/pipe_command.c, pipe/pipe.c.
+
+       Bugfix: cut-and-paste error: lmtp_connection_cache_limit
+       was left with the name of smtp_connection_cache_limit.
+       Reported by Victor? File: src/global/mail_params.h.
+
+20060403
+
+       Cleanup: made fcntl/flock handling consistent with respect
+       to EINTR (reported by Carlo Contavalli). However, Postfix
+       is not meant to be signal safe.  Only the master daemon
+       handles signals without terminating, and it uses only a
+       small subset of Postfix library routines. File: util/myflock.c.
+
+       Bugfix: the pipe-to-command error message was lost when the
+       command could not be executed. File: global/pipe_command.c.
+
 Wish list:
 
        Don't send xforward attributes to every site that announces
index 21f0f0de6c5ed387a20e3467d342812c8ebd9231..e3c8d7cbbc5349c1b2d341ac845011ff11857fc2 100644 (file)
@@ -181,11 +181,17 @@ that the Postfix queue is under /var/spool/postfix/.
 
     /some/where/dovecot.conf:
         auth default {
-          ..
+          mechanisms = plain login
+          passdb pam {
+          }
+          userdb passwd {
+          }
           socket listen {
             client {
               path = /var/spool/postfix/private/auth
-              mode = 0666
+              mode = 0660
+              user = postfix
+              group = postfix
             }
           }
         }
@@ -447,7 +453,7 @@ C\bCr\bre\bed\bdi\bit\bts\bs
     reject_authenticated_sender_login_mismatch and
     reject_unauthenticated_sender_login_mismatch, and revised the docs.
   * Wietse made another iteration through the code to add plug-in support for
-    multiple implementations.
-  * The Dovecot SMTP server plug-in was originally implemented by Timo Sirainen
-    of Procontrol, Finland.
+    multiple SASL implementations.
+  * The Dovecot SMTP server-only plug-in was originally implemented by Timo
+    Sirainen of Procontrol, Finland.
 
index fb2cf5325134f0ff60d3f41b9a5121b4efbad3cf..3c1825b2dcc905fb5e24c159481a9054c64e9b68 100644 (file)
@@ -140,7 +140,7 @@ in the Postfix top-level directory: </p>
 
 <li> <p> The "-DDEF_SASL_SERVER" stuff is not necessary; it just
 makes Postfix configuration a little more convenient because you
-don't have to specify the SASL plug-in type in the Postfix main.cf
+don't have to specify the SASL plug-in type in the Postfix <a href="postconf.5.html">main.cf</a>
 file.  </p>
 
 <li> <p> If you also want support for LDAP or TLS, you will have to merge
@@ -229,7 +229,7 @@ SMTP server</a></h2>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtpd_sasl_auth_enable">smtpd_sasl_auth_enable</a> = yes
 </pre>
 </blockquote>
@@ -238,7 +238,7 @@ SMTP server</a></h2>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtpd_recipient_restrictions">smtpd_recipient_restrictions</a> = 
         <a href="postconf.5.html#permit_mynetworks">permit_mynetworks</a> <a href="postconf.5.html#permit_sasl_authenticated">permit_sasl_authenticated</a> ...
 </pre>
@@ -249,7 +249,7 @@ SMTP server</a></h2>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtpd_sasl_authenticated_header">smtpd_sasl_authenticated_header</a> = yes
 </pre>
 </blockquote>
@@ -265,7 +265,7 @@ clients) use the following: </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#broken_sasl_auth_clients">broken_sasl_auth_clients</a> = yes
 </pre>
 </blockquote>
@@ -281,7 +281,7 @@ Postfix runs chrooted: </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a> = dovecot
     <a href="postconf.5.html#smtpd_sasl_path">smtpd_sasl_path</a> = private/auth
 </pre>
@@ -296,11 +296,17 @@ Postfix queue is under /var/spool/postfix/. </p>
 <pre>
 /some/where/dovecot.conf:
     auth default {
-      ..
+      mechanisms = plain login
+      passdb pam {
+      }
+      userdb passwd {
+      }
       socket listen {
         client {
           path = /var/spool/postfix/private/auth
-          mode = 0666
+          mode = 0660
+          user = postfix
+          group = postfix
         }
       }
     }
@@ -352,7 +358,7 @@ library for configuration can be set with: </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     smtpd_sasl_application_name = smtpd
 </pre>
 </blockquote>
@@ -449,7 +455,7 @@ realm used by smtpd: </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtpd_sasl_local_domain">smtpd_sasl_local_domain</a> = $<a href="postconf.5.html#myhostname">myhostname</a>
 </pre>
 </blockquote>
@@ -593,7 +599,7 @@ table. </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_sasl_auth_enable">smtp_sasl_auth_enable</a> = yes
     <a href="postconf.5.html#smtp_sasl_password_maps">smtp_sasl_password_maps</a> = hash:/etc/postfix/sasl_passwd
     <a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a> = cyrus
@@ -612,7 +618,7 @@ before it searches by destination, specify: </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_sender_dependent_authentication">smtp_sender_dependent_authentication</a> = yes
     <a href="postconf.5.html#smtp_sasl_auth_enable">smtp_sasl_auth_enable</a> = yes
     <a href="postconf.5.html#smtp_sasl_password_maps">smtp_sasl_password_maps</a> = hash:/etc/postfix/sasl_passwd
@@ -634,7 +640,7 @@ for example: </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_sasl_security_options">smtp_sasl_security_options</a> = noanonymous
 </pre>
 </blockquote>
@@ -652,7 +658,7 @@ into consideration:  </p>
 
 <blockquote>
 <pre>
-/etc/postfix/main.cf:
+/etc/postfix/<a href="postconf.5.html">main.cf</a>:
     <a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a> = !gssapi, !external, static:all
 </pre>
 </blockquote>
@@ -682,9 +688,9 @@ of SuSE Rhein/Main AG.
 <a href="postconf.5.html#reject_unauthenticated_sender_login_mismatch">reject_unauthenticated_sender_login_mismatch</a>, and revised the docs.
 
 <li> Wietse made another iteration through the code to add
-plug-in support for multiple implementations.
+plug-in support for multiple SASL implementations.
 
-<li> The Dovecot SMTP server plug-in was originally implemented by
+<li> The Dovecot SMTP server-only plug-in was originally implemented by
 Timo Sirainen of Procontrol, Finland.
 
 </ul>
index 8eda4d5f3c321ed680fc97e5343e46f12bbd06c8..893e7652558c6eb5209d186c8ce847c005e8c6bd 100644 (file)
@@ -48,9 +48,22 @@ PIPE(8)                                                                PIPE(8)
        file at the end of a service definition.  The syntax is as
        follows:
 
-       <b>directory=</b><i>pathname</i> (optional, default: <b>$<a href="postconf.5.html#queue_directory">queue_directory</a></b>)
-              Change to the named directory before executing  the
-              external  command.  Delivery is deferred in case of
+       <b>chroot=</b><i>pathname</i> (optional)
+              Change  the  process  root  directory  and  working
+              directory  to  the  named  directory.  This happens
+              before switching to the privileges  specified  with
+              the   <b>user</b>  attribute,  and  before  executing  the
+              optional <b>directory=</b><i>pathname</i> directive. Delivery  is
+              deferred in case of failure.
+
+              This feature is available as of Postfix 2.3.
+
+       <b>directory=</b><i>pathname</i> (optional)
+              Change  to the named directory before executing the
+              external command.  The directory must be accessible
+              for the user specified with the <b>user</b> attribute (see
+              below).    The   default   working   directory   is
+              <b>$<a href="postconf.5.html#queue_directory">queue_directory</a></b>.   Delivery is deferred in case of
               failure.
 
               This feature is available as of Postfix 2.2.
@@ -162,9 +175,9 @@ PIPE(8)                                                                PIPE(8)
        <b>user</b>=<i>username</i> (required)
 
        <b>user</b>=<i>username</i>:<i>groupname</i>
-              The external command is executed with the rights of
-              the  specified  <i>username</i>.   The software refuses to
-              execute commands with root privileges, or with  the
+              Execute the external command with the rights of the
+              specified  <i>username</i>.   The software refuses to exe-
+              cute commands with root  privileges,  or  with  the
               privileges  of  the mail system owner. If <i>groupname</i>
               is specified, the corresponding group  ID  is  used
               instead of the group ID of <i>username</i>.
index 59557d39f6ec8419ea87d3d60aae262d43c2f8c5..43f902d8269b0cfba53ada7d13a5071eb0912653 100644 (file)
@@ -3154,6 +3154,18 @@ configuration parameter.  See there for details. </p>
 <p> This feature is available in Postfix 2.3 and later. </p>
 
 
+</DD>
+
+<DT><b><a name="lmtp_connection_cache_time_limit">lmtp_connection_cache_time_limit</a>
+(default: 2s)</b></DT><DD>
+
+<p> The LMTP-specific version of the
+<a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> configuration parameter.
+See there for details. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
 </DD>
 
 <DT><b><a name="lmtp_connection_reuse_time_limit">lmtp_connection_reuse_time_limit</a>
index cfec35d0c798df94e3c37d912d83ad917c501eb5..16f0323fd290ffcf61898c9b60cce489cac71060 100644 (file)
@@ -1705,6 +1705,12 @@ The LMTP-specific version of the smtp_connection_cache_on_demand
 configuration parameter.  See there for details.
 .PP
 This feature is available in Postfix 2.3 and later.
+.SH lmtp_connection_cache_time_limit (default: 2s)
+The LMTP-specific version of the
+smtp_connection_cache_time_limit configuration parameter.
+See there for details.
+.PP
+This feature is available in Postfix 2.3 and later.
 .SH lmtp_connection_reuse_time_limit (default: 300s)
 The LMTP-specific version of the smtp_connection_reuse_time_limit
 configuration parameter.  See there for details.
index c3f653824e63ed213f7b5435779faf9422f770ab..40ccc713d4f46d23b75a8c411b1a9647f74b878e 100644 (file)
@@ -51,8 +51,19 @@ entry for the pipe-based delivery transport.
 .fi
 The external command attributes are given in the \fBmaster.cf\fR
 file at the end of a service definition.  The syntax is as follows:
-.IP "\fBdirectory=\fIpathname\fR (optional, default: \fB$queue_directory\fR)"
+.IP "\fBchroot=\fIpathname\fR (optional)"
+Change the process root directory and working directory to
+the named directory. This happens before switching to the
+privileges specified with the \fBuser\fR attribute, and
+before executing the optional \fBdirectory=\fIpathname\fR
+directive. Delivery is deferred in case of failure.
+.sp
+This feature is available as of Postfix 2.3.
+.IP "\fBdirectory=\fIpathname\fR (optional)"
 Change to the named directory before executing the external command.
+The directory must be accessible for the user specified with the
+\fBuser\fR attribute (see below).
+The default working directory is \fB$queue_directory\fR.
 Delivery is deferred in case of failure.
 .sp
 This feature is available as of Postfix 2.2.
@@ -148,7 +159,7 @@ Messages greater in size than this limit (in bytes) will
 be returned to the sender as undeliverable.
 .IP "\fBuser\fR=\fIusername\fR (required)"
 .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
-The external command is executed with the rights of the
+Execute the external command with the rights of the
 specified \fIusername\fR.  The software refuses to execute
 commands with root privileges, or with the privileges of the
 mail system owner. If \fIgroupname\fR is specified, the
index cb8c84173e159e62226a2e69b89d1d34a0674465..b2c9e70bad520c54261f412f28ae0109a56dc21e 100755 (executable)
@@ -201,6 +201,7 @@ while (<>) {
     s;\blmtp_sasl_mechanism_filter\b;<a href="postconf.5.html#lmtp_sasl_mechanism_filter">$&</a>;g;
     s;\blmtp_host_lookup\b;<a href="postconf.5.html#lmtp_host_lookup">$&</a>;g;
     s;\blmtp_connection_cache_destinations\b;<a href="postconf.5.html#lmtp_connection_cache_destinations">$&</a>;g;
+    s;\blmtp_connection_cache_time_limit\b;<a href="postconf.5.html#lmtp_connection_cache_time_limit">$&</a>;g;
     s;\blmtp_tls_per_site\b;<a href="postconf.5.html#lmtp_tls_per_site">$&</a>;g;
     s;\blmtp_generic_maps\b;<a href="postconf.5.html#lmtp_generic_maps">$&</a>;g;
     s;\blmtp_pix_workaround_threshold_time\b;<a href="postconf.5.html#lmtp_pix_workaround_threshold_time">$&</a>;g;
index 591b61b0b8616554013823f070dccdfa6f79cb86..29ae2843cd3fd7d7271d389f84a2c3c0ca9f4705 100644 (file)
@@ -296,11 +296,17 @@ Postfix queue is under /var/spool/postfix/. </p>
 <pre>
 /some/where/dovecot.conf:
     auth default {
-      ..
+      mechanisms = plain login
+      passdb pam {
+      }
+      userdb passwd {
+      }
       socket listen {
         client {
           path = /var/spool/postfix/private/auth
-          mode = 0666
+          mode = 0660
+          user = postfix
+          group = postfix
         }
       }
     }
@@ -682,9 +688,9 @@ reject_authenticated_sender_login_mismatch and
 reject_unauthenticated_sender_login_mismatch, and revised the docs.
 
 <li> Wietse made another iteration through the code to add
-plug-in support for multiple implementations.
+plug-in support for multiple SASL implementations.
 
-<li> The Dovecot SMTP server plug-in was originally implemented by
+<li> The Dovecot SMTP server-only plug-in was originally implemented by
 Timo Sirainen of Procontrol, Finland.
 
 </ul>
index fcf27e1c8209daff3dab2bc6dabc62885a3f24e4..4f5a2433e41181b630429d33a43d56786af490b9 100644 (file)
@@ -9243,6 +9243,14 @@ See there for details. </p>
 
 <p> This feature is available in Postfix 2.3 and later. </p>
 
+%PARAM lmtp_connection_cache_time_limit 2s
+
+<p> The LMTP-specific version of the
+smtp_connection_cache_time_limit configuration parameter.
+See there for details. </p>
+<p> This feature is available in Postfix 2.3 and later. </p>
+
 %PARAM smtpd_delay_open_until_valid_rcpt yes
 
 <p> Postpone the start of an SMTP mail transaction until a valid
index 30141265452356c80045955a7d2389f520a6c3f7..9b93f878ef74c7161c88ba1ab1f53273bec0aafd 100644 (file)
@@ -1415,10 +1415,12 @@ own_inet_addr.o: mail_params.h
 own_inet_addr.o: own_inet_addr.c
 own_inet_addr.o: own_inet_addr.h
 pipe_command.o: ../../include/argv.h
+pipe_command.o: ../../include/chroot_uid.h
 pipe_command.o: ../../include/clean_env.h
 pipe_command.o: ../../include/exec_command.h
 pipe_command.o: ../../include/iostuff.h
 pipe_command.o: ../../include/msg.h
+pipe_command.o: ../../include/msg_vstream.h
 pipe_command.o: ../../include/set_eugid.h
 pipe_command.o: ../../include/set_ugid.h
 pipe_command.o: ../../include/stringops.h
index 183f0db0fe77c0c77ac968357d2356f935d51d08..811dd847cd4e37d807c6d85985ecbe26dc881397 100644 (file)
@@ -278,7 +278,7 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
                     db_quote_callback_t quote_func)
 {
     char   *myname = "db_common_expand";
-    DB_COMMON_CTX *ctx = (DB_COMMON_CTX *)ctxArg;
+    DB_COMMON_CTX *ctx = (DB_COMMON_CTX *) ctxArg;
     const char *vdomain = 0;
     const char *kdomain = 0;
     char   *vuser = 0;
@@ -287,18 +287,28 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
     int     i;
     const char *cp;
 
-    /* Skip NULL or empty values */
-    if (value == 0 || *value == 0)
-       return (0);
-
+    /* Skip NULL values, silently. */
+    if (value == 0)
+       return (0);
+
+    /* Don't silenty skip empty query string or empty lookup results. */
+    if (*value == 0) {
+       if (key)
+           msg_warn("table \"%s:%s\": empty lookup result for: \"%s\""
+                    " -- ignored", ctx->dict->type, ctx->dict->name, key);
+       else
+           msg_warn("table \"%s:%s\": empty query string"
+                    " -- ignored", ctx->dict->type, ctx->dict->name);
+       return (0);
+    }
     if (key) {
-       /* This is a result template and the input value is the result */
+       /* This is a result template and the input value is the result */
        if (ctx->flags & (DB_COMMON_VALUE_DOMAIN | DB_COMMON_VALUE_USER))
            if ((vdomain = strrchr(value, '@')) != 0)
                ++vdomain;
 
-       if ((!vdomain || !*vdomain) && (ctx->flags&DB_COMMON_VALUE_DOMAIN) != 0
-           || vdomain == value + 1 && (ctx->flags&DB_COMMON_VALUE_USER) != 0)
+       if ((!vdomain || !*vdomain) && (ctx->flags & DB_COMMON_VALUE_DOMAIN) != 0
+       || vdomain == value + 1 && (ctx->flags & DB_COMMON_VALUE_USER) != 0)
            return (0);
 
        /* The result format may use the local or domain part of the key */
@@ -307,50 +317,51 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
                ++kdomain;
 
        /*
-        * The key should already be checked before the query. No harm if
-        * the query did not get optimized out, so we just issue a warning.
+        * The key should already be checked before the query. No harm if the
+        * query did not get optimized out, so we just issue a warning.
         */
-       if ((!kdomain || !*kdomain) && (ctx->flags&DB_COMMON_KEY_DOMAIN) != 0
-           || kdomain == key + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0) {
+       if ((!kdomain || !*kdomain) && (ctx->flags & DB_COMMON_KEY_DOMAIN) != 0
+         || kdomain == key + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0) {
            msg_warn("%s: %s: lookup key '%s' skipped after query", myname,
-                     ctx->dict->name, value);
+                    ctx->dict->name, value);
            return (0);
        }
     } else {
-       /* This is a query template and the input value is the lookup key */
+       /* This is a query template and the input value is the lookup key */
        if (ctx->flags & (DB_COMMON_KEY_DOMAIN | DB_COMMON_KEY_USER))
            if ((vdomain = strrchr(value, '@')) != 0)
                ++vdomain;
 
-       if ((!vdomain || !*vdomain) && (ctx->flags&DB_COMMON_KEY_DOMAIN) != 0
-           || vdomain == value + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0)
+       if ((!vdomain || !*vdomain) && (ctx->flags & DB_COMMON_KEY_DOMAIN) != 0
+         || vdomain == value + 1 && (ctx->flags & DB_COMMON_KEY_USER) != 0)
            return (0);
     }
 
     if (ctx->nparts > 0) {
-       parts = argv_split(key ? kdomain : vdomain, ".");
+       parts = argv_split(key ? kdomain : vdomain, ".");
+
        /*
-        * Filter out input keys whose domains lack enough labels
-        * to fill-in the query template. See below and also 
-        * db_common_parse() which initializes ctx->nparts.
+        * Filter out input keys whose domains lack enough labels to fill-in
+        * the query template. See below and also db_common_parse() which
+        * initializes ctx->nparts.
         */
        if (parts->argc < ctx->nparts) {
            argv_free(parts);
            return (0);
        }
+
        /*
-        * Skip domains with leading, consecutive or trailing '.'
-        * separators among the required labels.
+        * Skip domains with leading, consecutive or trailing '.' separators
+        * among the required labels.
         */
        for (i = 0; i < ctx->nparts; i++)
-           if (*parts->argv[parts->argc-i-1] == 0) {
+           if (*parts->argv[parts->argc - i - 1] == 0) {
                argv_free(parts);
                return (0);
            }
     }
-
     if (VSTRING_LEN(result) > 0)
-       VSTRING_ADDCH(result, ',');
+       VSTRING_ADDCH(result, ',');
 
 #define QUOTE_VAL(d, q, v, buf) do { \
        if (q) \
@@ -360,9 +371,9 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
     } while (0)
 
     /*
-     * Replace all instances of %s with the address to look up. Replace
-     * %u with the user portion, and %d with the domain portion. "%%"
-     * expands to "%".  lowercase -> addr, uppercase -> key
+     * Replace all instances of %s with the address to look up. Replace %u
+     * with the user portion, and %d with the domain portion. "%%" expands to
+     * "%".  lowercase -> addr, uppercase -> key
      */
     for (cp = format; *cp; cp++) {
        if (*cp == '%') {
@@ -381,8 +392,7 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
                    if (vuser == 0)
                        vuser = mystrndup(value, vdomain - value - 1);
                    QUOTE_VAL(ctx->dict, quote_func, vuser, result);
-               }
-               else
+               } else
                    QUOTE_VAL(ctx->dict, quote_func, value, result);
                break;
 
@@ -391,7 +401,7 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
                break;
 
            case 'S':
-               if (key)
+               if (key)
                    QUOTE_VAL(ctx->dict, quote_func, key, result);
                else
                    QUOTE_VAL(ctx->dict, quote_func, value, result);
@@ -403,16 +413,14 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
                        if (kuser == 0)
                            kuser = mystrndup(key, kdomain - key - 1);
                        QUOTE_VAL(ctx->dict, quote_func, kuser, result);
-                   }
-                   else
+                   } else
                        QUOTE_VAL(ctx->dict, quote_func, key, result);
                } else {
                    if (vdomain) {
                        if (vuser == 0)
                            vuser = mystrndup(value, vdomain - value - 1);
                        QUOTE_VAL(ctx->dict, quote_func, vuser, result);
-                   }
-                   else
+                   } else
                        QUOTE_VAL(ctx->dict, quote_func, value, result);
                }
                break;
@@ -424,18 +432,26 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
                    QUOTE_VAL(ctx->dict, quote_func, vdomain, result);
                break;
 
-           case '1': case '2': case '3': case '4': case '5':
-           case '6': case '7': case '8': case '9':
-               /*
-                * Interpolate %[1-9] components into the query string.
-                * By this point db_common_parse() has identified the
-                * highest component index, and (see above) keys with
-                * fewer components have been filtered out. The "parts"
-                * ARGV is guaranteed to be initialized and hold enough
-                * elements to satisfy the query template.
+           case '1':
+           case '2':
+           case '3':
+           case '4':
+           case '5':
+           case '6':
+           case '7':
+           case '8':
+           case '9':
+
+               /*
+                * Interpolate %[1-9] components into the query string. By
+                * this point db_common_parse() has identified the highest
+                * component index, and (see above) keys with fewer
+                * components have been filtered out. The "parts" ARGV is
+                * guaranteed to be initialized and hold enough elements to
+                * satisfy the query template.
                 */
                QUOTE_VAL(ctx->dict, quote_func,
-                         parts->argv[parts->argc-(*cp-'0')], result);
+                         parts->argv[parts->argc - (*cp - '0')], result);
                break;
 
            default:
@@ -449,11 +465,11 @@ int db_common_expand(void *ctxArg, const char *format, const char *value,
     VSTRING_TERMINATE(result);
 
     if (vuser)
-       myfree(vuser);
+       myfree(vuser);
     if (kuser)
-       myfree(kuser);
+       myfree(kuser);
     if (parts)
-       argv_free(parts);
+       argv_free(parts);
 
     return (1);
 }
index 613ce47c974cfb05714033e908afc332aeaac195..0f6695db2d5fe2a8e00af2dd9cc92cc7d5062bfd 100644 (file)
@@ -870,7 +870,7 @@ extern char *var_bestmx_transp;
 
 #define VAR_SMTP_CACHE_CONNT   "smtp_connection_cache_time_limit"
 #define DEF_SMTP_CACHE_CONNT   "2s"
-#define VAR_LMTP_CACHE_CONNT   "smtp_connection_cache_time_limit"
+#define VAR_LMTP_CACHE_CONNT   "lmtp_connection_cache_time_limit"
 #define DEF_LMTP_CACHE_CONNT   "2s"
 extern int var_smtp_cache_conn;
 
index 45414bc4472ddf9a3d66f115aae7068c8a0ab312..fc5b98bc3c5e2be1c6181814a5271f94906e967e 100644 (file)
@@ -20,7 +20,7 @@
   * Patches change both the patchlevel and the release date. Snapshots have no
   * patchlevel; they change the release date only.
   */
-#define MAIL_RELEASE_DATE      "20060325"
+#define MAIL_RELEASE_DATE      "20060403"
 #define MAIL_VERSION_NUMBER    "2.3"
 
 #ifdef SNAPSHOT
index 8939ba2bb2f3faca1f1503df78938fa43064741b..2ccbd25283b6a4d7e2b4124e32f538d233301735 100644 (file)
 /*     The command is specified as an argument vector. This vector is
 /*     passed without further inspection to the \fIexecvp\fR() routine.
 /*     One of PIPE_CMD_COMMAND or PIPE_CMD_ARGV must be specified.
+/* .IP "PIPE_CMD_CHROOT (char *)"
+/*     Root and working directory for command execution. This takes
+/*     effect before PIPE_CMD_CWD. A null pointer means don't
+/*     change root and working directory anyway. Failure to change
+/*     directory causes mail delivery to be deferred.
 /* .IP "PIPE_CMD_CWD (char *)"
-/*     Working directory for command execution. A null pointer means
+/*     Working directory for command execution, after changing process
+/*     privileges to PIPE_CMD_UID and PIPE_CMD_GID. A null pointer means
 /*     don't change directory anyway. Failure to change directory
 /*     causes mail delivery to be deferred.
 /* .IP "PIPE_CMD_ENV (char **)"
 
 #include <msg.h>
 #include <vstream.h>
+#include <msg_vstream.h>
 #include <vstring.h>
 #include <stringops.h>
 #include <iostuff.h>
 #include <set_ugid.h>
 #include <set_eugid.h>
 #include <argv.h>
+#include <chroot_uid.h>
 
 /* Global library. */
 
@@ -172,6 +180,7 @@ struct pipe_args {
     char  **export;                    /* exportable environment */
     char   *shell;                     /* command shell */
     char   *cwd;                       /* preferred working directory */
+    char   *chroot;                    /* root directory */
 };
 
 static int pipe_command_timeout;       /* command has timed out */
@@ -200,6 +209,7 @@ static void get_pipe_args(struct pipe_args * args, va_list ap)
     args->export = 0;
     args->shell = 0;
     args->cwd = 0;
+    args->chroot = 0;
 
     pipe_command_maxtime = var_command_maxtime;
 
@@ -254,6 +264,9 @@ static void get_pipe_args(struct pipe_args * args, va_list ap)
        case PIPE_CMD_CWD:
            args->cwd = va_arg(ap, char *);
            break;
+       case PIPE_CMD_CHROOT:
+           args->chroot = va_arg(ap, char *);
+           break;
        default:
            msg_panic("%s: unknown key: %d", myname, key);
        }
@@ -357,14 +370,22 @@ static int pipe_command_wait_or_kill(pid_t pid, WAIT_STATUS_T *statusp, int sig,
 
 static void pipe_child_cleanup(void)
 {
-    exit(EX_TEMPFAIL);
+
+    /*
+     * WARNING: don't place code here. This code may run as mail_owner, as
+     * root, or as the user/group specified with the "user" attribute. The
+     * only safe action is to terminate.
+     * 
+     * Future proofing. If you need exit() here then you broke Postfix.
+     */
+    _exit(EX_TEMPFAIL);
 }
 
 /* pipe_command - execute command with extreme prejudice */
 
 int     pipe_command(VSTREAM *src, DSN_BUF *why,...)
 {
-    char   *myname = "pipe_comand";
+    char   *myname = "pipe_command";
     va_list ap;
     VSTREAM *cmd_in_stream;
     VSTREAM *cmd_out_stream;
@@ -448,6 +469,28 @@ int     pipe_command(VSTREAM *src, DSN_BUF *why,...)
         */
     case 0:
        (void) msg_cleanup(pipe_child_cleanup);
+
+       /*
+        * In order to chroot it is necessary to switch euid back to root.
+        * Right after chroot we call set_ugid() so all privileges will be
+        * dropped again.
+        * 
+        * XXX For consistency we use chroot_uid() to change root+current
+        * directory. However, we must not use chroot_uid() to change process
+        * privileges (assuming a version that accepts numeric privileges).
+        * That would create a maintenance problem, because we would have two
+        * different code paths to set the external command's privileges.
+        */
+       if (args.chroot) {
+           seteuid(0);
+           chroot_uid(args.chroot, (char *) 0);
+       }
+
+       /*
+        * XXX If we put code before the set_ugid() call, then the code that
+        * changes root directory must switch back to the mail_owner UID,
+        * otherwise we'd be running with root privileges.
+        */
        set_ugid(args.uid, args.gid);
        if (setsid() < 0)
            msg_warn("setsid failed: %m");
@@ -488,12 +531,15 @@ int     pipe_command(VSTREAM *src, DSN_BUF *why,...)
        /*
         * Process plumbing. If possible, avoid running a shell.
         * 
-        * From this point we would like to handle fatal errors ourselves
-        * (ENOMEM would probably be one of the few soft error conditions).
-        * For that we have to update exec_command() first so it returns an
-        * error indication instead of terminating the process.
+        * As a safety for buggy libraries, we close the syslog socket.
+        * Otherwise we could leak a file descriptor that was created by a
+        * privileged process.
+        * 
+        * XXX To avoid losing fatal error messages we open a VSTREAM and
+        * capture the output in the parent process.
         */
        closelog();
+       msg_vstream_init(var_procname, VSTREAM_ERR);
        if (args.argv) {
            execvp(args.argv[0], args.argv);
            msg_fatal("%s: execvp %s: %m", myname, args.argv[0]);
@@ -605,7 +651,10 @@ int     pipe_command(VSTREAM *src, DSN_BUF *why,...)
                return (sp->dsn[0] == '4' ?
                        PIPE_STAT_DEFER : PIPE_STAT_BOUNCE);
            }
-           /* No "D.S.N text" or <sysexits.h> compatible status. Fake it. */
+
+           /*
+            * No "D.S.N text" or <sysexits.h> compatible status. Fake it.
+            */
            else {
                sp = sys_exits_detail(WEXITSTATUS(wait_status));
                dsb_unix(why, sp->dsn,
index 694adb19def98f1110ec0065b45547d3166aec32..339ac5ec015f4900ba146e6cc2eb1c4c439c167c 100644 (file)
@@ -41,6 +41,7 @@
 #define PIPE_CMD_EXPORT                12      /* exportable environment */
 #define PIPE_CMD_ORIG_RCPT     13      /* mail_copy() original recipient */
 #define PIPE_CMD_CWD           14      /* working directory */
+#define PIPE_CMD_CHROOT                15      /* chroot() before exec() */
 
  /*
   * Command completion status.
index d8670c97af2f77e227b234995c42c1189adfe0b5..b35b689fea974a1c90c0f3ebe4750767481228c0 100644 (file)
 /* .fi
 /*     The external command attributes are given in the \fBmaster.cf\fR
 /*     file at the end of a service definition.  The syntax is as follows:
-/* .IP "\fBdirectory=\fIpathname\fR (optional, default: \fB$queue_directory\fR)"
+/* .IP "\fBchroot=\fIpathname\fR (optional)"
+/*     Change the process root directory and working directory to
+/*     the named directory. This happens before switching to the
+/*     privileges specified with the \fBuser\fR attribute, and
+/*     before executing the optional \fBdirectory=\fIpathname\fR
+/*     directive. Delivery is deferred in case of failure.
+/* .sp
+/*     This feature is available as of Postfix 2.3.
+/* .IP "\fBdirectory=\fIpathname\fR (optional)"
 /*     Change to the named directory before executing the external command.
+/*     The directory must be accessible for the user specified with the
+/*     \fBuser\fR attribute (see below).
+/*     The default working directory is \fB$queue_directory\fR.
 /*     Delivery is deferred in case of failure.
 /* .sp
 /*     This feature is available as of Postfix 2.2.
 /*     be returned to the sender as undeliverable.
 /* .IP "\fBuser\fR=\fIusername\fR (required)"
 /* .IP "\fBuser\fR=\fIusername\fR:\fIgroupname\fR"
-/*     The external command is executed with the rights of the
+/*     Execute the external command with the rights of the
 /*     specified \fIusername\fR.  The software refuses to execute
 /*     commands with root privileges, or with the privileges of the
 /*     mail system owner. If \fIgroupname\fR is specified, the
@@ -474,6 +485,7 @@ typedef struct {
     gid_t   gid;                       /* command privileges */
     int     flags;                     /* mail_copy() flags */
     char   *exec_dir;                  /* working directory */
+    char   *chroot_dir;                        /* chroot directory */
     VSTRING *eol;                      /* output record delimiter */
     VSTRING *null_sender;              /* null sender expansion */
     off_t   size_limit;                        /* max size in bytes we will accept */
@@ -728,6 +740,7 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
     attr->command = 0;
     attr->flags = 0;
     attr->exec_dir = 0;
+    attr->chroot_dir = 0;
     attr->eol = vstring_strcpy(vstring_alloc(1), "\n");
     attr->null_sender = vstring_strcpy(vstring_alloc(1), MAIL_ADDR_MAIL_DAEMON);
     attr->size_limit = 0;
@@ -807,6 +820,13 @@ static void get_service_attr(PIPE_ATTR *attr, char **argv)
            attr->exec_dir = mystrdup(*argv + sizeof("directory=") - 1);
        }
 
+       /*
+        * chroot=string
+        */
+       else if (strncasecmp("chroot=", *argv, sizeof("chroot=") - 1) == 0) {
+           attr->chroot_dir = mystrdup(*argv + sizeof("chroot=") - 1);
+       }
+
        /*
         * eol=string
         */
@@ -1105,6 +1125,7 @@ static int deliver_message(DELIVER_REQUEST *request, char *service, char **argv)
                                  PIPE_CMD_EOL, STR(attr.eol),
                                  PIPE_CMD_EXPORT, export_env->argv,
                                  PIPE_CMD_CWD, attr.exec_dir,
+                                 PIPE_CMD_CHROOT, attr.chroot_dir,
                           PIPE_CMD_ORIG_RCPT, rcpt_list->info[0].orig_addr,
                             PIPE_CMD_DELIVERED, rcpt_list->info[0].address,
                                  PIPE_CMD_END);
index 65814b255606ba992897eed2cdfd2c4038c64df6..610f72ac5def74858c32b9ede8a48ac1d5376334 100644 (file)
@@ -107,7 +107,9 @@ int     myflock(int fd, int lock_style, int operation)
                -1, LOCK_SH | LOCK_NB, LOCK_EX | LOCK_NB, -1
            };
 
-           status = flock(fd, lock_ops[operation]);
+           while ((status = flock(fd, lock_ops[operation])) < 0
+                  && errno == EINTR)
+               sleep(1);
            break;
        }
 #endif
@@ -129,8 +131,7 @@ int     myflock(int fd, int lock_style, int operation)
            lock.l_type = lock_ops[operation & ~MYFLOCK_OP_NOWAIT];
            request = (operation & MYFLOCK_OP_NOWAIT) ? F_SETLK : F_SETLKW;
            while ((status = fcntl(fd, request, &lock)) < 0
-                  && request == F_SETLKW
-                && (errno == EINTR || errno == ENOLCK || errno == EDEADLK))
+                  && errno == EINTR)
                sleep(1);
            break;
        }