20011008
Bugfix: there was a minute memory leak when an smtpd access
- restriction is misconfigured. File: smtpd/smtpd_check.c.
+ restriction was misconfigured. File: smtpd/smtpd_check.c.
20011010
- Postfix daemons now print the name of the UNIX-domain socket
- (instead of "unknown stream") complaining about a malformed
- client request. Files: master/*server.c.
+ Code cleanup: Postfix daemons now print the name of the
+ UNIX-domain socket (instead of "unknown stream") in case
+ of a malformed client request. Files: master/*server.c.
20011010-14
- Replaced the ugly mail_print() and mail-scan() protocols
- by (name,value) attribute lists. This gives better error
- detection when we start making changes to internal protocols,
+ Code cleanup: replaced the ugly mail_print() and mail-scan()
+ protocols by (name,value) attribute lists. This gives better
+ error detection when we make changes to internal protocols,
and allows new attributes to be introduced without breaking
- everything immediately.
+ everything immediately. Files: util/attr_print.c util/attr_scan.c
+ global/mail_command_server.c global/mail_command_client.c
+ as wel as most Postfix applications and daemons.
20011015
Put base 64 encoding into place on the replaced internal
protocols. Files: util/base64_code.[hc].
- Feature: header/body REJECT rules can now end in text that
+ Feature: header/body REJECT rules can now provide text that
is sent to the originator. Files: cleanup/cleanup.c,
cleanup/cleanup_message.c, conf/sample-filter.cf.
util/attr_scan.c.
Bugfix: qmqpd could read past the end of a string while
- looking for the VERP magic token in the envelope sender
+ looking for qmail's VERP magic token in the envelope sender
address. File: qmqpd/qmqpd.c.
-Open problems:
+ Code cleanup: finished testing the new internal protocols.
+ The only bug was with the flush server, which still needs
+ to support the old (string + null byte) protocol for triggers
+ from the Postfix master daemon.
- Medium: need in-process caching for map lookups.
+20011103
- Low: The $process_id_directory setting is not used anywhere
- in Postfix. Problem reported by Michael Smith, texas.net.
- This should either be documented, or better, the code should
- warn about attempts to set a read-only parameter.
+ Bugfix: Postfix would log the wrong error text when locally
+ submitted mail was deferred due to "soft_bounce = yes".
+
+ Bugfix: The LDAP client dropped any entries that don't have
+ the result_attribute, but errored out when a DN didn't
+ exist. The behavior is now consistent: treat non-existant
+ DN's in a special result attribute expansion the same as
+ DN's with no attribtue. LaMont Jones, HP.
+
+Open problems:
+
+ Medium: need in-process caching for map lookups. LDAP
+ servers seem to need this in particular.
Medium: make address rewriting on/off configurable for
envelopes and/or headers.
Medium: smtpd access maps don't understand the recipient
delimiter setting.
+ Low: The $process_id_directory setting is not used anywhere
+ in Postfix. Problem reported by Michael Smith, texas.net.
+ This should be documented, or better, the code should warn
+ about attempts to set read-only parameters.
+
Low: the virtual delivery agent needs a way to specify
fixed uid/gid for all deliveries.
+
+ Low: postconf -e edits parameters that postconf won't list.
-This release introduces a negligible amount of features and is all
-about revision of Postfix internals. With more than 70 pages of
-context diffs compared to the previous snapshot, this release is
-a baseline for upcoming feature changes.
+Snapshot 20011103 introduces a negligible amount of features and
+is all about revision of Postfix internals. With more than 70 pages
+of context diffs compared to the previous snapshot, this release
+is a baseline for upcoming feature changes.
-Major changes with snapshot-20011102
+Major changes with snapshot-20011103
====================================
The protocol between Postfix daemons was replaced by something that
of the protocols is described in src/util/attr_scan.c.
In header/body_check files, REJECT can now be followed by text that
-is sent to the originator. That feature was stuck waiting for the
-internal protocol revision.
+is sent to the originator. That feature was stuck waiting for years,
+pending the internal protocol revision.
Incompatible changes with snapshot-20011008
===========================================
catch up and access the disk, while still allowing new mail to
arrive.
-This feature is disabled by default, because it needs further
-development. It will change but I have not enough time now.
+This feature is on by default, but currently it has effect only
+when mail arrives via a relatively small number of SMTP clients.
+The code needs further development. It will change but I have not
+enough time now.
The in_flow_delay feature has effect mainly when your system is
being flooded through a limited number of SMTP connections. This
RANLIB=echo
SYSLIBS="-lresolv -lsocket -lnsl"
;;
-Rhapsody.5*|Darwin.1.*)
+Rhapsody.5*|Darwin.*)
SYSTYPE=RHAPSODY5
# Use the native compiler by default
: ${CC=cc}
AWK=gawk
+ case $RELEASE in
+ 1.[0-3]) ;;
+ *) AWK=awk
+ SYSLIBS=-flat_namespace
+ ;;
+ esac
;;
"Mac OS".10*) SYSTYPE=MACOSX
# Use the native compiler by default
state->queue_id, state->sender) == 0) {
state->errs = 0;
} else {
- if (var_soft_bounce == 0)
+ if (var_soft_bounce == 0) {
msg_warn("%s: bounce message failure", state->queue_id);
- state->errs = CLEANUP_STAT_WRITE;
+ state->errs = CLEANUP_STAT_WRITE;
+ }
}
}
if (REMOVE(cleanup_path))
return (FLUSH_STAT_OK);
}
+/* flush_request_receive - receive request */
+
+static int flush_request_receive(VSTREAM *client_stream, VSTRING *request)
+{
+ int count;
+
+ /*
+ * Kluge: choose the protocol depending on the request size.
+ */
+ if (read_wait(vstream_fileno(client_stream), var_ipc_timeout) < 0) {
+ msg_warn("timeout while waiting for data from %s",
+ VSTREAM_PATH(client_stream));
+ return (-1);
+ }
+ if ((count = peekfd(vstream_fileno(client_stream))) < 0) {
+ msg_warn("cannot examine read buffer of %s: %m",
+ VSTREAM_PATH(client_stream));
+ return (-1);
+ }
+
+ /*
+ * Short request: master trigger. Use the string+null protocol.
+ */
+ if (count <= 2) {
+ if (vstring_get_null(request, client_stream) == VSTREAM_EOF) {
+ msg_warn("end-of-input while reading request from %s: %m",
+ VSTREAM_PATH(client_stream));
+ return (-1);
+ }
+ }
+
+ /*
+ * Long request: real flush client. Use the attribute list protocol.
+ */
+ else {
+ if (attr_scan(client_stream,
+ ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
+ ATTR_TYPE_STR, MAIL_ATTR_REQ, request,
+ ATTR_TYPE_END) != 1) {
+ return (-1);
+ }
+ }
+ return (0);
+}
+
/* flush_service - perform service for client */
static void flush_service(VSTREAM *client_stream, char *unused_service,
* All connection-management stuff is handled by the common code in
* single_server.c.
*/
- if (peekfd(vstream_fileno(client_stream)) <= 2 ?
- (vstring_get_null(request, client_stream) != VSTREAM_EOF) :
- (attr_scan(client_stream,
- ATTR_FLAG_MORE | ATTR_FLAG_STRICT,
- ATTR_TYPE_STR, MAIL_ATTR_REQ, request,
- ATTR_TYPE_END) == 1)) {
+ if (flush_request_receive(client_stream, request) == 0) {
if (STREQ(STR(request), FLUSH_REQ_ADD)) {
site = vstring_alloc(10);
queue_id = vstring_alloc(10);
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
-#define DEF_MAIL_VERSION "Snapshot-20011102"
+#define DEF_MAIL_VERSION "Snapshot-20011103"
extern char *var_mail_version;
/* LICENSE
/* .in
/*
/* All attribute names and attribute values are sent as base64-encoded
-/* strings. Each base64-encoded must be no longer than 2*var_line_limit
+/* strings. Each base64 encoding must be no longer than 2*var_line_limit
/* characters. The formatting rules aim to make implementations in PERL
/* and other languages easy.
/*
/* This argument is followed by an attribute name and a VSTRING pointer.
/* .IP "ATTR_TYPE_HASH (HTABLE *)"
/* All further input attributes are processed as string attributes.
-/* In this case, no specific attribute sequence is enforced.
+/* No specific attribute sequence is enforced.
+/* All attributes up to the attribute list terminator are read,
+/* but only the first instance of each attribute is stored.
/* .sp
/* The attribute string values are stored in the hash table under
/* keys equal to the attribute name (obtained from the input stream).
/* This argument terminates the requested attribute list.
/* .RE
/* BUGS
-/* ATTR_TYPE_HASH accepts attributes with arbitrary names from an
-/* untrusted source. This is safe only if the resulting table is
+/* ATTR_TYPE_HASH accepts attributes with arbitrary names from possibly
+/* untrusted sources. This is unsafe, unless the resulting table is
/* queried only with known to be good attribute names.
/* DIAGNOSTICS
/* attr_scan() and attr_vscan() return -1 when malformed input is
/* detected (string too long, incomplete line, missing end marker).
-/* Otherwise, the result value is the number of attributes that were
-/* successfully recovered from the input stream (a hash table counts
+/* Otherwise, the result value is the number of attributes that were
+/* successfully recovered from the input stream (a hash table counts
/* as the number of entries stored into the table).
/*
/* Panic: interface violation. All system call errors are fatal.
if ((ch = attr_scan_string(fp, str_buf, context)) < 0)
return (-1);
if (sscanf(STR(str_buf), "%u%c", ptr, &junk) != 1 || junk != 0) {
- msg_warn("malformed numerical data from %s while %s: %.100s",
+ msg_warn("malformed numerical data from %s while reading %s: %.100s",
VSTREAM_PATH(fp), context, STR(str_buf));
return (-1);
}
if (wanted_type == ATTR_TYPE_END) {
if ((flags & ATTR_FLAG_MORE) != 0)
return (conversions);
- wanted_name = "list terminator";
+ wanted_name = "(list terminator)";
} else if (wanted_type == ATTR_TYPE_HASH) {
wanted_name = "(any attribute name or list terminator)";
hash_table = va_arg(ap, HTABLE *);
return (-1);
}
string = va_arg(ap, VSTRING *);
- if ((ch = attr_scan_string(fp, string,
- "input attribute value")) < 0)
+ if ((ch = attr_scan_string(fp, string,
+ "input attribute value")) < 0)
return (-1);
if (ch != '\n') {
msg_warn("multiple values for attribute %s from %s",
STR(name_buf), VSTREAM_PATH(fp));
return (-1);
}
- if ((ch = attr_scan_string(fp, str_buf,
-"input attribute value")) < 0)
+ if ((ch = attr_scan_string(fp, str_buf,
+ "input attribute value")) < 0)
return (-1);
if (ch != '\n') {
msg_warn("multiple values for attribute %s from %s",
./attr_scan: input attribute value: 4711
./attr_scan: unknown_stream: wanted attribute: string
./attr_scan: input attribute name: string
-./attr_scan: attribute value: whoopee
+./attr_scan: input attribute value: whoopee
./attr_scan: unknown_stream: wanted attribute: (any attribute name or list terminator)
./attr_scan: input attribute name: foo-name
-./attr_scan: attribute value: foo-value
+./attr_scan: input attribute value: foo-value
./attr_scan: unknown_stream: wanted attribute: (any attribute name or list terminator)
./attr_scan: input attribute name: bar-name
-./attr_scan: attribute value: bar-value
+./attr_scan: input attribute value: bar-value
./attr_scan: unknown_stream: wanted attribute: (any attribute name or list terminator)
./attr_scan: input attribute name: (end)
./attr_scan: unknown_stream: wanted attribute: number
./attr_scan: input attribute value: 4711
./attr_scan: unknown_stream: wanted attribute: string
./attr_scan: input attribute name: string
-./attr_scan: attribute value: whoopee
-./attr_scan: unknown_stream: wanted attribute: list terminator
+./attr_scan: input attribute value: whoopee
+./attr_scan: unknown_stream: wanted attribute: (list terminator)
./attr_scan: input attribute name: (end)
number 4711
string whoopee
VSTRING *base64_decode(VSTRING *result, const char *in, int len)
{
- static char *un_b64 = 0;
+ static unsigned char *un_b64 = 0;
const unsigned char *cp;
int count;
int ch0;
* Once: initialize the decoding lookup table on the fly.
*/
if (un_b64 == 0) {
- un_b64 = mymalloc(CHARS_PER_BYTE);
+ un_b64 = (unsigned char *) mymalloc(CHARS_PER_BYTE);
memset(un_b64, INVALID, CHARS_PER_BYTE);
for (cp = to_b64; cp < to_b64 + sizeof(to_b64); cp++)
un_b64[*cp] = cp - to_b64;
dict_ldap->result_attributes->argv,
0, &tv, &resloop);
}
- if (rc == LDAP_SUCCESS)
- dict_ldap_get_values(dict_ldap, resloop, result);
- else {
- msg_warn("%s: search error %d: %s ", myname, rc,
+ switch (rc) {
+ case LDAP_SUCCESS:
+ dict_ldap_get_values(dict_ldap, resloop, result);
+ break;
+ case LDAP_NO_SUCH_OBJECT:
+ /* Go ahead and treat this as though the DN existed
+ * and just didn't have any result attributes.
+ */
+ msg_warn("%s: DN %s not found, skipping ", myname,
+ vals[i]);
+ break;
+ default:
+ msg_warn("%s: search error %d: %s ", myname, rc,
ldap_err2string(rc));
- dict_errno = DICT_ERR_RETRY;
+ dict_errno = DICT_ERR_RETRY;
+ break;
}
+
if (resloop != 0)
ldap_msgfree(resloop);
}