diff --git a/postfix/HISTORY b/postfix/HISTORY index fc09adcf0..a7d0460eb 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -10931,8 +10931,34 @@ Apologies for any names omitted. util/attr_print0.c, global/dsb_scan.c, global/dsn_print.c, global/rcpt_buf,c global/rcpt_print.c, global/deliver_pass.c. + Added delegated attribute scan/print function support to + the base64 and plain attribute I/O encodings. Files: + util/attr_scan_plain.c util/attr_print_plain.c. + +20040624 + + Added "." to the list commands that smtp-sink can "break" + (by disconnecting, or by responding with a 4XX or 5XX reply + code). File: smtpstone/smtp-sink.c. + +20040625 + + Safety: allow only 4.x.x and 5.x.x enhanced status codes + in header/body_checks REJECT actions. File: + cleanup/cleanup_message.c. + +20050627 + + Code cleanup: generalized the smtp-sink code that simulates + server errors. File: smtpstone/smtp-sink.c. + Open problems: + Look for systems with XPG basename() declared in , + and prepare for phasing out the Postfix-supplied one. + Beware, however, that XPG basename() takes (char *), and + not (const char *) because it may change its argument. + Laptop friendliness: make the qmgr remember when the next deferred queue scan needs to be done, and have the pickup server stat() the maildrop directory before searching it. diff --git a/postfix/html/lmtp.8.html b/postfix/html/lmtp.8.html index df7235987..1802920c3 100644 --- a/postfix/html/lmtp.8.html +++ b/postfix/html/lmtp.8.html @@ -281,11 +281,16 @@ LMTP(8) LMTP(8) P.O. Box 704 Yorktown Heights, NY 10598, USA - Alterations for LMTP by: + Modifications for LMTP by: Philip A. Prindeville Mirapoint, Inc. USA. + SASL support originally by: + Till Franke + SuSE Rhein/Main AG + 65760 Eschborn, Germany + Additional work on LMTP by: Amos Gouaux University of Texas at Dallas diff --git a/postfix/html/postconf.5.html b/postfix/html/postconf.5.html index 626d09d2e..9e280791a 100644 --- a/postfix/html/postconf.5.html +++ b/postfix/html/postconf.5.html @@ -6206,7 +6206,7 @@ The default time unit is s (seconds).

The maximal number of MX (mail exchanger) IP addresses that can result from mail exchanger lookups, or zero (no limit). Prior to -Postfix 2.3, this limit was disabled. +Postfix 2.3, this limit was disabled by default.

