a file descriptor into its child process, and requires that
sendmail closes the descriptor, otherwise mail notification
will hang. These GUI programmers never figured out that
- the child process must close the writing ed of a pipe.
+ the child process must close the writing end of a pipe.
File: sendmail/sendmail.c.
20000314
Workaround: added -blibpath option for AIX 4.x, to close
hole in case postdrop needs to be set-gid.
+
+20000320
+
+ Portability: FreeBSD 5.x added to the list of supported
+ systems (Mark Huizer).
+
+20000323
+
+ Portability: INSTALL.sh looks if sendmail is in /usr/lib
+ rather than in /usr/sbin.
+
+20000326
+
+ Bugfix: settings in one mysql configuration file would act
+ as the implicit defaults for the next one, which could be
+ confusing. Patch by Scott Cotton. File: util/dict_mysql.c.
+
+ Robustness: limit the number of "junk" commands that can
+ be issued in an SMTP session (ex.: NOOP, VRFY, ETRN, RSET).
+ Problem report by Michael Ju. Tokarev @ tls.msk.ru. Files:
+ global/mail_params.h, smtpd/smtpd.c.
FreeBSD 2.x
FreeBSD 3.x
FreeBSD 4.x
+ FreeBSD 5.x
HP-UX 9.x
HP-UX 10.x
HP-UX 11.x
or something closely resemblant.
+On Solaris, the "make" command and other utilities for software
+development are in /usr/ccs/bin, so you MUST have /usr/ccs/bin
+in your command search path.
+
If at any time in the build process you get messages like: "make:
don't know how to ..." you should be able to recover by running
the following command from the Postfix top-level directory:
compare_or_replace() {
cmp $2 $3 >/dev/null 2>&1 || {
+ echo Updating $3...
rm -f $tempdir/junk || exit 1
cp $2 $tempdir/junk || exit 1
chmod $1 $tempdir/junk || exit 1
compare_or_symlink() {
cmp $1 $2 >/dev/null 2>&1 || {
+ echo Updating $2...
rm -f $tempdir/junk || exit 1
dest=`echo $1 | sed '
s;^'$install_root';;
compare_or_move() {
cmp $2 $3 >/dev/null 2>&1 || {
+ echo Updating $3...
mv -f $2 $3 || exit 1
chmod $1 $3 || exit 1
}
daemon_directory=/usr/libexec/postfix
command_directory=/usr/sbin
queue_directory=/var/spool/postfix
-sendmail_path=/usr/sbin/sendmail
+if [ -f /usr/lib/sendmail ]
+ then sendmail_path=/usr/lib/sendmail
+ else sendmail_path=/usr/sbin/sendmail
+fi
newaliases_path=/usr/bin/newaliases
mailq_path=/usr/bin/mailq
mail_owner=postfix
for file in man?/*
do
(test -f $MANPAGES/$file && cmp -s $file $MANPAGES/$file) || {
+ echo Updating $MANPAGES/$file...
rm -f $MANPAGES/$file
cp $file $MANPAGES/$file || exit 1
chmod 644 $MANPAGES/$file || exit 1
Incompatible changes with snapshot-20000309
===========================================
-This release is mainly to have a reference point after reorganizing
-the cleanup daemon, and before adding some major contributions from
-other people.
-
-The sendmail command now treats a `.' line as end of input, for
-the sake of compatibility. To revert to past behavior, specify the
-`-i' or `-oi' command-line flags.
+The Postfix sendmail command now treats a line with only `.' as
+the end of input, for the sake of sendmail compatibility. To disable
+this feature, specify the sendmail-compatible `-i' or `-oi' flags
+on the sendmail command line.
Major changes with snapshot-20000309
====================================
Other SASL libraries may require some changes. All the library
specific code is in smtp_sasl_glue.c and in smtpd_sasl_glue.c.
+IMPORTANT: if you install the sasl libraries as per the default,
+you will have to symlink /usr/lib/sasl -> /usr/local/lib/sasl.
+This is not my idea - complain to the sasl people.
+
Building Postfix with SASL authentication support
=================================================
pwcheck_method: {PAM, kerberos_v4, passwd, shadow, sasldb}
-/etc/sasldb is a db (dbm) database. IN order to make all this work
+/etc/sasldb is a db (dbm) database. In order to make all this work
with chrooted operation, you may have to copy files into chroot
jail: password files, PAM libraries, etc.
state->resent, vstring_str(state->temp1));
}
}
-#ifdef USE_AUTH
- /*
- * Add client and sender identity headers if configured
- */
- if (cleanup_auth_client_identity && *var_cleanup_auth_client_header) {
- cleanup_out_format(REC_TYPE_NORM, "%s %s@%s",
- var_cleanup_auth_client_header,
- cleanup_auth_client_identity,
- var_cleanup_auth_client_header_domain);
- }
- if (cleanup_auth_sender_identity && *var_cleanup_auth_sender_header) {
- cleanup_out_format(REC_TYPE_NORM, "%s %s",
- var_cleanup_auth_sender_header,
- cleanup_auth_sender_identity);
- }
-#endif
}
/* cleanup_message - initialize message content segment */
+umask 022
mkdir /var/spool/postfix/etc
chmod 755 /var/spool/postfix/etc
for i in /etc/environment /etc/netsvc.conf /etc/localtime
+umask 022
mkdir /var/spool/postfix/etc
chmod 755 /var/spool/postfix/etc
cp /etc/localtime /etc/services /etc/resolv.conf /var/spool/postfix/etc
+umask 022
mkdir /var/spool/postfix/etc
chmod 755 /var/spool/postfix/etc
cp /etc/localtime /etc/services /etc/resolv.conf /var/spool/postfix/etc
+umask 022
mkdir /var/spool/postfix/etc
chmod 755 /var/spool/postfix/etc
cd /etc ; cp host.conf localtime services resolv.conf /var/spool/postfix/etc
+umask 022
mkdir /var/spool/postfix/etc
chmod 755 /var/spool/postfix/etc
cd /etc ; cp host.conf localtime services resolv.conf /var/spool/postfix/etc
+umask 022
mkdir /var/spool/postfix/etc
chmod 755 /var/spool/postfix/etc
cd /etc ; cp localtime services resolv.conf /var/spool/postfix/etc
#!/bin/sh
+umask 022
PATH=/usr/bin:/sbin:/usr/sbin
# Create chroot'd area under Solaris 2.5.1 for postfix.
#define DEF_SMTPD_ERR_SLEEP 5
extern int var_smtpd_err_sleep;
+#define VAR_SMTPD_JUNK_CMD "smtpd_junk_command_limit"
+#define DEF_SMTPD_JUNK_CMD 1000
+extern int var_smtpd_junk_cmd_limit;
+
/*
* SASL authentication support.
*/
-#ifdef USE_SASL_AUTH
-
#define VAR_SMTPD_SASL_ENABLE "smtpd_sasl_auth_enable"
#define DEF_SMTPD_SASL_ENABLE 0
extern bool var_smtpd_sasl_enable;
#define PERMIT_SASL_AUTH "permit_sasl_authenticated"
-#endif
-
/*
* Cleanup service. Header info that exceeds $header_size_limit bytes forces
* the start of the message body.
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20000316"
+#define DEF_MAIL_VERSION "Snapshot-20000330"
extern char *var_mail_version;
/* LICENSE
<ul>
+<li><a href="#delay">Postfix responds slowly to SMTP connections</a>
+
<li><a href="#numerical_log">Postfix logs SMTP clients as IP
addresses</a>
<hr>
+<a name="delay"><h3>Postfix responds slowly to SMTP connections</h3></a>
+
+<dl>
+
+<dt>Question:
+
+<dd> My Postfix server is too slow. When I telnet to the SMTP port
+(<tt>telnet hostname 25</tt>), the response comes after 40 seconds.
+On the other hand, when I telnet to the the POP port (<tt>telnet
+hostname 110</tt>) the response comes with no delay.
+
+<p>
+
+<dt>Answer:
+
+<dd>
+
+This is a DNS configuration problem. Postfix tries to resolve the
+SMTP client IP address to a hostname. Apparently, your POP server
+does not look up POP clients.
+
+<p>
+
+The fix is to properly configure the naming service. If you can't
+have every host in the DNS, then configure the mail server to look
+in /etc/hosts before the DNS, and specify the clients in /etc/hosts.
+
+</dl>
+
+<hr>
+
<a name="numerical_log"><h3>Postfix logs SMTP clients as IP
addresses</h3>
;;
FreeBSD.4*) SYSTYPE=FREEBSD4
;;
+ FreeBSD.5*) SYSTYPE=FREEBSD5
+ ;;
OpenBSD.2*) SYSTYPE=OPENBSD2
;;
NetBSD.1*) SYSTYPE=NETBSD1
Sendmail command-line options are recognized but silently ignored.
By default, \fBsendmail\fR reads a message from standard input
+until EOF or until it reads a line with only a \fB.\fR character,
and arranges for delivery. \fBsendmail\fR attempts to create
a queue file in the \fBmaildrop\fR directory. If that directory
is not world-writable, the message is piped through the
.IP "\fB-h \fIhop_count\fR (ignored)"
Hop count limit. Use the \fBhopcount_limit\fR configuration
parameter instead.
-.IP "\fB-i\fR (ignored)"
-Lines beginning with "." get special treatment only with \fB-bs\fR.
+.IP "\fB-i\fR"
+When reading a message from standard input, don\'t treat a line
+with only a \fB.\fR character as the end of input.
.IP "\fB-m\fR (ignored)"
Backwards compatibility.
.IP "\fB-n\fR (ignored)"
.IP "\fB-o8\fR (ignored)"
The message body type. Currently, Postfix implements
\fBjust-send-eight\fR.
+.IP "\fB-oi\fR"
+When reading a message from standard input, don\'t treat a line
+with only a \fB.\fR character as the end of input.
.IP "\fB-om\fR (ignored)"
The sender is never eliminated from alias etc. expansions.
.IP "\fB-o \fIx value\fR (ignored)"
.ad
.fi
The Postfix mail system uses optional tables for address
-rewriting or mail routing. These tables usually are in
+rewriting or mail routing. These tables are usually in
\fBdbm\fR or \fBdb\fR format. Alternatively, lookup tables
can be specified in Perl Compatible Regular Expression form.
.ad
.fi
The Postfix mail system uses optional tables for address
-rewriting or mail routing. These tables usually are in
+rewriting or mail routing. These tables are usually in
\fBdbm\fR or \fBdb\fR format. Alternatively, lookup tables
can be specified in POSIX regular expression form.
RFC 1854 (SMTP Pipelining)
RFC 1870 (Message Size Declaration)
RFC 1985 (ETRN command) (partial)
+RFC 2554 (AUTH command)
.SH DIAGNOSTICS
.ad
.fi
.IP \fBstrict_rfc821_envelopes\fR
Disallow non-RFC 821 style addresses in envelopes. For example,
allow RFC822-style address forms with comments, like Sendmail does.
+.SH "Authenication controls"
+.IP \fBenable_sasl_authentication\fR
+Enable per-session authentication as per RFC 2554 (SASL).
+This functionality is available only when explicitly selected
+at program build time and explicitly enabled at runtime.
.SH Miscellaneous
.ad
.fi
\fIerror_count\fR seconds before responding to any client request.
.IP \fBsmtpd_hard_error_limit\fR
Disconnect after a client has made this number of errors.
+.IP \fBsmtpd_junk_command_limit\fR
+Limit the number of times a client can issue a junk command
+such as NOOP, VRFY, ETRN or RSET in one SMTP session before
+it is penalized with tarpit delays.
.SH "UCE control restrictions"
.ad
.fi
vstream_fclose(stream);
return (0);
}
+ vstream_ungetc(stream, ch);
/*
* Skip this host if it sends a 4xx greeting.
vstream_fclose(stream);
return (0);
}
- vstream_ungetc(stream, ch);
return (smtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr)));
}
/* DESCRIPTION
/* This module contains random chunks of code that implement
/* the SMTP protocol interface for SASL negotiation. The goal
-/* is to reduce clutter of the main SMTP client source code.
+/* is to reduce clutter in the main SMTP client source code.
/*
/* smtp_sasl_helo_auth() processes the AUTH option in the
/* SMTP server's EHLO response.
/* memory for buffers etc.
/*
/* smtp_cleanup() destroys memory allocated by smtp_state_init().
+/* STANDARDS
+/* DIAGNOSTICS
+/* BUGS
+/* SEE ALSO
/* LICENSE
/* .ad
/* .fi
vstring_free(state->buffer);
vstring_free(state->scratch);
vstring_free(state->scratch2);
-#ifdef USE_AUTH
+#ifdef USE_SASL_AUTH
smtp_sasl_cleanup(state);
#endif
myfree((char *) state);
/* \fIerror_count\fR seconds before responding to any client request.
/* .IP \fBsmtpd_hard_error_limit\fR
/* Disconnect after a client has made this number of errors.
+/* .IP \fBsmtpd_junk_command_limit\fR
+/* Limit the number of times a client can issue a junk command
+/* such as NOOP, VRFY, ETRN or RSET in one SMTP session before
+/* it is penalized with tarpit delays.
/* .SH "UCE control restrictions"
/* .ad
/* .fi
char *var_alias_maps;
char *var_local_rcpt_maps;
bool var_allow_untrust_route;
-
-#ifdef USE_SASL_AUTH
+int var_smtpd_junk_cmd_limit;
bool var_smtpd_sasl_enable;
-#endif
-
/*
* Global state, for stand-alone mode queue file cleanup. When this is
* non-null at cleanup time, the named file is removed.
typedef struct SMTPD_CMD {
char *name;
int (*action) (SMTPD_STATE *, int, SMTPD_TOKEN *);
+ int flags;
} SMTPD_CMD;
+#define SMTPD_CMD_FLAG_LIMIT (1<<0) /* limit usage */
+
static SMTPD_CMD smtpd_cmd_table[] = {
- "HELO", helo_cmd,
- "EHLO", ehlo_cmd,
+ "HELO", helo_cmd, 0,
+ "EHLO", ehlo_cmd, 0,
#ifdef USE_SASL_AUTH
- "AUTH", smtpd_sasl_auth_cmd,
+ "AUTH", smtpd_sasl_auth_cmd, 0,
#endif
- "MAIL", mail_cmd,
- "RCPT", rcpt_cmd,
- "DATA", data_cmd,
- "RSET", rset_cmd,
- "NOOP", noop_cmd,
- "VRFY", vrfy_cmd,
- "ETRN", etrn_cmd,
- "QUIT", quit_cmd,
+ "MAIL", mail_cmd, 0,
+ "RCPT", rcpt_cmd, 0,
+ "DATA", data_cmd, 0,
+ "RSET", rset_cmd, SMTPD_CMD_FLAG_LIMIT,
+ "NOOP", noop_cmd, SMTPD_CMD_FLAG_LIMIT,
+ "VRFY", vrfy_cmd, SMTPD_CMD_FLAG_LIMIT,
+ "ETRN", etrn_cmd, SMTPD_CMD_FLAG_LIMIT,
+ "QUIT", quit_cmd, 0,
0,
};
state->where = cmdp->name;
if (cmdp->action(state, argc, argv) != 0)
state->error_count++;
+ if ((cmdp->flags & SMTPD_CMD_FLAG_LIMIT)
+ && state->junk_cmds++ > var_smtpd_junk_cmd_limit)
+ state->error_count++;
if (cmdp->action == quit_cmd)
break;
VAR_REJECT_CODE, DEF_REJECT_CODE, &var_reject_code, 0, 0,
VAR_SMTPD_ERR_SLEEP, DEF_SMTPD_ERR_SLEEP, &var_smtpd_err_sleep, 0, 0,
VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0,
+ VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0,
0,
};
static CONFIG_BOOL_TABLE bool_table[] = {
VAR_STRICT_RFC821_ENV, DEF_STRICT_RFC821_ENV, &var_strict_rfc821_env,
VAR_DISABLE_VRFY_CMD, DEF_DISABLE_VRFY_CMD, &var_disable_vrfy_cmd,
VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route,
-#ifdef USE_SASL_AUTH
VAR_SMTPD_SASL_ENABLE, DEF_SMTPD_SASL_ENABLE, &var_smtpd_sasl_enable,
-#endif
0,
};
static CONFIG_STR_TABLE str_table[] = {
char *where;
int recursion;
off_t msg_size;
+ int junk_cmds;
#ifdef USE_SASL_AUTH
char *sasl_mechanism_list;
char *sasl_method;
/* SMTPD_STATE *state;
/* DESCRIPTION
/* This module contains random chunks of code that implement
-/* the SMTP protocol interface for SASL negotiation. The goal
+/* the SMTP protocol interface for SASL negotiation. The goal
/* is to reduce clutter of the main SMTP server source code.
/*
/* smtpd_sasl_auth_cmd() implements the AUTH command.
/*
/* smtpd_sasl_auth_reset() cleans up after the AUTH command.
/*
-/* smtpd_sasl_mail_opt() implements the AUTH=sender option
-/* to the MAIL FROM command. The result is an error response
+/* smtpd_sasl_mail_opt() implements the SASL-specific AUTH=sender
+/* option to the MAIL FROM command. The result is an error response
/* in case of problems.
/*
-/* smtpd_sasl_mail_log() logs the queue ID and client information.
+/* smtpd_sasl_mail_log() logs SASL-specific information after
+/* processing the MAIL FROM command.
/*
-/* smtpd_sasl_mail_reset() cleans up after the AUTH=sender option.
+/* smtpd_sasl_mail_reset() performs cleanup for the SASL-specific
+/* AUTH=sender option to the MAIL FROM command.
/*
/* Arguments:
/* .IP state
}
/*
- * All authentication failures shall be logged. The 5xx reply code
- * triggers tar-pit delays in order to slow down password guessing
- * attacks.
+ * All authentication failures shall be logged. The 5xx reply code from
+ * the SASL authentication routine triggers tar-pit delays, which help to
+ * slow down password guessing attacks.
*/
auth_mechanism = argv[1].strval;
initial_response = (argc == 3 ? argv[2].strval : 0);
smtpd_sasl_logout(state);
}
-/* smtpd_sasl_mail_opt - SASL-specific AUTH=sender option */
+/* smtpd_sasl_mail_opt - SASL-specific MAIL FROM option */
char *smtpd_sasl_mail_opt(SMTPD_STATE *state, const char *addr)
{
+
+ /*
+ * Do not store raw RFC2554 protocol data.
+ */
if (!var_smtpd_sasl_enable) {
state->error_mask |= MAIL_ERROR_PROTOCOL;
return ("503 Error: authentication disabled");
return (0);
}
-/* smtpd_sasl_mail_log - SASL-specific MAIL FROM command logging */
+/* smtpd_sasl_mail_log - SASL-specific MAIL FROM logging */
void smtpd_sasl_mail_log(SMTPD_STATE *state)
{
state->where = SMTPD_AFTER_CONNECT;
state->recursion = 0;
state->msg_size = 0;
+ state->junk_cmds = 0;
#ifdef USE_SASL_AUTH
smtpd_sasl_connect(state);
/* answer already found */
if (res != 0 && host->stat == STATACTIVE) {
- msg_info("dict_mysql: closing unnecessary connection to %s", host->hostname);
+ msg_info("dict_mysql: closing unnessary connection to %s", host->hostname);
mysql_close(&(host->db)); /* also frees memory, have to
* reallocate it */
host->db = *((MYSQL *) mymalloc(sizeof(MYSQL)));
int i;
char *nameval;
char *hosts;
+ /* the name of the dict for processing the mysql options file */
MYSQL_NAME *name = (MYSQL_NAME *) mymalloc(sizeof(MYSQL_NAME));
ARGV *hosts_argv;
-
- dict_load_file("mysql_options", mysqlcf_path);
+
+ dict_load_file(mysqlcf_path, mysqlcf_path);
/* mysql username lookup */
- if ((nameval = (char *) dict_lookup("mysql_options", "user")) == NULL)
+ if ((nameval = (char *) dict_lookup(mysqlcf_path, "user")) == NULL)
name->username = mystrdup("");
else
name->username = mystrdup(nameval);
if (msg_verbose)
msg_info("mysqlname_parse(): set username to '%s'", name->username);
/* password lookup */
- if ((nameval = (char *) dict_lookup("mysql_options", "password")) == NULL)
+ if ((nameval = (char *) dict_lookup(mysqlcf_path, "password")) == NULL)
name->password = mystrdup("");
else
name->password = mystrdup(nameval);
msg_info("mysqlname_parse(): set password to '%s'", name->password);
/* database name lookup */
- if ((nameval = (char *) dict_lookup("mysql_options", "dbname")) == NULL)
+ if ((nameval = (char *) dict_lookup(mysqlcf_path, "dbname")) == NULL)
msg_fatal("%s: mysql options file does not include database name", mysqlcf_path);
else
name->dbname = mystrdup(nameval);
msg_info("mysqlname_parse(): set database name to '%s'", name->dbname);
/* table lookup */
- if ((nameval = (char *) dict_lookup("mysql_options", "table")) == NULL)
+ if ((nameval = (char *) dict_lookup(mysqlcf_path, "table")) == NULL)
msg_fatal("%s: mysql options file does not include table name", mysqlcf_path);
else
name->table = mystrdup(nameval);
msg_info("mysqlname_parse(): set table name to '%s'", name->table);
/* select field lookup */
- if ((nameval = (char *) dict_lookup("mysql_options", "select_field")) == NULL)
+ if ((nameval = (char *) dict_lookup(mysqlcf_path, "select_field")) == NULL)
msg_fatal("%s: mysql options file does not include select field", mysqlcf_path);
else
name->select_field = mystrdup(nameval);
msg_info("mysqlname_parse(): set select_field to '%s'", name->select_field);
/* where field lookup */
- if ((nameval = (char *) dict_lookup("mysql_options", "where_field")) == NULL)
+ if ((nameval = (char *) dict_lookup(mysqlcf_path, "where_field")) == NULL)
msg_fatal("%s: mysql options file does not include where field", mysqlcf_path);
else
name->where_field = mystrdup(nameval);
msg_info("mysqlname_parse(): set where_field to '%s'", name->where_field);
/* additional conditions */
- if ((nameval = (char *) dict_lookup("mysql_options", "additional_conditions")) == NULL)
+ if ((nameval = (char *) dict_lookup(mysqlcf_path, "additional_conditions")) == NULL)
name->additional_conditions = mystrdup("");
else
name->additional_conditions = mystrdup(nameval);
msg_info("mysqlname_parse(): set additional_conditions to '%s'", name->additional_conditions);
/* mysql server hosts */
- if ((nameval = (char *) dict_lookup("mysql_options", "hosts")) == NULL)
+ if ((nameval = (char *) dict_lookup(mysqlcf_path, "hosts")) == NULL)
hosts = mystrdup("");
else
hosts = mystrdup(nameval);
* makedefs script, and adding a section below for the new system.
*/
#if defined(FREEBSD2) || defined(FREEBSD3) || defined(FREEBSD4) \
+ || defined(FREEBSD5) \
|| defined(BSDI2) || defined(BSDI3) || defined(BSDI4) \
|| defined(OPENBSD2) || defined(NETBSD1)
#define SUPPORTED