tls/tls_client.c, util/dict_alloc.c, util/dict_open.c,
util/match_list.c.
-20150214
+20150124
Workaround: nroff has been improved so that "-" comes out as
some non-ASCII character, unlike HTML where it comes out
hops to generate HTML and nroff input from the same source
text. Files; mantools/srctoman, mantools/postconf2man.
-20150524
-
Cleanup: UTF-8 support in masquerade_domains. File:
cleanup/cleanup_masquerade.c.
-20150525
+20150125
Cleanup: simplified the casefold() API: no input-dependent
failure modes. Files: cleanup/cleanup_masquerade.c,
20150127
- Cleanup: simplified the 20150525 and 20150126 APIs, replacing
+ Cleanup: simplified the 20150125 and 20150126 APIs, replacing
the most-common use cases with convenience macros that have
fewer arguments. Files: anything that implements or invokes
casefold*() or str*casecmp().
Cleanup: after many years, the access(5) map BCC action is
part of the stable release. Files: smtpd/smtpd_check.c,
proto/acces.
+
+20150210
+
+ Cleanup: socketmap documentation. File: proto/socketmap_table.
+
+20150211
+
+ Cleanup: strncasecmp_utf8() streamlining. Files: util/stringops.h,
+ util/allascii.c, util/strcasecmp_utf8.c.
+
+20150212
+
+ Cleanup: in code after reading main.cf, removed bogus guard
+ before re-evaluating the mail_task() syslog prefix. File:
+ postlog/postlog.c.
+
+20150214
+
+ Bugfix: missing #ifdef USE_TLS inside #ifdef USE_SASL_AUTH
+ broke the build. Viktor Dukhovni. File: smtpd/smtpd.c.
+
+ Cleanup: missing errno logging in bounce daemon clients.
+ This made troubleshooting significantly more difficult.
+ File: global/mail_command_client.c.
+
+20150216
+
+ Cleanup: documented that mail_connect() produces no errno
+ logging. The functions that call it should log the error
+ (and the majority does). File: global/mail_connect.c.
+
+ Cleanup: added errno logging after mail_connect() failure.
+ Files: global/post_mail.c, local/forward.c.
+
+ Cleanup: in code after reading main.cf, removed bogus guard
+ before re-evaluating the mail_task() syslog prefix. Files:
+ postalias/postalias.c, postdrop/postdrop.c, postmap/postmap.c,
+ postqueue/postqueue.c, postsuper/postsuper.c, sendmail/sendmail.c.
string object.
<b>REQUEST FORMAT</b>
- The socketmap protocol supports only the lookup request.
-
- Postfix will not generate partial search keys such as domain names
- without one or more subdomains, network addresses without one or more
- least-significant octets, or email addresses without the localpart,
- address extension or domain portion. This behavior is also found with
- <a href="cidr_table.5.html">cidr</a>:, <a href="pcre_table.5.html">pcre</a>:, and <a href="regexp_table.5.html">regexp</a>: tables.
+ The socketmap protocol supports only the lookup request. The request
+ has the following form:
<i>name</i> <<b>space</b>> <i>key</i>
Search the named socketmap for the specified key.
+ Postfix will not generate partial search keys such as domain names
+ without one or more subdomains, network addresses without one or more
+ least-significant octets, or email addresses without the localpart,
+ address extension or domain portion. This behavior is also found with
+ <a href="cidr_table.5.html">cidr</a>:, <a href="pcre_table.5.html">pcre</a>:, and <a href="regexp_table.5.html">regexp</a>: tables.
+
<b>REPLY FORMAT</b>
- The Postfix socketmap client requires that replies are not longer than
- 100000 characters (not including the netstring encapsulation). Replies
+ The Postfix socketmap client requires that replies are not longer than
+ 100000 characters (not including the netstring encapsulation). Replies
must have the following form:
<b>OK</b> <<b>space</b>> <i>data</i>
<b>TIMEOUT</b> <<b>space</b>> <i>reason</i>
<b>PERM</b> <<b>space</b>> <i>reason</i>
- The request failed. The reason, if non-empty, is descriptive
+ The request failed. The reason, if non-empty, is descriptive
text.
<b>SECURITY</b>
.ad
.fi
The socketmap protocol supports only the lookup request.
+The request has the following form:
+.IP "\fB\fIname\fB <space> \fIkey\fR"
+Search the named socketmap for the specified key.
+.PP
Postfix will not generate partial search keys such as domain
names without one or more subdomains, network addresses
without one or more least\-significant octets, or email
addresses without the localpart, address extension or domain
portion. This behavior is also found with cidr:, pcre:, and
regexp: tables.
-.IP "\fB\fIname\fB <space> \fIkey\fR"
-Search the named socketmap for the specified key.
.SH "REPLY FORMAT"
.na
.nf
# .ad
# .fi
# The socketmap protocol supports only the lookup request.
+# The request has the following form:
#
+# .IP "\fB\fIname\fB <space> \fIkey\fR"
+# Search the named socketmap for the specified key.
+# .PP
# Postfix will not generate partial search keys such as domain
# names without one or more subdomains, network addresses
# without one or more least-significant octets, or email
# addresses without the localpart, address extension or domain
# portion. This behavior is also found with cidr:, pcre:, and
# regexp: tables.
-# .IP "\fB\fIname\fB <space> \fIkey\fR"
-# Search the named socketmap for the specified key.
# REPLY FORMAT
# .ad
# .fi
mail_command_client.o: ../../include/check_arg.h
mail_command_client.o: ../../include/htable.h
mail_command_client.o: ../../include/iostuff.h
+mail_command_client.o: ../../include/msg.h
mail_command_client.o: ../../include/mymalloc.h
mail_command_client.o: ../../include/nvtable.h
mail_command_client.o: ../../include/sys_defs.h
/* Utility library. */
#include <vstream.h>
+#include <msg.h>
/* Global library. */
/*
* Talk a little protocol with the specified service.
+ *
+ * This function is used for non-critical services where it is OK to back
+ * off after the first error. Log what communication stage failed, to
+ * facilitate trouble analysis.
*/
- if ((stream = mail_connect(class, name, BLOCKING)) == 0)
+ if ((stream = mail_connect(class, name, BLOCKING)) == 0) {
+ msg_warn("connect to %s/%s: %m", class, name);
return (-1);
+ }
va_start(ap, name);
status = attr_vprint(stream, ATTR_FLAG_NONE, ap);
va_end(ap);
- if (status != 0
- || attr_scan(stream, ATTR_FLAG_STRICT,
- RECV_ATTR_INT(MAIL_ATTR_STATUS, &status), 0) != 1)
+ if (status != 0) {
+ msg_warn("write %s: %m", VSTREAM_PATH(stream));
status = -1;
+ } else if (attr_scan(stream, ATTR_FLAG_STRICT,
+ RECV_ATTR_INT(MAIL_ATTR_STATUS, &status), 0) != 1) {
+ msg_warn("write/read %s: %m", VSTREAM_PATH(stream));
+ status = -1;
+ }
(void) vstream_fclose(stream);
return (status);
}
/*
/* mail_connect() attempts to connect to the UNIX-domain socket of
/* the named subsystem. The result is a null pointer in case of failure.
+/* By default this function provides no errno logging.
/*
/* mail_connect_wait() is like mail_connect(), but keeps trying until
/* the connection succeeds. However, mail_connect_wait() terminates
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20150208"
+#define MAIL_RELEASE_DATE "20150216"
#define MAIL_VERSION_NUMBER "3.1"
#ifdef SNAPSHOT
BLOCKING)) != 0)
post_mail_init(stream, sender, recipient, source_class, trace_flags,
utf8_flags, queue_id);
+ else
+ msg_warn("connect to %s/%s: %m",
+ MAIL_CLASS_PUBLIC, var_cleanup_service);
return (stream);
}
* ourselves is that we don't really know who the recipients are.
*/
cleanup = mail_connect(MAIL_CLASS_PUBLIC, var_cleanup_service, BLOCKING);
- if (cleanup == 0)
+ if (cleanup == 0) {
+ msg_warn("connect to %s/%s: %m",
+ MAIL_CLASS_PUBLIC, var_cleanup_service);
FORWARD_OPEN_RETURN(0);
+ }
close_on_exec(vstream_fileno(cleanup), CLOSE_ON_EXEC);
if (attr_scan(cleanup, ATTR_FLAG_STRICT,
RECV_ATTR_STR(MAIL_ATTR_QUEUEID, buffer),
}
}
mail_conf_read();
- if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
- msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
+ /* Re-evaluate mail_task() after reading main.cf. */
+ msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
mail_dict_init();
/*
* perform some sanity checks on the input.
*/
mail_conf_read();
- if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
- msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY);
+ /* Re-evaluate mail_task() after reading main.cf. */
+ msg_syslog_init(mail_task("postdrop"), LOG_PID, LOG_FACILITY);
get_mail_conf_str_table(str_table);
/*
int main(int argc, char **argv)
{
struct stat st;
- char *slash;
int fd;
int ch;
const char *tag;
/*
* Set up diagnostics.
*/
- if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
- tag = mail_task(slash + 1);
- else
- tag = mail_task(argv[0]);
+ tag = mail_task(argv[0]);
if (isatty(STDERR_FILENO))
msg_vstream_init(tag, VSTREAM_ERR);
msg_syslog_init(tag, LOG_PID, LOG_FACILITY);
/*
* Parse switches.
*/
+ tag = 0;
while ((ch = GETOPT(argc, argv, "c:ip:t:v")) > 0) {
switch (ch) {
default:
- msg_fatal("usage: %s [-c config_dir] [-i] [-p priority] [-t tag] [-v] [text]", tag);
+ msg_fatal("usage: %s [-c config_dir] [-i] [-p priority] [-t tag] [-v] [text]", argv[0]);
break;
case 'c':
if (setenv(CONF_ENV_PATH, optarg, 1) < 0)
}
/*
- * Process the main.cf file. This overrides any logging facility that was
- * specified with msg_syslog_init();
+ * Process the main.cf file. This may change the syslog_name setting and
+ * may require that mail_task() be re-evaluated.
*/
mail_conf_read();
- if (tag == 0 && strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0) {
- if ((slash = strrchr(argv[0], '/')) != 0 && slash[1])
- tag = mail_task(slash + 1);
- else
- tag = mail_task(argv[0]);
- }
+ if (tag == 0)
+ tag = mail_task(argv[0]);
/*
* Re-initialize the logging, this time with the tag specified in main.cf
* or on the command line.
*/
- if (tag != 0) {
- if (isatty(STDERR_FILENO))
- msg_vstream_init(tag, VSTREAM_ERR);
- msg_syslog_init(tag, LOG_PID, LOG_FACILITY);
- }
+ if (isatty(STDERR_FILENO))
+ msg_vstream_init(tag, VSTREAM_ERR);
+ msg_syslog_init(tag, LOG_PID, LOG_FACILITY);
/*
* Log the command line or log lines from standard input.
}
}
mail_conf_read();
- if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
- msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
+ /* Re-evaluate mail_task() after reading main.cf. */
+ msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
mail_dict_init();
if ((query == 0 || strcmp(query, "-") != 0)
&& (postmap_flags & POSTMAP_FLAG_ANY_KEY))
* Further initialization...
*/
mail_conf_read();
- if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
- msg_syslog_init(mail_task("postqueue"), LOG_PID, LOG_FACILITY);
+ /* Re-evaluate mail_task() after reading main.cf. */
+ msg_syslog_init(mail_task("postqueue"), LOG_PID, LOG_FACILITY);
mail_dict_init(); /* proxy, sql, ldap */
get_mail_conf_str_table(str_table);
* configuration directory location.
*/
mail_conf_read();
- if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
- msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
+ /* Re-evaluate mail_task() after reading main.cf. */
+ msg_syslog_init(mail_task(argv[0]), LOG_PID, LOG_FACILITY);
if (chdir(var_queue_dir))
msg_fatal("chdir %s: %m", var_queue_dir);
}
optind = saved_optind;
mail_conf_read();
- if (strcmp(var_syslog_name, DEF_SYSLOG_NAME) != 0)
- msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY);
+ /* Re-evaluate mail_task() after reading main.cf. */
+ msg_syslog_init(mail_task("sendmail"), LOG_PID, LOG_FACILITY);
get_mail_conf_str_table(str_table);
if (chdir(var_queue_dir))
if (got_login)
saved_username = mystrdup(state->sasl_username);
smtpd_sasl_deactivate(state);
- if (state->tls_context == 0) /* TLS from XCLIENT proxy? */
- smtpd_sasl_activate(state, VAR_SMTPD_SASL_OPTS,
- var_smtpd_sasl_opts);
- else
+#ifdef USE_TLS
+ if (state->tls_context != 0) /* TLS from XCLIENT proxy? */
smtpd_sasl_activate(state, VAR_SMTPD_SASL_TLS_OPTS,
var_smtpd_sasl_tls_opts);
+ else
+#endif
+ smtpd_sasl_activate(state, VAR_SMTPD_SASL_OPTS,
+ var_smtpd_sasl_opts);
if (got_login) {
smtpd_sasl_auth_extern(state, saved_username, XCLIENT_CMD);
myfree(saved_username);
/*
/* int allascii(buffer)
/* const char *buffer;
+/*
+/* int allascii_len(buffer len)
+/* const char *buffer;
+/* ssize_t len;
/* DESCRIPTION
/* allascii() determines if its argument is an all-ASCII string.
/*
/* Arguments:
/* .IP buffer
/* The null-terminated input string.
+/* .IP len
+/* The string length, -1 to determine the length dynamically.
/* LICENSE
/* .ad
/* .fi
#include "stringops.h"
-/* allascii - return true if string is all ASCII */
+/* allascii_len - return true if string is all ASCII */
-int allascii(const char *string)
+int allascii_len(const char *string, ssize_t len)
{
const char *cp;
int ch;
- if (*string == 0)
+ if (len < 0)
+ len = strlen(string);
+ if (len == 0)
return (0);
- for (cp = string; (ch = *(unsigned char *) cp) != 0; cp++)
+ for (cp = string; cp < string + len
+ && (ch = *(unsigned char *) cp) != 0; cp++)
if (!ISASCII(ch))
return (0);
return (1);
/* .IP dest
/* Output buffer, null-terminated. Specify a null pointer to
/* use an internal buffer that is overwritten upon each call.
-/* .IP len
+/* .IP src_len
/* The string length, -1 to determine the length dynamically.
/* .IP flags
/* Bitwise OR of zero or more of the following:
/*
* Short-circuit optimization for ASCII-only text. This may be slower
* than using a cache for all results. See comments above for limitations
- * of strcasecmp(). XXX We could avoid the vstring_strncpy() if
- * allascii() had a length argument.
+ * of strcasecmp().
*/
- vstring_strncpy(f1, s1, len);
- vstring_strncpy(f2, s2, len);
- if (allascii(STR(f1)) && allascii(STR(f2)))
- return (strncasecmp(STR(f1), STR(f2), len));
+ if (allascii_len(s1, len) && allascii_len(s2, len))
+ return (strncasecmp(s1, s2, len));
/*
* Caution: casefolding may change the number of bytes. See comments
compare HeLlO hellp
compare hellp HeLlO
compare-len HeLlO hellp 4
+compare-len HeLO help 4
compare abcde abcdf
compare YYY\80\80\80XXX yyy\80\80\80xxx
"hellp" > "HeLlO"
> compare-len HeLlO hellp 4
"HeLl" == "hell"
+> compare-len HeLO help 4
+"HeLO" < "help"
> compare abcde abcdf
"abcde" < "abcdf"
> compare YYY\80\80\80XXX yyy\80\80\80xxx
extern int alldig(const char *);
extern int allprint(const char *);
extern int allspace(const char *);
-extern int allascii(const char *);
+extern int allascii_len(const char *, ssize_t);
extern const char *split_nameval(char *, char **, char **);
extern int valid_utf8_string(const char *, ssize_t);
extern size_t balpar(const char *, const char *);
/*
* Convenience wrappers for most-common use cases.
*/
+#define allascii(s) allascii_len((s), -1)
#define casefold(dst, src) \
casefoldx(util_utf8_enable ? CASEF_FLAG_UTF8 : 0, (dst), (src), -1)
#define casefold_len(dst, src, len) \