diff --git a/postfix/html/smtp-sink.1.html b/postfix/html/smtp-sink.1.html index e773ad591..6110c8065 100644 --- a/postfix/html/smtp-sink.1.html +++ b/postfix/html/smtp-sink.1.html @@ -50,6 +50,12 @@ SMTP-SINK(1) SMTP-SINK(1) Reject the specified commands with a hard (5xx) error code. This option implies -p. + Examples of commands are HELO, EHLO, LHLO, MAIL, + RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate + command names by white space or commas, and use + quotes to protect white space from the shell. Com- + mand names are case-insensitive. + -F Disable XFORWARD support. -h hostname @@ -73,21 +79,34 @@ SMTP-SINK(1) SMTP-SINK(1) Disconnect (without replying) after receiving one of the specified commands. - -r command,command,... - Reject the specified commands with a soft (4xx) - error code. This option implies -p. - - -s command,command,... - Log the named commands to syslogd. Examples of - commands that can be logged are HELO, EHLO, LHLO, - MAIL, RCPT, VRFY, RSET, NOOP, and QUIT. Separate + Examples of commands are HELO, EHLO, LHLO, MAIL, + RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate command names by white space or commas, and use quotes to protect white space from the shell. Com- mand names are case-insensitive. + -r command,command,... + Reject the specified commands with a soft (4xx) + error code. This option implies -p. + + Examples of commands are HELO, EHLO, LHLO, MAIL, + RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate + command names by white space or commas, and use + quotes to protect white space from the shell. Com- + mand names are case-insensitive. + + -s command,command,... + Log the named commands to syslogd. + + Examples of commands are HELO, EHLO, LHLO, MAIL, + RCPT, VRFY, DATA, ., RSET, NOOP, and QUIT. Separate + command names by white space or commas, and use + quotes to protect white space from the shell. Com- + mand names are case-insensitive. + -t timeout (default: 100) Limit the time for receiving a command or sending a - response. The time limit is specified in seconds. + response. The time limit is specified in seconds. -v Show the SMTP conversations. @@ -96,7 +115,7 @@ SMTP-SINK(1) SMTP-SINK(1) mand. [inet:][host]:port - Listen on network interface host (default: any + Listen on network interface host (default: any interface) TCP port port. Both host and port may be specified in numeric or symbolic form. @@ -104,14 +123,14 @@ SMTP-SINK(1) SMTP-SINK(1) Listen on the UNIX-domain socket at pathname. backlog - The maximum length the queue of pending connec- + The maximum length the queue of pending connec- tions, as defined by the listen(2) system call. SEE ALSO smtp-source(1), SMTP/LMTP message generator LICENSE - The Secure Mailer license must be distributed with this + The Secure Mailer license must be distributed with this software. AUTHOR(S) diff --git a/postfix/html/smtp.8.html b/postfix/html/smtp.8.html index be81081f0..4b1d90606 100644 --- a/postfix/html/smtp.8.html +++ b/postfix/html/smtp.8.html @@ -523,6 +523,11 @@ SMTP(8) SMTP(8) Coventry, CV1 4LY, United Kingdom. + SASL support originally by: + Till Franke + SuSE Rhein/Main AG + 65760 Eschborn, Germany + Connection caching in cooperation with: Victor Duchovni Morgan Stanley diff --git a/postfix/html/smtpd.8.html b/postfix/html/smtpd.8.html index 433712dbe..37208aa0a 100644 --- a/postfix/html/smtpd.8.html +++ b/postfix/html/smtpd.8.html @@ -962,6 +962,11 @@ SMTPD(8) SMTPD(8) P.O. Box 704 Yorktown Heights, NY 10598, USA + SASL support originally by: + Till Franke + SuSE Rhein/Main AG + 65760 Eschborn, Germany + TLS support originally by: Lutz Jaenicke BTU Cottbus diff --git a/postfix/man/man1/smtp-sink.1 b/postfix/man/man1/smtp-sink.1 index ddbd2812f..77cd22c5e 100644 --- a/postfix/man/man1/smtp-sink.1 +++ b/postfix/man/man1/smtp-sink.1 @@ -49,6 +49,11 @@ Do not announce ENHANCEDSTATUSCODES support. .IP "\fB-f \fIcommand,command,...\fR" Reject the specified commands with a hard (5xx) error code. This option implies \fB-p\fR. +.sp +Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY, +DATA, ., RSET, NOOP, and QUIT. Separate command names by +white space or commas, and use quotes to protect white space +from the shell. Command names are case-insensitive. .IP \fB-F\fR Disable XFORWARD support. .IP "\fB-h\fI hostname\fR" @@ -66,15 +71,26 @@ a CISCO PIX system. Implies \fB-e\fR. .IP "\fB-q \fIcommand,command,...\fR" Disconnect (without replying) after receiving one of the specified commands. +.sp +Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY, +DATA, ., RSET, NOOP, and QUIT. Separate command names by +white space or commas, and use quotes to protect white space +from the shell. Command names are case-insensitive. .IP "\fB-r \fIcommand,command,...\fR" Reject the specified commands with a soft (4xx) error code. This option implies \fB-p\fR. +.sp +Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY, +DATA, ., RSET, NOOP, and QUIT. Separate command names by +white space or commas, and use quotes to protect white space +from the shell. Command names are case-insensitive. .IP "\fB-s \fIcommand,command,...\fR" Log the named commands to syslogd. -Examples of commands that can be logged are HELO, EHLO, LHLO, MAIL, -RCPT, VRFY, RSET, NOOP, and QUIT. Separate command names by white -space or commas, and use quotes to protect white space from the -shell. Command names are case-insensitive. +.sp +Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY, +DATA, ., RSET, NOOP, and QUIT. Separate command names by +white space or commas, and use quotes to protect white space +from the shell. Command names are case-insensitive. .IP "\fB-t \fItimeout\fR (default: 100)" Limit the time for receiving a command or sending a response. The time limit is specified in seconds. diff --git a/postfix/man/man5/postconf.5 b/postfix/man/man5/postconf.5 index c0fe6d3bf..9f144a0cf 100644 --- a/postfix/man/man5/postconf.5 +++ b/postfix/man/man5/postconf.5 @@ -3437,7 +3437,7 @@ The default time unit is s (seconds). .SH smtp_mx_address_limit (default: 5) The maximal number of MX (mail exchanger) IP addresses that can result from mail exchanger lookups, or zero (no limit). Prior to -Postfix 2.3, this limit was disabled. +Postfix 2.3, this limit was disabled by default. .PP This feature is available in Postfix 2.1 and later. .SH smtp_mx_session_limit (default: 2) diff --git a/postfix/man/man8/lmtp.8 b/postfix/man/man8/lmtp.8 index 3874e254c..8f2202039 100644 --- a/postfix/man/man8/lmtp.8 +++ b/postfix/man/man8/lmtp.8 @@ -259,11 +259,16 @@ IBM T.J. Watson Research P.O. Box 704 Yorktown Heights, NY 10598, USA -Alterations for LMTP by: +Modifications for LMTP by: Philip A. Prindeville Mirapoint, Inc. USA. +SASL support originally by: +Till Franke +SuSE Rhein/Main AG +65760 Eschborn, Germany + Additional work on LMTP by: Amos Gouaux University of Texas at Dallas diff --git a/postfix/man/man8/smtp.8 b/postfix/man/man8/smtp.8 index 29f41ca17..9459f0e7d 100644 --- a/postfix/man/man8/smtp.8 +++ b/postfix/man/man8/smtp.8 @@ -429,6 +429,11 @@ Canal Basin, Coventry, CV1 4LY, United Kingdom. +SASL support originally by: +Till Franke +SuSE Rhein/Main AG +65760 Eschborn, Germany + Connection caching in cooperation with: Victor Duchovni Morgan Stanley diff --git a/postfix/man/man8/smtpd.8 b/postfix/man/man8/smtpd.8 index 4c4121318..a07f82035 100644 --- a/postfix/man/man8/smtpd.8 +++ b/postfix/man/man8/smtpd.8 @@ -779,6 +779,11 @@ IBM T.J. Watson Research P.O. Box 704 Yorktown Heights, NY 10598, USA +SASL support originally by: +Till Franke +SuSE Rhein/Main AG +65760 Eschborn, Germany + TLS support originally by: Lutz Jaenicke BTU Cottbus diff --git a/postfix/proto/postconf.proto b/postfix/proto/postconf.proto index ffdc3f8db..16bc0f1c2 100644 --- a/postfix/proto/postconf.proto +++ b/postfix/proto/postconf.proto @@ -3829,7 +3829,7 @@ The default time unit is s (seconds).

The maximal number of MX (mail exchanger) IP addresses that can result from mail exchanger lookups, or zero (no limit). Prior to -Postfix 2.3, this limit was disabled. +Postfix 2.3, this limit was disabled by default.

diff --git a/postfix/src/cleanup/cleanup_message.c b/postfix/src/cleanup/cleanup_message.c index f8524f749..127870f0f 100644 --- a/postfix/src/cleanup/cleanup_message.c +++ b/postfix/src/cleanup/cleanup_message.c @@ -315,6 +315,11 @@ static const char *cleanup_act(CLEANUP_STATE *state, char *context, if (state->reason == 0) { if (*optional_text) { state->reason = dsn_prepend("5.7.1", optional_text); + if (*state->reason != '4' && *state->reason != '5') { + msg_warn("bad DSN action in %s -- need 4.x.x or 5.x.x", + optional_text); + *state->reason = '4'; + } } else { detail = cleanup_stat_detail(CLEANUP_STAT_CONT); state->reason = dsn_prepend(detail->dsn, detail->text); diff --git a/postfix/src/global/mail_version.h b/postfix/src/global/mail_version.h index 0993eae72..b9c6453ab 100644 --- a/postfix/src/global/mail_version.h +++ b/postfix/src/global/mail_version.h @@ -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 "20050623" +#define MAIL_RELEASE_DATE "20050627" #define MAIL_VERSION_NUMBER "2.3" #define VAR_MAIL_VERSION "mail_version" diff --git a/postfix/src/lmtp/lmtp.c b/postfix/src/lmtp/lmtp.c index 16712c879..f095c8a6d 100644 --- a/postfix/src/lmtp/lmtp.c +++ b/postfix/src/lmtp/lmtp.c @@ -225,11 +225,16 @@ /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /* -/* Alterations for LMTP by: +/* Modifications for LMTP by: /* Philip A. Prindeville /* Mirapoint, Inc. /* USA. /* +/* SASL support originally by: +/* Till Franke +/* SuSE Rhein/Main AG +/* 65760 Eschborn, Germany +/* /* Additional work on LMTP by: /* Amos Gouaux /* University of Texas at Dallas diff --git a/postfix/src/smtp/smtp.c b/postfix/src/smtp/smtp.c index 5f7693092..c2944f737 100644 --- a/postfix/src/smtp/smtp.c +++ b/postfix/src/smtp/smtp.c @@ -389,6 +389,11 @@ /* Coventry, /* CV1 4LY, United Kingdom. /* +/* SASL support originally by: +/* Till Franke +/* SuSE Rhein/Main AG +/* 65760 Eschborn, Germany +/* /* Connection caching in cooperation with: /* Victor Duchovni /* Morgan Stanley diff --git a/postfix/src/smtp/smtp_session.c b/postfix/src/smtp/smtp_session.c index 993f342cc..f9d338708 100644 --- a/postfix/src/smtp/smtp_session.c +++ b/postfix/src/smtp/smtp_session.c @@ -355,7 +355,7 @@ int smtp_session_passivate(SMTP_SESSION *session, VSTRING *dest_prop, /* * Append the passivated SASL attributes. */ -#ifdef USE_SASL +#ifdef notdef if (smtp_sasl_enable) smtp_sasl_passivate(endp_prop, session); #endif @@ -460,7 +460,7 @@ SMTP_SESSION *smtp_session_activate(int fd, VSTRING *dest_prop, /* * Re-activate the SASL attributes. */ -#ifdef USE_SASL +#ifdef notdef if (smtp_sasl_enable && smtp_sasl_activate(session, endp_props) < 0) { vstream_fdclose(session->stream); session->stream = 0; diff --git a/postfix/src/smtpd/smtpd.c b/postfix/src/smtpd/smtpd.c index e52224fb5..772509932 100644 --- a/postfix/src/smtpd/smtpd.c +++ b/postfix/src/smtpd/smtpd.c @@ -721,6 +721,11 @@ /* P.O. Box 704 /* Yorktown Heights, NY 10598, USA /* +/* SASL support originally by: +/* Till Franke +/* SuSE Rhein/Main AG +/* 65760 Eschborn, Germany +/* /* TLS support originally by: /* Lutz Jaenicke /* BTU Cottbus @@ -1435,8 +1440,12 @@ static int extract_addr(SMTPD_STATE *state, SMTPD_TOKEN *arg, } /* - * Report trouble. Log a warning only if we are going to sleep+reject so - * that attackers can't flood our logfiles. + * Report trouble. XXX Should log a warning only if we are going to + * sleep+reject so that attackers can't flood our logfiles. + * + * XXX Unfortunately, the sleep-before-reject feature had to be abandoned + * (at least for small error counts) because servers were DOS-ing + * themselves when flooded by backscatter traffic. */ if (naddr > 1 || (strict_rfc821 && (non_addr || *STR(arg->vstrval) != '<'))) { @@ -1503,8 +1512,7 @@ static int mail_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) * XXX 2821 pedantism: Section 4.1.2 says that SMTP servers that receive a * command in which invalid character codes have been employed, and for * which there are no other reasons for rejection, MUST reject that - * command with a 501 response. So much for the principle of "be liberal - * in what you accept, be strict in what you send". + * command with a 501 response. Postfix attempts to be 8-bit clean. */ if (var_helo_required && state->helo_name == 0) { state->error_mask |= MAIL_ERROR_POLICY; @@ -2448,6 +2456,7 @@ static int vrfy_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) smtpd_chat_reply(state, "501 5.1.3 Bad recipient address syntax"); return (-1); } + /* Not: state->addr_buf */ if (SMTPD_STAND_ALONE(state) == 0 && (err = smtpd_check_rcpt(state, argv[1].strval)) != 0) { smtpd_chat_reply(state, "%s", err); @@ -2555,8 +2564,11 @@ static int quit_cmd(SMTPD_STATE *state, int unused_argc, SMTPD_TOKEN *unused_arg * When the "." and quit replies are pipelined, make sure they are * flushed now, to avoid repeated mail deliveries in case of a crash in * the "clean up before disconnect" code. + * + * XXX When this was added in Postfix 2.1 we used vstream_fflush(). As of + * Postfix 2.3 we use smtp_flush() for better error reporting. */ - vstream_fflush(state->client); + smtp_flush(state->client); return (0); } @@ -2945,7 +2957,7 @@ static void chat_reset(SMTPD_STATE *state, int threshold) #ifdef USE_TLS -/* smtpd_start_tls -turn on TLS or force disconnect */ +/* smtpd_start_tls - turn on TLS or force disconnect */ static void smtpd_start_tls(SMTPD_STATE *state) { @@ -2961,10 +2973,10 @@ static void smtpd_start_tls(SMTPD_STATE *state) * verification unless TLS is required. */ state->tls_context = - tls_server_start(smtpd_tls_ctx, state->client, - var_smtpd_starttls_tmout, - state->name, state->addr, &(state->tls_info), - (var_smtpd_tls_req_ccert && state->tls_enforce_tls)); + tls_server_start(smtpd_tls_ctx, state->client, + var_smtpd_starttls_tmout, + state->name, state->addr, &(state->tls_info), + (var_smtpd_tls_req_ccert && state->tls_enforce_tls)); /* * When the TLS handshake fails, the conversation is in an unknown state. @@ -3493,12 +3505,13 @@ static void post_jail_init(char *unused_name, char **unused_argv) * recipient checks, address mapping, header_body_checks?. */ smtpd_input_transp_mask = - input_transp_mask(VAR_INPUT_TRANSP, var_input_transp); + input_transp_mask(VAR_INPUT_TRANSP, var_input_transp); /* * Sanity checks. The queue_minfree value should be at least as large as * (process_limit * message_size_limit) but that is unpractical, so we - * arbitrarily pick a number and require twice the message size limit. + * arbitrarily pick a small multiple of the per-message size limit. This + * helps to avoid many unneeded (re)transmissions. */ if (var_queue_minfree > 0 && var_message_limit > 0 diff --git a/postfix/src/smtpstone/smtp-sink.c b/postfix/src/smtpstone/smtp-sink.c index 4a6c3d7cd..a497885c1 100644 --- a/postfix/src/smtpstone/smtp-sink.c +++ b/postfix/src/smtpstone/smtp-sink.c @@ -43,6 +43,11 @@ /* .IP "\fB-f \fIcommand,command,...\fR" /* Reject the specified commands with a hard (5xx) error code. /* This option implies \fB-p\fR. +/* .sp +/* Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY, +/* DATA, ., RSET, NOOP, and QUIT. Separate command names by +/* white space or commas, and use quotes to protect white space +/* from the shell. Command names are case-insensitive. /* .IP \fB-F\fR /* Disable XFORWARD support. /* .IP "\fB-h\fI hostname\fR" @@ -60,15 +65,26 @@ /* .IP "\fB-q \fIcommand,command,...\fR" /* Disconnect (without replying) after receiving one of the /* specified commands. +/* .sp +/* Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY, +/* DATA, ., RSET, NOOP, and QUIT. Separate command names by +/* white space or commas, and use quotes to protect white space +/* from the shell. Command names are case-insensitive. /* .IP "\fB-r \fIcommand,command,...\fR" /* Reject the specified commands with a soft (4xx) error code. /* This option implies \fB-p\fR. +/* .sp +/* Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY, +/* DATA, ., RSET, NOOP, and QUIT. Separate command names by +/* white space or commas, and use quotes to protect white space +/* from the shell. Command names are case-insensitive. /* .IP "\fB-s \fIcommand,command,...\fR" /* Log the named commands to syslogd. -/* Examples of commands that can be logged are HELO, EHLO, LHLO, MAIL, -/* RCPT, VRFY, RSET, NOOP, and QUIT. Separate command names by white -/* space or commas, and use quotes to protect white space from the -/* shell. Command names are case-insensitive. +/* .sp +/* Examples of commands are HELO, EHLO, LHLO, MAIL, RCPT, VRFY, +/* DATA, ., RSET, NOOP, and QUIT. Separate command names by +/* white space or commas, and use quotes to protect white space +/* from the shell. Command names are case-insensitive. /* .IP "\fB-t \fItimeout\fR (default: 100)" /* Limit the time for receiving a command or sending a response. /* The time limit is specified in seconds. @@ -141,6 +157,7 @@ typedef struct SINK_STATE { int data_state; int (*read_fn) (struct SINK_STATE *); int rcpts; + char *push_back_ptr; } SINK_STATE; #define ST_ANY 0 @@ -150,6 +167,10 @@ typedef struct SINK_STATE { #define ST_CR_LF_DOT_CR 4 #define ST_CR_LF_DOT_CR_LF 5 +#define PUSH_BACK_PEEK(state) (*(state)->push_back_ptr != 0) +#define PUSH_BACK_GET(state) (*(state)->push_back_ptr++) +#define PUSH_BACK_SET(state, text) ((state)->push_back_ptr = (text)) + static int var_tmout = 100; static int var_max_line_length = 2048; static char *var_myhostname; @@ -170,6 +191,25 @@ static int disable_xclient; static int disable_xforward; static int disable_enh_status; +#define SOFT_ERROR_RESP "450 4.3.0 Error: command failed" +#define HARD_ERROR_RESP "500 5.3.0 Error: command failed" + +/* hard_err_resp - generic hard error response */ + +static void hard_err_resp(SINK_STATE *state) +{ + smtp_printf(state->stream, HARD_ERROR_RESP); + smtp_flush(state->stream); +} + +/* soft_err_resp - generic soft error response */ + +static void soft_err_resp(SINK_STATE *state) +{ + smtp_printf(state->stream, SOFT_ERROR_RESP); + smtp_flush(state->stream); +} + /* ehlo_response - respond to EHLO command */ static void ehlo_response(SINK_STATE *state) @@ -244,6 +284,32 @@ static void data_event(int unused_event, char *context) data_response(state); } +/* dot_resp_hard - hard error response to . command */ + +static void dot_resp_hard(SINK_STATE *state) +{ + if (enable_lmtp) { + while (state->rcpts-- > 0) /* XXX this could block */ + smtp_printf(state->stream, HARD_ERROR_RESP); + } else { + smtp_printf(state->stream, HARD_ERROR_RESP); + } + smtp_flush(state->stream); +} + +/* dot_resp_soft - soft error response to . command */ + +static void dot_resp_soft(SINK_STATE *state) +{ + if (enable_lmtp) { + while (state->rcpts-- > 0) /* XXX this could block */ + smtp_printf(state->stream, SOFT_ERROR_RESP); + } else { + smtp_printf(state->stream, SOFT_ERROR_RESP); + } + smtp_flush(state->stream); +} + /* dot_response - response to . command */ static void dot_response(SINK_STATE *state) @@ -312,9 +378,7 @@ static int data_read(SINK_STATE *state) else state->data_state = ST_ANY; if (state->data_state == ST_CR_LF_DOT_CR_LF) { - if (msg_verbose) - msg_info("."); - dot_response(state); + PUSH_BACK_SET(state, ".\r\n"); state->read_fn = command_read; state->data_state = ST_ANY; break; @@ -337,6 +401,8 @@ static int data_read(SINK_STATE *state) typedef struct SINK_COMMAND { char *name; void (*response) (SINK_STATE *); + void (*hard_response) (SINK_STATE *); + void (*soft_response) (SINK_STATE *); int flags; } SINK_COMMAND; @@ -347,19 +413,20 @@ typedef struct SINK_COMMAND { #define FLAG_DISCONNECT (1<<4) /* disconnect */ static SINK_COMMAND command_table[] = { - "helo", helo_response, 0, - "ehlo", ehlo_response, 0, - "lhlo", ehlo_response, 0, - "xclient", ok_response, FLAG_ENABLE, - "xforward", ok_response, FLAG_ENABLE, - "auth", ok_response, FLAG_ENABLE, - "mail", mail_response, FLAG_ENABLE, - "rcpt", rcpt_response, FLAG_ENABLE, - "data", data_response, FLAG_ENABLE, - "rset", ok_response, FLAG_ENABLE, - "noop", ok_response, FLAG_ENABLE, - "vrfy", ok_response, FLAG_ENABLE, - "quit", quit_response, FLAG_ENABLE, + "helo", helo_response, hard_err_resp, soft_err_resp, 0, + "ehlo", ehlo_response, hard_err_resp, soft_err_resp, 0, + "lhlo", ehlo_response, hard_err_resp, soft_err_resp, 0, + "xclient", ok_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, + "xforward", ok_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, + "auth", ok_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, + "mail", mail_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, + "rcpt", rcpt_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, + "data", data_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, + ".", dot_response, dot_resp_hard, dot_resp_soft, FLAG_ENABLE, + "rset", ok_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, + "noop", ok_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, + "vrfy", ok_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, + "quit", quit_response, hard_err_resp, soft_err_resp, FLAG_ENABLE, 0, }; @@ -428,8 +495,11 @@ static int command_read(SINK_STATE *state) * A read may result in EOF, but is never supposed to time out - a time * out means that we were trying to read when no data was available. */ +#define NEXT_CHAR(state) \ + (PUSH_BACK_PEEK(state) ? PUSH_BACK_GET(state) : VSTREAM_GETC(state->stream)) + for (;;) { - if ((ch = VSTREAM_GETC(state->stream)) == VSTREAM_EOF) + if ((ch = NEXT_CHAR(state)) == VSTREAM_EOF) return (-1); /* @@ -467,7 +537,7 @@ static int command_read(SINK_STATE *state) * instead of peek_fd() (which uses ioctl FIONREAD). Workaround added * 20020604. */ - if (vstream_peek(state->stream) <= 0 + if (PUSH_BACK_PEEK(state) == 0 && vstream_peek(state->stream) <= 0 && readable(vstream_fileno(state->stream)) <= 0) return (0); } @@ -501,21 +571,19 @@ static int command_read(SINK_STATE *state) smtp_flush(state->stream); return (0); } - if (cmdp->flags & FLAG_DISCONNECT) - return (-1); - if (cmdp->flags & FLAG_HARD_ERR) { - smtp_printf(state->stream, "500 5.3.0 Error: command failed"); - smtp_flush(state->stream); - return (0); - } - if (cmdp->flags & FLAG_SOFT_ERR) { - smtp_printf(state->stream, "450 4.3.0 Error: command failed"); - smtp_flush(state->stream); - return (0); - } /* We use raw syslog. Sanitize data content and length. */ if (cmdp->flags & FLAG_SYSLOG) syslog(LOG_INFO, "%s %.100s", command, printable(ptr, '?')); + if (cmdp->flags & FLAG_DISCONNECT) + return (-1); + if (cmdp->flags & FLAG_HARD_ERR) { + cmdp->hard_response(state); + return (0); + } + if (cmdp->flags & FLAG_SOFT_ERR) { + cmdp->soft_response(state); + return (0); + } if (cmdp->response == data_response && fixed_delay > 0) { event_request_timer(data_event, (char *) state, fixed_delay); } else { @@ -582,7 +650,7 @@ static void read_event(int unused_event, char *context) return; } } - } while (vstream_peek(state->stream) > 0); + } while (PUSH_BACK_PEEK(state) != 0 || vstream_peek(state->stream) > 0); /* * Reset the idle timer. Wait until the next input event, or until the @@ -633,6 +701,7 @@ static void connect_event(int unused_event, char *context) state->buffer = vstring_alloc(1024); state->read_fn = command_read; state->data_state = ST_ANY; + PUSH_BACK_SET(state, ""); smtp_timeout_setup(state->stream, var_tmout); /* diff --git a/postfix/src/util/attr_print0.c b/postfix/src/util/attr_print0.c index 4d9c4e97e..26a6a394f 100644 --- a/postfix/src/util/attr_print0.c +++ b/postfix/src/util/attr_print0.c @@ -56,7 +56,8 @@ /* length, and an attribute value pointer. /* .IP "ATTR_TYPE_FUNC (ATTR_PRINT_SLAVE_FN, void *)" /* This argument is followed by a function pointer and generic data -/* pointer. +/* pointer. The caller-specified function returns whatever the +/* specified attribute printing function returns. /* .IP "ATTR_TYPE_HASH (HTABLE *)" /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" /* The content of the table is sent as a sequence of string-valued diff --git a/postfix/src/util/attr_print64.c b/postfix/src/util/attr_print64.c index cb13b0bfc..4d4704310 100644 --- a/postfix/src/util/attr_print64.c +++ b/postfix/src/util/attr_print64.c @@ -51,6 +51,10 @@ /* .IP "ATTR_TYPE_STR (char *, char *)" /* This argument is followed by an attribute name and a null-terminated /* string. +/* .IP "ATTR_TYPE_FUNC (ATTR_PRINT_SLAVE_FN, void *)" +/* This argument is followed by a function pointer and generic data +/* pointer. The caller-specified function returns whatever the +/* specified attribute printing function returns. /* .IP "ATTR_TYPE_HASH (HTABLE *)" /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" /* The content of the table is sent as a sequence of string-valued @@ -142,6 +146,8 @@ int attr_vprint64(VSTREAM *fp, int flags, va_list ap) HTABLE_INFO **ht_info_list; HTABLE_INFO **ht; int len_val; + ATTR_PRINT_SLAVE_FN print_fn; + void *print_arg; /* * Sanity check. @@ -196,6 +202,11 @@ int attr_vprint64(VSTREAM *fp, int flags, va_list ap) if (msg_verbose) msg_info("send attr %s = [data %d bytes]", attr_name, len_val); break; + case ATTR_TYPE_FUNC: + print_fn = va_arg(ap, ATTR_PRINT_SLAVE_FN); + print_arg = va_arg(ap, void *); + print_fn(attr_print64, fp, flags | ATTR_FLAG_MORE, print_arg); + break; case ATTR_TYPE_HASH: ht_info_list = htable_list(va_arg(ap, HTABLE *)); for (ht = ht_info_list; *ht; ht++) { diff --git a/postfix/src/util/attr_print_plain.c b/postfix/src/util/attr_print_plain.c index 4568bc938..5fb6b6684 100644 --- a/postfix/src/util/attr_print_plain.c +++ b/postfix/src/util/attr_print_plain.c @@ -54,6 +54,10 @@ /* .IP "ATTR_TYPE_DATA (char *, int, char *)" /* This argument is followed by an attribute name, an attribute value /* length, and a pointer to attribute value. +/* .IP "ATTR_TYPE_FUNC (ATTR_PRINT_SLAVE_FN, void *)" +/* This argument is followed by a function pointer and generic data +/* pointer. The caller-specified function returns whatever the +/* specified attribute printing function returns. /* .IP "ATTR_TYPE_HASH (HTABLE *)" /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" /* The content of the table is sent as a sequence of string-valued @@ -112,6 +116,8 @@ int attr_vprint_plain(VSTREAM *fp, int flags, va_list ap) HTABLE_INFO **ht; static VSTRING *base64_buf; int len_val; + ATTR_PRINT_SLAVE_FN print_fn; + void *print_arg; /* * Sanity check. @@ -157,6 +163,11 @@ int attr_vprint_plain(VSTREAM *fp, int flags, va_list ap) if (msg_verbose) msg_info("send attr %s = [data %d bytes]", attr_name, len_val); break; + case ATTR_TYPE_FUNC: + print_fn = va_arg(ap, ATTR_PRINT_SLAVE_FN); + print_arg = va_arg(ap, void *); + print_fn(attr_print_plain, fp, flags | ATTR_FLAG_MORE, print_arg); + break; case ATTR_TYPE_HASH: ht_info_list = htable_list(va_arg(ap, HTABLE *)); for (ht = ht_info_list; *ht; ht++) { diff --git a/postfix/src/util/attr_scan0.c b/postfix/src/util/attr_scan0.c index bf00c64c9..27f60a685 100644 --- a/postfix/src/util/attr_scan0.c +++ b/postfix/src/util/attr_scan0.c @@ -95,7 +95,8 @@ /* This argument is followed by an attribute name and a VSTRING pointer. /* .IP "ATTR_TYPE_FUNC (ATTR_SCAN_SLAVE_FN, void *)" /* This argument is followed by a function pointer and a generic data -/* pointer. +/* pointer. The caller-specified function returns < 0 in case of +/* error. /* .IP "ATTR_TYPE_HASH (HTABLE *)" /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" /* All further input attributes are processed as string attributes. diff --git a/postfix/src/util/attr_scan64.c b/postfix/src/util/attr_scan64.c index b6cce996d..8cf480812 100644 --- a/postfix/src/util/attr_scan64.c +++ b/postfix/src/util/attr_scan64.c @@ -47,7 +47,7 @@ /* characters. The formatting rules aim to make implementations in PERL /* and other languages easy. /* -/* Normally, attributes must be received in the sequence as specified with +/* Normally, attributes must be received in the sequence as specified with /* the attr_scan64() argument list. The input stream may contain additional /* attributes at any point in the input stream, including additional /* instances of requested attributes. @@ -95,6 +95,10 @@ /* This argument is followed by an attribute name and a VSTRING pointer. /* .IP "ATTR_TYPE_DATA (char *, VSTRING *)" /* This argument is followed by an attribute name and a VSTRING pointer. +/* .IP "ATTR_TYPE_FUNC (ATTR_SCAN_SLAVE_FN, void *)" +/* This argument is followed by a function pointer and a generic data +/* pointer. The caller-specified function returns < 0 in case of +/* error. /* .IP "ATTR_TYPE_HASH (HTABLE *)" /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" /* All further input attributes are processed as string attributes. @@ -165,9 +169,11 @@ static int attr_scan64_string(VSTREAM *fp, VSTRING *plain_buf, const char *context) { static VSTRING *base64_buf = 0; + #if 0 extern int var_line_limit; /* XXX */ int limit = var_line_limit * 4; + #endif int ch; @@ -254,6 +260,8 @@ int attr_vscan64(VSTREAM *fp, int flags, va_list ap) HTABLE *hash_table; int ch; int conversions; + ATTR_SCAN_SLAVE_FN scan_fn; + void *scan_arg; /* * Sanity check. @@ -295,7 +303,7 @@ int attr_vscan64(VSTREAM *fp, int flags, va_list ap) if (va_arg(ap, int) !=ATTR_TYPE_END) msg_panic("%s: ATTR_TYPE_HASH not followed by ATTR_TYPE_END", myname); - } else { + } else if (wanted_type != ATTR_TYPE_FUNC) { wanted_name = va_arg(ap, char *); } } @@ -303,7 +311,7 @@ int attr_vscan64(VSTREAM *fp, int flags, va_list ap) /* * Locate the next attribute of interest in the input stream. */ - for (;;) { + while (wanted_type != ATTR_TYPE_FUNC) { /* * Get the name of the next attribute. Hitting EOF is always bad. @@ -419,6 +427,12 @@ int attr_vscan64(VSTREAM *fp, int flags, va_list ap) return (-1); } break; + case ATTR_TYPE_FUNC: + scan_fn = va_arg(ap, ATTR_SCAN_SLAVE_FN); + scan_arg = va_arg(ap, void *); + if (scan_fn(attr_scan64, fp, flags | ATTR_FLAG_MORE, scan_arg) < 0) + return (-1); + break; case ATTR_TYPE_HASH: if (ch != ':') { msg_warn("missing value for string attribute %s from %s", diff --git a/postfix/src/util/attr_scan_plain.c b/postfix/src/util/attr_scan_plain.c index ba2be7970..79c119cf5 100644 --- a/postfix/src/util/attr_scan_plain.c +++ b/postfix/src/util/attr_scan_plain.c @@ -45,7 +45,7 @@ /* characters. The formatting rules aim to make implementations in PERL /* and other languages easy. /* -/* Normally, attributes must be received in the sequence as specified +/* Normally, attributes must be received in the sequence as specified /* with the attr_scan_plain() argument list. The input stream may /* contain additional attributes at any point in the input stream, /* including additional instances of requested attributes. @@ -93,6 +93,10 @@ /* This argument is followed by an attribute name and a VSTRING pointer. /* .IP "ATTR_TYPE_DATA (char *, VSTRING *)" /* This argument is followed by an attribute name and a VSTRING pointer. +/* .IP "ATTR_TYPE_FUNC (ATTR_SCAN_SLAVE_FN, void *)" +/* This argument is followed by a function pointer and a generic data +/* pointer. The caller-specified function returns < 0 in case of +/* error. /* .IP "ATTR_TYPE_HASH (HTABLE *)" /* .IP "ATTR_TYPE_NAMEVAL (NVTABLE *)" /* All further input attributes are processed as string attributes. @@ -166,6 +170,7 @@ static int attr_scan_plain_string(VSTREAM *fp, VSTRING *plain_buf, #if 0 extern int var_line_limit; /* XXX */ int limit = var_line_limit * 4; + #endif int ch; @@ -268,6 +273,8 @@ int attr_vscan_plain(VSTREAM *fp, int flags, va_list ap) HTABLE *hash_table; int ch; int conversions; + ATTR_SCAN_SLAVE_FN scan_fn; + void *scan_arg; /* * Sanity check. @@ -309,7 +316,7 @@ int attr_vscan_plain(VSTREAM *fp, int flags, va_list ap) if (va_arg(ap, int) !=ATTR_TYPE_END) msg_panic("%s: ATTR_TYPE_HASH not followed by ATTR_TYPE_END", myname); - } else { + } else if (wanted_type != ATTR_TYPE_FUNC) { wanted_name = va_arg(ap, char *); } } @@ -317,7 +324,7 @@ int attr_vscan_plain(VSTREAM *fp, int flags, va_list ap) /* * Locate the next attribute of interest in the input stream. */ - for (;;) { + while (wanted_type != ATTR_TYPE_FUNC) { /* * Get the name of the next attribute. Hitting EOF is always bad. @@ -361,12 +368,7 @@ int attr_vscan_plain(VSTREAM *fp, int flags, va_list ap) } /* - * Do the requested conversion. If the target attribute is a - * non-array type, disallow sending a multi-valued attribute, and - * disallow sending no value. If the target attribute is an array - * type, allow the sender to send a zero-element array (i.e. no value - * at all). XXX Need to impose a bound on the number of array - * elements. + * Do the requested conversion. */ switch (wanted_type) { case ATTR_TYPE_NUM: @@ -413,6 +415,12 @@ int attr_vscan_plain(VSTREAM *fp, int flags, va_list ap) "input attribute value")) < 0) return (-1); break; + case ATTR_TYPE_FUNC: + scan_fn = va_arg(ap, ATTR_SCAN_SLAVE_FN); + scan_arg = va_arg(ap, void *); + if (scan_fn(attr_scan_plain, fp, flags | ATTR_FLAG_MORE, scan_arg) < 0) + return (-1); + break; case ATTR_TYPE_HASH: if (ch != '=') { msg_warn("missing value for string attribute %s from %s",