mirror of
https://github.com/vdukhovni/postfix
synced 2025-08-30 05:38:06 +00:00
snapshot-20000504
This commit is contained in:
parent
17e2c5a67a
commit
2e7745be77
4
postfix/.indent.pro
vendored
4
postfix/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/base64/.indent.pro
vendored
4
postfix/base64/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/bounce/.indent.pro
vendored
4
postfix/bounce/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/cleanup/.indent.pro
vendored
4
postfix/cleanup/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/dns/.indent.pro
vendored
4
postfix/dns/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/error/.indent.pro
vendored
4
postfix/error/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/fsstone/.indent.pro
vendored
4
postfix/fsstone/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/global/.indent.pro
vendored
4
postfix/global/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
@ -15,7 +15,7 @@
|
||||
* Version of this program.
|
||||
*/
|
||||
#define VAR_MAIL_VERSION "mail_version"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20000503"
|
||||
#define DEF_MAIL_VERSION "Snapshot-20000504"
|
||||
extern char *var_mail_version;
|
||||
|
||||
/* LICENSE
|
||||
|
@ -6,10 +6,6 @@
|
||||
/* SYNOPSIS
|
||||
/* #include <smtp_stream.h>
|
||||
/*
|
||||
/* void smtp_jump_setup(stream, jbuf)
|
||||
/* VSTREAM *stream;
|
||||
/* jmp_buf *jbuf;
|
||||
/*
|
||||
/* void smtp_timeout_setup(stream, timeout)
|
||||
/* VSTREAM *stream;
|
||||
/* int timeout;
|
||||
@ -46,22 +42,15 @@
|
||||
/* with error detection: timeouts or unexpected end-of-file.
|
||||
/* A trailing CR LF is added upon writing and removed upon reading.
|
||||
/*
|
||||
/* smtp_jump_setup() registers a caller context that will be
|
||||
/* jumped to (with longjmp()) when any routine in this module
|
||||
/* experiences an error condition (timeout, I/O error, or
|
||||
/* unexpected EOF).
|
||||
/*
|
||||
/* smtp_timeout_setup() arranges for a time limit on the smtp read
|
||||
/* and write operations described below.
|
||||
/* This routine alters the behavior of streams as follows:
|
||||
/* .IP \(bu
|
||||
/* The read routine is replaced by one than calls timed_read().
|
||||
/* .IP \(bu
|
||||
/* The write routine is replaced by one that calls timed_write().
|
||||
/* The read/write timeout is set to the specified value.
|
||||
/* .IP \f(bu
|
||||
/* The stream is configured to use double buffering.
|
||||
/* .IP \f(bu
|
||||
/* A timeout error is reported to the vstream module as an I/O error.
|
||||
/* The stream is configured to enable exception handling.
|
||||
/* .PP
|
||||
/* smtp_printf() formats its arguments and writes the result to
|
||||
/* the named stream, followed by a CR LF pair. The stream is flushed.
|
||||
@ -89,9 +78,9 @@
|
||||
/* DIAGNOSTICS
|
||||
/* .fi
|
||||
/* .ad
|
||||
/* In case of error, a longjmp() is performed to the context
|
||||
/* specified with the smtp_jump_setup() call.
|
||||
/* Error codes passed along with longjmp() are:
|
||||
/* In case of error, a vstream_longjmp() call is performed to the
|
||||
/* context specified with vstream_setjmp().
|
||||
/* Error codes passed along with vstream_longjmp() are:
|
||||
/* .IP SMTP_ERR_EOF
|
||||
/* An I/O error happened, or the peer has disconnected unexpectedly.
|
||||
/* .IP SMTP_ERR_TIME
|
||||
@ -100,8 +89,8 @@
|
||||
/* The timeout deadline affects all I/O on the named stream, not
|
||||
/* just the I/O done on behalf of this module.
|
||||
/*
|
||||
/* The timeout deadline and exception handling context overwrite
|
||||
/* any previously set up state on the named stream.
|
||||
/* The timeout deadline overwrites any previously set up state on
|
||||
/* the named stream.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
@ -137,35 +126,9 @@
|
||||
|
||||
#include "smtp_stream.h"
|
||||
|
||||
/*
|
||||
* Our private VSTREAM attribute name for keeping track of the
|
||||
* caller-supplied context for exception handling.
|
||||
*/
|
||||
#define SMTP_ATTR_JBUF "smtp_timeout_buf"
|
||||
/* smtp_timeout_reset - reset per-stream timeout flag */
|
||||
|
||||
/* smtp_timeout_jump - release timeout trap */
|
||||
|
||||
static void smtp_timeout_jump(VSTREAM *stream, int what)
|
||||
{
|
||||
char *myname = "smtp_timeout_jump";
|
||||
jmp_buf *jbuf;
|
||||
|
||||
if ((jbuf = (jmp_buf *) vstream_attr_get(stream, SMTP_ATTR_JBUF)) == 0)
|
||||
msg_panic("%s: no jump buffer", myname);
|
||||
longjmp(jbuf[0], what);
|
||||
}
|
||||
|
||||
/* smtp_jump_setup - configure exception handling context */
|
||||
|
||||
void smtp_jump_setup(VSTREAM *stream, jmp_buf * jbuf)
|
||||
{
|
||||
vstream_attr_set(stream, SMTP_ATTR_JBUF,
|
||||
(char *) jbuf, (VSTREAM_ATTR_FREE_FN) 0);
|
||||
}
|
||||
|
||||
/* smtp_timeout_protect - reset per-stream timeout flag */
|
||||
|
||||
static void smtp_timeout_protect(VSTREAM *stream)
|
||||
static void smtp_timeout_reset(VSTREAM *stream)
|
||||
{
|
||||
vstream_clearerr(stream);
|
||||
}
|
||||
@ -175,7 +138,7 @@ static void smtp_timeout_protect(VSTREAM *stream)
|
||||
static void smtp_timeout_detect(VSTREAM *stream)
|
||||
{
|
||||
if (vstream_ftimeout(stream))
|
||||
smtp_timeout_jump(stream, SMTP_ERR_TIME);
|
||||
vstream_longjmp(stream, SMTP_ERR_TIME);
|
||||
}
|
||||
|
||||
/* smtp_timeout_setup - configure timeout trap */
|
||||
@ -185,13 +148,14 @@ void smtp_timeout_setup(VSTREAM *stream, int maxtime)
|
||||
|
||||
/*
|
||||
* Stick your TLS/whatever read-write routines here. Notice that the
|
||||
* read/write interface now includes a timeout parameter, and that a
|
||||
* read/write routine is supposed to set errno to ETIMEDOUT when the
|
||||
* alarm clock goes off.
|
||||
* read/write interface now includes a timeout parameter and application
|
||||
* context, and that a read/write routine is supposed to set errno to
|
||||
* ETIMEDOUT when the alarm clock goes off.
|
||||
*/
|
||||
vstream_control(stream,
|
||||
VSTREAM_CTL_TIMEOUT, maxtime,
|
||||
VSTREAM_CTL_DOUBLE,
|
||||
VSTREAM_CTL_TIMEOUT, maxtime,
|
||||
VSTREAM_CTL_EXCEPT,
|
||||
VSTREAM_CTL_END);
|
||||
}
|
||||
|
||||
@ -204,7 +168,7 @@ void smtp_vprintf(VSTREAM *stream, const char *fmt, va_list ap)
|
||||
/*
|
||||
* Do the I/O, protected against timeout.
|
||||
*/
|
||||
smtp_timeout_protect(stream);
|
||||
smtp_timeout_reset(stream);
|
||||
vstream_vfprintf(stream, fmt, ap);
|
||||
vstream_fputs("\r\n", stream);
|
||||
err = vstream_fflush(stream);
|
||||
@ -216,7 +180,7 @@ void smtp_vprintf(VSTREAM *stream, const char *fmt, va_list ap)
|
||||
if (err != 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("smtp_vprintf: EOF");
|
||||
smtp_timeout_jump(stream, SMTP_ERR_EOF);
|
||||
vstream_longjmp(stream, SMTP_ERR_EOF);
|
||||
}
|
||||
}
|
||||
|
||||
@ -244,7 +208,7 @@ int smtp_get(VSTRING *vp, VSTREAM *stream, int bound)
|
||||
* allow for lines ending in bare LF. The idea is to be liberal in what
|
||||
* we accept, strict in what we send.
|
||||
*/
|
||||
smtp_timeout_protect(stream);
|
||||
smtp_timeout_reset(stream);
|
||||
last_char = (bound == 0 ? vstring_get(vp, stream) :
|
||||
vstring_get_bound(vp, stream, bound));
|
||||
|
||||
@ -291,7 +255,7 @@ int smtp_get(VSTRING *vp, VSTREAM *stream, int bound)
|
||||
if (vstream_feof(stream) || vstream_ferror(stream)) {
|
||||
if (msg_verbose)
|
||||
msg_info("smtp_get: EOF");
|
||||
smtp_timeout_jump(stream, SMTP_ERR_EOF);
|
||||
vstream_longjmp(stream, SMTP_ERR_EOF);
|
||||
}
|
||||
return (last_char);
|
||||
}
|
||||
@ -308,7 +272,7 @@ void smtp_fputs(const char *cp, int todo, VSTREAM *stream)
|
||||
/*
|
||||
* Do the I/O, protected against timeout.
|
||||
*/
|
||||
smtp_timeout_protect(stream);
|
||||
smtp_timeout_reset(stream);
|
||||
err = (vstream_fwrite(stream, cp, todo) != todo
|
||||
|| vstream_fputs("\r\n", stream) == VSTREAM_EOF);
|
||||
smtp_timeout_detect(stream);
|
||||
@ -319,7 +283,7 @@ void smtp_fputs(const char *cp, int todo, VSTREAM *stream)
|
||||
if (err != 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("smtp_fputs: EOF");
|
||||
smtp_timeout_jump(stream, SMTP_ERR_EOF);
|
||||
vstream_longjmp(stream, SMTP_ERR_EOF);
|
||||
}
|
||||
}
|
||||
|
||||
@ -335,7 +299,7 @@ void smtp_fwrite(const char *cp, int todo, VSTREAM *stream)
|
||||
/*
|
||||
* Do the I/O, protected against timeout.
|
||||
*/
|
||||
smtp_timeout_protect(stream);
|
||||
smtp_timeout_reset(stream);
|
||||
err = (vstream_fwrite(stream, cp, todo) != todo);
|
||||
smtp_timeout_detect(stream);
|
||||
|
||||
@ -345,7 +309,7 @@ void smtp_fwrite(const char *cp, int todo, VSTREAM *stream)
|
||||
if (err != 0) {
|
||||
if (msg_verbose)
|
||||
msg_info("smtp_fwrite: EOF");
|
||||
smtp_timeout_jump(stream, SMTP_ERR_EOF);
|
||||
vstream_longjmp(stream, SMTP_ERR_EOF);
|
||||
}
|
||||
}
|
||||
|
||||
@ -358,7 +322,7 @@ void smtp_fputc(int ch, VSTREAM *stream)
|
||||
/*
|
||||
* Do the I/O, protected against timeout.
|
||||
*/
|
||||
smtp_timeout_protect(stream);
|
||||
smtp_timeout_reset(stream);
|
||||
stat = VSTREAM_PUTC(ch, stream);
|
||||
smtp_timeout_detect(stream);
|
||||
|
||||
@ -368,6 +332,6 @@ void smtp_fputc(int ch, VSTREAM *stream)
|
||||
if (stat == VSTREAM_EOF) {
|
||||
if (msg_verbose)
|
||||
msg_info("smtp_fputc: EOF");
|
||||
smtp_timeout_jump(stream, SMTP_ERR_EOF);
|
||||
vstream_longjmp(stream, SMTP_ERR_EOF);
|
||||
}
|
||||
}
|
||||
|
120
postfix/lmtp/.indent.pro
vendored
Normal file
120
postfix/lmtp/.indent.pro
vendored
Normal file
@ -0,0 +1,120 @@
|
||||
-TALIAS_TOKEN
|
||||
-TARGV
|
||||
-TBH_TABLE
|
||||
-TBINATTR
|
||||
-TBINATTR_INFO
|
||||
-TBINHASH
|
||||
-TBINHASH_INFO
|
||||
-TBOUNCE_STAT
|
||||
-TCLEANUP_STATE
|
||||
-TCLIENT_LIST
|
||||
-TCLNT_STREAM
|
||||
-TCONFIG_BOOL_FN_TABLE
|
||||
-TCONFIG_BOOL_TABLE
|
||||
-TCONFIG_INT_FN_TABLE
|
||||
-TCONFIG_INT_TABLE
|
||||
-TCONFIG_STR_FN_TABLE
|
||||
-TCONFIG_STR_TABLE
|
||||
-TDELIVER_ATTR
|
||||
-TDELIVER_REQUEST
|
||||
-TDICT
|
||||
-TDICT_DB
|
||||
-TDICT_DBM
|
||||
-TDICT_ENV
|
||||
-TDICT_HT
|
||||
-TDICT_LDAP
|
||||
-TDICT_MYSQL
|
||||
-TDICT_NI
|
||||
-TDICT_NIS
|
||||
-TDICT_NISPLUS
|
||||
-TDICT_NODE
|
||||
-TDICT_OPEN_INFO
|
||||
-TDICT_PCRE
|
||||
-TDICT_REGEXP
|
||||
-TDICT_REGEXP_RULE
|
||||
-TDICT_UNIX
|
||||
-TDNS_FIXED
|
||||
-TDNS_REPLY
|
||||
-TDNS_RR
|
||||
-TDOMAIN_LIST
|
||||
-TEXPAND_ATTR
|
||||
-TFILE
|
||||
-TFORWARD_INFO
|
||||
-THEADER_OPTS
|
||||
-THOST
|
||||
-THTABLE
|
||||
-THTABLE_INFO
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
-TMAC_HEAD
|
||||
-TMAC_PARSE
|
||||
-TMAIL_PRINT
|
||||
-TMAIL_SCAN
|
||||
-TMAPS
|
||||
-TMASTER_PROC
|
||||
-TMASTER_SERV
|
||||
-TMASTER_STATUS
|
||||
-TMBLOCK
|
||||
-TMKMAP
|
||||
-TMKMAP_OPEN_INFO
|
||||
-TMULTI_SERVER
|
||||
-TMVECT
|
||||
-TMYSQL_NAME
|
||||
-TNAMADR_LIST
|
||||
-TNAME_MASK
|
||||
-TPEER_NAME
|
||||
-TPICKUP_INFO
|
||||
-TPIPE_ATTR
|
||||
-TPIPE_PARAMS
|
||||
-TPLMYSQL
|
||||
-TQMGR_ENTRY
|
||||
-TQMGR_MESSAGE
|
||||
-TQMGR_QUEUE
|
||||
-TQMGR_RCPT_LIST
|
||||
-TQMGR_RECIPIENT
|
||||
-TQMGR_SCAN
|
||||
-TQMGR_TRANSPORT
|
||||
-TRECIPIENT
|
||||
-TRECIPIENT_LIST
|
||||
-TREC_TYPE_NAME
|
||||
-TRESOLVE_REPLY
|
||||
-TRESPONSE
|
||||
-TSCAN_DIR
|
||||
-TSCAN_INFO
|
||||
-TSCAN_OBJ
|
||||
-TSESSION
|
||||
-TSINGLE_SERVER
|
||||
-TSINK_COMMAND
|
||||
-TSINK_STATE
|
||||
-TSMTPD_CMD
|
||||
-TSMTPD_STATE
|
||||
-TSMTPD_TOKEN
|
||||
-TSMTP_ADDR
|
||||
-TSMTP_CMD
|
||||
-TSMTP_RESP
|
||||
-TSMTP_SESSION
|
||||
-TSMTP_STATE
|
||||
-TSOCKADDR_SIZE
|
||||
-TSPAWN_ATTR
|
||||
-TSTRING_TABLE
|
||||
-TSYS_EXITS_TABLE
|
||||
-TTOK822
|
||||
-TTRIGGER_SERVER
|
||||
-TUSER_ATTR
|
||||
-TVBUF
|
||||
-TVSTREAM
|
||||
-TVSTREAM_POPEN_ARGS
|
||||
-TVSTRING
|
||||
-TWAIT_STATUS_T
|
||||
-TWATCHDOG
|
||||
-TWATCH_FD
|
||||
-Tsasl_conn_t
|
||||
-Tsasl_secret_t
|
25
postfix/lmtp/.printfck
Normal file
25
postfix/lmtp/.printfck
Normal file
@ -0,0 +1,25 @@
|
||||
been_here_xt 2 0
|
||||
bounce_append 5 0
|
||||
cleanup_out_format 1 0
|
||||
defer_append 5 0
|
||||
mail_command 1 0
|
||||
mail_print 1 0
|
||||
msg_error 0 0
|
||||
msg_fatal 0 0
|
||||
msg_info 0 0
|
||||
msg_panic 0 0
|
||||
msg_warn 0 0
|
||||
opened 3 0
|
||||
post_mail_fprintf 1 0
|
||||
qmgr_message_bounce 2 0
|
||||
rec_fprintf 2 0
|
||||
sent 4 0
|
||||
smtp_cmd 1 0
|
||||
smtp_mesg_fail 2 0
|
||||
smtp_printf 1 0
|
||||
smtp_rcpt_fail 3 0
|
||||
smtp_site_fail 2 0
|
||||
udp_syslog 1 0
|
||||
vstream_fprintf 1 0
|
||||
vstream_printf 0 0
|
||||
vstring_sprintf 1 0
|
146
postfix/lmtp/CHANGES
Normal file
146
postfix/lmtp/CHANGES
Normal file
@ -0,0 +1,146 @@
|
||||
2000 Feb 23
|
||||
|
||||
* lmtp.c, lmtp_connect.c, global-patch: added the main.cf
|
||||
configuration parameter "lmtp_tcp_port". If no port is explicitly
|
||||
specificed for the connection to the inet LMTP server, first
|
||||
lookup "lmtp" with getservbyname. If that fails, use the value of
|
||||
this "lmtp_tcp_port" parameter, which as a default value of 24.
|
||||
|
||||
|
||||
2000 Feb 21
|
||||
|
||||
* Updated lmtp.c to yield a lmtp.8 man page that more accurately
|
||||
reflects the current code.
|
||||
|
||||
* Created man-patch so that lmtp.8 man page is created. Updated
|
||||
README to include applying this patch.
|
||||
|
||||
|
||||
2000 Feb 17
|
||||
|
||||
* Correctly handle lmtp master.cf arguments of type "inet".
|
||||
Possible uses are:
|
||||
|
||||
_USAGE_ _MEANING_
|
||||
serv=inet: connect over tcp to $nexthop
|
||||
serv=inet:hostname connect to named host port 24
|
||||
(Actually, what "lmtp" is defined to be
|
||||
in /etc/services.)
|
||||
serv=inet:hostname:port connect to named host named port
|
||||
serv=inet:[ip.address] connect to named host port 24
|
||||
serv=inet:[ip.address]:port connect to named address named port
|
||||
|
||||
|
||||
2000 Feb 15
|
||||
|
||||
* Put in comment about local_destination_recipient_limit
|
||||
in README.local.
|
||||
|
||||
* In lmtp_chat.c, changed error reporting so that it goes
|
||||
to var_error_rcpt, like the other Postfix services.
|
||||
|
||||
|
||||
2000 Jan 31
|
||||
|
||||
* lmtp_proto.c:lmtp_lhlo: Don't worry about LMTP_FEATURE_PIPELINING
|
||||
for sessions of type LMTP_SERV_TYPE_UNIX.
|
||||
|
||||
|
||||
2000 Jan 30
|
||||
|
||||
* BIG changes. Removed all the pipe stuff from lmtp.c and
|
||||
lmtp_connect.c Now, lmtp will either do a remote connection much
|
||||
like the smtp client, or it will connect to a UNIX domain socket
|
||||
to an auxiliary service (spawn). This makes the lmtp patch
|
||||
simpler because it doesn't have to worry at all about exec-ing an
|
||||
external command, and all the resulting security implications.
|
||||
See README.local for details.
|
||||
|
||||
NOTE: postfix-19991231-pl04 is REQUIRED for this to work!
|
||||
(Need the "spawn" service.)
|
||||
|
||||
* Updated the makefile-patch for postfix-19991231-pl03.
|
||||
|
||||
* lmtp.h: changed the LMTP_ATTR structure to contain "type", "class", and
|
||||
"name" fields, reflecting the change from the pipe mechanism to
|
||||
the local sockets connection. Changed LMTP_SESSION to contain the
|
||||
"type" field. The connection type is recorded in this field in
|
||||
case it is needed elsewhere, like in lmtp_proto.
|
||||
|
||||
* lmtp.c:get_service_attr altered for new command syntax. Examples:
|
||||
|
||||
serv=unix:private/lmtpd
|
||||
serv=inet:public/lmtpd
|
||||
|
||||
After `serv=' is the "type", followed by `:', then the "class",
|
||||
followed by '/', and then finally the "name".
|
||||
|
||||
* Added SAME_DESTINATION macro to lmtp.c:deliver_message for
|
||||
readability, and simpler logic.
|
||||
|
||||
* lmtp_connect.c: changed lmtp_connect to contain logic to determine
|
||||
just what kind of connection to make, removing it from lmtp.c;
|
||||
removed lmtp_connect_pipe; and added lmtp_connect_local, which
|
||||
uses mail_connect_wait to connect to the service running the LMTP
|
||||
server (spawn). In lmtp_connect, the connection type stored in
|
||||
attr.type is saved into session.type, so it can be used later if
|
||||
necessary.
|
||||
|
||||
* lmtp_proto.c:lmtp_lhlo: towards the end of this function we check
|
||||
to see if service->type is LMTP_SERV_TYPE_UNIX so that we don't
|
||||
try to do a getsockopt on a descriptor that doesn't support it.
|
||||
Is this the best way to handle this? Or maybe we should just try
|
||||
it and if it bombs, check the error code before simply going
|
||||
fatal?
|
||||
|
||||
* Snagged the latest quota_821_local.c from the smtp client.
|
||||
|
||||
* Updated the README files accordingly.
|
||||
|
||||
|
||||
2000 Jan 28
|
||||
|
||||
* Well, wondering about using REWRITE_ADDRESS in lmtp_proto.c,
|
||||
putting the lowercase thing in there. Though, that would also
|
||||
apply to sender address. Is that okay?
|
||||
|
||||
* We shouldn't be doing DNS lookups at this stage, so can get rid
|
||||
of lmtp_unalias.c. Also cut out the unalias portion in
|
||||
REWRITE_ADDRESS in lmtp_proto.c
|
||||
|
||||
|
||||
2000 Jan 11
|
||||
|
||||
* At the suggestion of Rupa Schomaker, added the following to
|
||||
lmtp_proto.c:
|
||||
|
||||
lowercase(rcpt->address); /* [AAG] rupa */
|
||||
|
||||
|
||||
1999 Dec 1 (or thereabouts)
|
||||
|
||||
* Added lmtp_session_reset to make it easier to remember to reset
|
||||
certain things to 0. Did this to lmtp_chat_reset too.
|
||||
|
||||
* Finally, did some work with the connection caching so that an RSET
|
||||
is sent to the LMTP server. This is done for two reasons: first,
|
||||
to tell the LMTP server to flush out any status information
|
||||
because we're about to feed it another message, and second, to
|
||||
test the link to see if it is still alive. If the link has died
|
||||
for some reason, it is reestablished. Changes to lmtp.c and
|
||||
lmtp_proto.c.
|
||||
|
||||
* There was also some tidying in lmtp.c so that things were a little
|
||||
clearer as to what was going on. I added a few more comments as
|
||||
well.
|
||||
|
||||
* I tried to make the master.cf argument parsing a little more
|
||||
consistent with the other Postfix services. Changes to lmtp.c.
|
||||
|
||||
* On the postfix-users mailing list, Valery Brasseur pointed out that
|
||||
errors encountered during LMTP delivery were not getting bounced
|
||||
as appropriate. This lead me to investigate the matter, wanting
|
||||
to put this LMTP capability into service myself. I then realized
|
||||
that some of the error checking was a tad over zealous, and so
|
||||
simplified things a bit in lmtp_proto.c.
|
||||
|
61
postfix/lmtp/Makefile.in
Normal file
61
postfix/lmtp/Makefile.in
Normal file
@ -0,0 +1,61 @@
|
||||
SHELL = /bin/sh
|
||||
SRCS = lmtp.c quote_821_local.c lmtp_connect.c lmtp_proto.c lmtp_chat.c \
|
||||
lmtp_session.c lmtp_addr.c lmtp_trouble.c lmtp_state.c
|
||||
OBJS = lmtp.o quote_821_local.o lmtp_connect.o lmtp_proto.o lmtp_chat.o \
|
||||
lmtp_session.o lmtp_addr.o lmtp_trouble.o lmtp_state.o
|
||||
HDRS = lmtp.h
|
||||
TESTSRC =
|
||||
WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \
|
||||
-Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \
|
||||
-Wunused
|
||||
DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
|
||||
CFLAGS = $(DEBUG) $(OPT) $(DEFS)
|
||||
TESTPROG= quote_821_local
|
||||
PROG = lmtp
|
||||
INC_DIR = ../include
|
||||
LIBS = ../lib/libmaster.a ../lib/libglobal.a ../lib/libdns.a ../lib/libutil.a
|
||||
|
||||
.c.o:; $(CC) $(CFLAGS) -c $*.c
|
||||
|
||||
$(PROG): $(OBJS) $(LIBS)
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS)
|
||||
|
||||
Makefile: Makefile.in
|
||||
(set -e; echo "# DO NOT EDIT"; $(OPTS) sh ../makedefs; cat $?) >$@
|
||||
|
||||
test: $(TESTPROG)
|
||||
|
||||
update: ../libexec/$(PROG)
|
||||
|
||||
../libexec/$(PROG): $(PROG)
|
||||
cp $(PROG) ../libexec
|
||||
|
||||
printfck: $(OBJS) $(PROG)
|
||||
rm -rf printfck
|
||||
mkdir printfck
|
||||
cp *.h printfck
|
||||
sed '1,/^# do not edit/!d' Makefile >printfck/Makefile
|
||||
set -e; for i in *.c; do printfck -f .printfck $$i >printfck/$$i; done
|
||||
cd printfck; make "INC_DIR=../../include" `cd ..; ls *.o`
|
||||
|
||||
lint:
|
||||
lint $(DEFS) $(SRCS) $(LINTFIX)
|
||||
|
||||
clean:
|
||||
rm -f *.o *core $(PROG) $(TESTPROG) junk
|
||||
rm -rf printfck
|
||||
|
||||
tidy: clean
|
||||
|
||||
quote_821_local: quote_821_local.c $(LIBS)
|
||||
$(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIBS) $(SYSLIBS)
|
||||
|
||||
depend: $(MAKES)
|
||||
(sed '1,/^# do not edit/!d' Makefile.in; \
|
||||
set -e; for i in [a-z][a-z0-9]*.c; do \
|
||||
$(CC) -E $(DEFS) $(INCL) $$i | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
|
||||
-e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \
|
||||
done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
|
||||
@make -f Makefile.in Makefile
|
||||
|
||||
# do not edit below this line - it is generated by 'make depend'
|
34
postfix/lmtp/README
Normal file
34
postfix/lmtp/README
Normal file
@ -0,0 +1,34 @@
|
||||
README
|
||||
|
||||
The starting point for this work was the original LMTP patch,
|
||||
lmtp-19990427.tar.gz, found in the experimental directory on the
|
||||
Postfix mirror ftp sites. Without this original work by Philip A.
|
||||
Prindeville, I probably wouldn't have taken the time to dive into
|
||||
this issue. Fortunately, this individual's work gave me a good
|
||||
starting point to learn about LMTP, and Postfix in general.
|
||||
|
||||
First, in the Postfix source directory, apply the following patches:
|
||||
|
||||
patch -p0 < lmtp/makefile-patch
|
||||
patch -p0 < lmtp/global-patch
|
||||
patch -p0 < lmtp/man-patch
|
||||
|
||||
Then compile and install Postfix as usual. There really isn't
|
||||
anything OS specific so it should compile without problems.
|
||||
|
||||
NOTE: Previously this patch would do a pipe to an external command
|
||||
to perform local delivery. That is no longer the case! This
|
||||
version now requires the "spawn" service be defined. See
|
||||
README.local for details.
|
||||
|
||||
The other way to use this lmtp service is to talk to a remote LMTP
|
||||
server. An example of this would be if an MX host is to insert
|
||||
incoming mail directly into a message store that supports the LMTP
|
||||
protocol. This is described in README.inet.
|
||||
|
||||
The file CHANGES lists some of the changes that have been made
|
||||
since lmtp-19990427.tar.gz, and TODO discusses some thoughts
|
||||
that are currently floating around.
|
||||
|
||||
Amos
|
||||
|
80
postfix/lmtp/README.inet
Normal file
80
postfix/lmtp/README.inet
Normal file
@ -0,0 +1,80 @@
|
||||
README.inet
|
||||
|
||||
This is an example of how to set up a remote LMTP server. This can
|
||||
be useful if you have a central/firewall mail router that feeds
|
||||
incoming mail into the appropriate inbox server(s), the central box
|
||||
can stuff the incoming mail directly into the message store on the
|
||||
inbox machine using LMTP. This also means the inbox machine doesn't
|
||||
have to have a SMTP server to handle this intermediate step. Tidy
|
||||
all the way around.
|
||||
|
||||
|
||||
** Inbox Server:
|
||||
|
||||
On the inbox server, in this case a CMU Cyrus imapd/popd server, add
|
||||
the following to /etc/services:
|
||||
|
||||
pop3 110/tcp # Cyrus POP3
|
||||
imap 143/tcp # Cyrus IMAP4
|
||||
lmtp 24/tcp
|
||||
|
||||
|
||||
Next, put the following in /etc/inetd.conf:
|
||||
|
||||
lmtp stream tcp nowait cyrus /usr/sbin/tcpd /usr/local/cyrus/bin/deliver -e -l
|
||||
|
||||
|
||||
(/usr/sbin/tcpd is from the tcp_wrappers package. You want this to
|
||||
make sure only your central box can do the stuffing.)
|
||||
|
||||
|
||||
** Central Server:
|
||||
|
||||
Similar changes to /etc/services:
|
||||
|
||||
lmtp 24/tcp
|
||||
|
||||
|
||||
Now we add this to /etc/postfix/master.cf:
|
||||
|
||||
lmtp unix - - n - - lmtp
|
||||
|
||||
|
||||
NOTES: No arguments are specified to lmtp!
|
||||
Root privs are not necessary!
|
||||
|
||||
We put this in /etc/postfix/transport:
|
||||
|
||||
inbox.domain.org lmtp:inbox.domain.org
|
||||
|
||||
|
||||
Naturally, this means we also have to have in
|
||||
/etc/postfix/main.cf:
|
||||
|
||||
transport_maps = hash:/etc/postfix/transport
|
||||
|
||||
|
||||
Use the map type of your choice.
|
||||
|
||||
That's it.
|
||||
|
||||
|
||||
Oh, it may be necessary to apply the following patch to deliver so
|
||||
that the final "bye" is not lost. This should not be necessary in
|
||||
releases subsequent to 1.6.20 of cyrus-imapd.
|
||||
|
||||
*** deliver.c._orig Tue Dec 21 11:12:47 1999
|
||||
--- deliver.c Wed Dec 22 20:12:54 1999
|
||||
***************
|
||||
*** 1753,1758 ****
|
||||
--- 1753,1759 ----
|
||||
case 'Q':
|
||||
if (!strcasecmp(buf, "quit")) {
|
||||
prot_printf(deliver_out,"221 2.0.0 bye\r\n");
|
||||
+ prot_flush(deliver_out);
|
||||
exit(0);
|
||||
}
|
||||
goto syntaxerr;
|
||||
|
||||
|
||||
|
50
postfix/lmtp/README.local
Normal file
50
postfix/lmtp/README.local
Normal file
@ -0,0 +1,50 @@
|
||||
README.local
|
||||
|
||||
This file describes how to use the lmtp service for local delivery.
|
||||
You'll need postfix-19991231-pl04 or later for this to work because
|
||||
it relies on the "spawn" service.
|
||||
|
||||
Configure your Postfix as follows:
|
||||
|
||||
/etc/postfix/master.cf:
|
||||
|
||||
#local unix - n n - - local
|
||||
local unix - - n - - lmtp
|
||||
serv=unix:private/lmtpd
|
||||
lmtpd unix - n n - - spawn
|
||||
user=cyrus:cyrus argv=/usr/local/cyrus/bin/deliver -e -l
|
||||
|
||||
|
||||
First, we comment out the original "local" service and define
|
||||
a new one based on the "lmtp" client. The "serv=" argument says
|
||||
what LMTP server we're to talk to, in this case the "lmtpd"
|
||||
service.
|
||||
|
||||
The `-l' option to deliver tells it to go into LMTP mode, and the
|
||||
`-e' tells it to use the duplicate delivery database, which is
|
||||
required in order to use the vacation features of Sieve, the
|
||||
filtering language in Cyrus 1.6.X.
|
||||
|
||||
A note about spawn, this is a new experimental service. The
|
||||
makefile-patch included with this bundle will add spawn to the
|
||||
compile targets. However, you may need to check that it actually
|
||||
gets installed.
|
||||
|
||||
A note about local delivery and the number of recipients. Starting
|
||||
with postfix-19991231-pl04, it is now possible to specify the
|
||||
maximum number of recipients per message for local delivery. By
|
||||
default, this is set to 1 as follows:
|
||||
|
||||
local_destination_recipient_limit = 1
|
||||
|
||||
You can set it to zero (means no limit) or, safer, set it to some
|
||||
reasonable number so that your machine doesn't risk running out of
|
||||
resources on a message with an inordinate number of recipients.
|
||||
|
||||
Why is this of interest? Well, if a message contains multiple
|
||||
recipients, and all these recipients happen to be on the same Cyrus
|
||||
partition, then recent (1.6.X) releases of deliver will hard link
|
||||
the message to each recipient instead of each recipient getting a
|
||||
copy. So you'll probably want to set the above mail.cf value to
|
||||
something reasonable to take advantage of this feature in Cyrus.
|
||||
|
5
postfix/lmtp/fixnames
Normal file
5
postfix/lmtp/fixnames
Normal file
@ -0,0 +1,5 @@
|
||||
sed '
|
||||
s/LMTP/SMTP/g
|
||||
s/lmtp/smtp/g
|
||||
s/host/namaddr/g
|
||||
' $*
|
65
postfix/lmtp/global-patch
Normal file
65
postfix/lmtp/global-patch
Normal file
@ -0,0 +1,65 @@
|
||||
*** ../../orig/global/mail_params.h Thu Jan 27 20:05:29 2000
|
||||
--- global/mail_params.h Wed Feb 23 01:26:01 2000
|
||||
***************
|
||||
*** 624,629 ****
|
||||
--- 624,683 ----
|
||||
extern int var_smtpd_err_sleep;
|
||||
|
||||
/*
|
||||
+ * LMTP client. Timeouts inspired by RFC 1123. The LMTP recipient limit
|
||||
+ * determines how many recipient addresses the LMTP client sends along with
|
||||
+ * each message. Unfortunately, some mailers misbehave and disconnect (smap)
|
||||
+ * when given more recipients than they are willing to handle.
|
||||
+ */
|
||||
+ #define VAR_LMTP_TCP_PORT "lmtp_tcp_port"
|
||||
+ #define DEF_LMTP_TCP_PORT 24
|
||||
+ extern int var_lmtp_tcp_port;
|
||||
+
|
||||
+ #define VAR_LMTP_CACHE_CONN "lmtp_cache_connection"
|
||||
+ #define DEF_LMTP_CACHE_CONN 1
|
||||
+ extern bool var_lmtp_cache_conn;
|
||||
+
|
||||
+ #define VAR_LMTP_SKIP_QUIT_RESP "lmtp_skip_quit_response"
|
||||
+ #define DEF_LMTP_SKIP_QUIT_RESP 0
|
||||
+ extern bool var_lmtp_skip_quit_resp;
|
||||
+
|
||||
+ #define VAR_LMTP_CONN_TMOUT "lmtp_connect_timeout"
|
||||
+ #define DEF_LMTP_CONN_TMOUT 0
|
||||
+ extern int var_lmtp_conn_tmout;
|
||||
+
|
||||
+ #define VAR_LMTP_RSET_TMOUT "lmtp_rset_timeout"
|
||||
+ #define DEF_LMTP_RSET_TMOUT 300
|
||||
+ extern int var_lmtp_rset_tmout;
|
||||
+
|
||||
+ #define VAR_LMTP_LHLO_TMOUT "lmtp_lhlo_timeout"
|
||||
+ #define DEF_LMTP_LHLO_TMOUT 300
|
||||
+ extern int var_lmtp_lhlo_tmout;
|
||||
+
|
||||
+ #define VAR_LMTP_MAIL_TMOUT "lmtp_mail_timeout"
|
||||
+ #define DEF_LMTP_MAIL_TMOUT 300
|
||||
+ extern int var_lmtp_mail_tmout;
|
||||
+
|
||||
+ #define VAR_LMTP_RCPT_TMOUT "lmtp_rcpt_timeout"
|
||||
+ #define DEF_LMTP_RCPT_TMOUT 300
|
||||
+ extern int var_lmtp_rcpt_tmout;
|
||||
+
|
||||
+ #define VAR_LMTP_DATA0_TMOUT "lmtp_data_init_timeout"
|
||||
+ #define DEF_LMTP_DATA0_TMOUT 120
|
||||
+ extern int var_lmtp_data0_tmout;
|
||||
+
|
||||
+ #define VAR_LMTP_DATA1_TMOUT "lmtp_data_xfer_timeout"
|
||||
+ #define DEF_LMTP_DATA1_TMOUT 180
|
||||
+ extern int var_lmtp_data1_tmout;
|
||||
+
|
||||
+ #define VAR_LMTP_DATA2_TMOUT "lmtp_data_done_timeout"
|
||||
+ #define DEF_LMTP_DATA2_TMOUT 600
|
||||
+ extern int var_lmtp_data2_tmout;
|
||||
+
|
||||
+ #define VAR_LMTP_QUIT_TMOUT "lmtp_quit_timeout"
|
||||
+ #define DEF_LMTP_QUIT_TMOUT 300
|
||||
+ extern int var_lmtp_quit_tmout;
|
||||
+
|
||||
+ /*
|
||||
* Cleanup service. Header info that exceeds $header_size_limit bytes forces
|
||||
* the start of the message body.
|
||||
*/
|
608
postfix/lmtp/lmtp.c
Normal file
608
postfix/lmtp/lmtp.c
Normal file
@ -0,0 +1,608 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp 8
|
||||
/* SUMMARY
|
||||
/* Postfix local delivery via LMTP
|
||||
/* SYNOPSIS
|
||||
/* \fBlmtp\fR [generic Postfix daemon options] [server attributes...]
|
||||
/* DESCRIPTION
|
||||
/* The LMTP client processes message delivery requests from
|
||||
/* the queue manager. Each request specifies a queue file, a sender
|
||||
/* address, a domain or host to deliver to, and recipient information.
|
||||
/* This program expects to be run from the \fBmaster\fR(8) process
|
||||
/* manager.
|
||||
/*
|
||||
/* The LMTP client updates the queue file and marks recipients
|
||||
/* as finished, or it informs the queue manager that delivery should
|
||||
/* be tried again at a later time. Delivery problem reports are sent
|
||||
/* to the \fBbounce\fR(8) or \fBdefer\fR(8) daemon as appropriate.
|
||||
/*
|
||||
/* There are two basic modes of operation for the LMTP client:
|
||||
/* .IP \(bu
|
||||
/* Communication with a local LMTP server via UNIX domain sockets.
|
||||
/* .IP \(bu
|
||||
/* Communication with a (possibly remote) LMTP server via
|
||||
/* Internet sockets.
|
||||
/* .PP
|
||||
/* If no server attributes are specified, the LMTP client will contact
|
||||
/* the destination host derived from the message delivery request using
|
||||
/* the TCP port defined as \fBlmtp\fR in \fBservices\fR(4). If no such
|
||||
/* service is found, the \fBlmtp_tcp_port\fR configuration parameter
|
||||
/* (default value of 24) will be used.
|
||||
/*
|
||||
/* In order to use a local LMTP server, this LMTP server will need to
|
||||
/* be specified via the server attributes described in the following
|
||||
/* section. Typically, the LMTP client would also be configured as the
|
||||
/* \fBlocal\fR delivery agent in the \fBmaster.cf\fR file.
|
||||
/* SERVER ATTRIBUTE SYNTAX
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The server attributes are given in the \fBmaster.cf\fR file at
|
||||
/* the end of a service definition. The syntax is as follows:
|
||||
/* .IP "\fBserv\fR=\fItype\fR:\fIserver\fR"
|
||||
/* The LMTP server to connect to for final delivery. The \fItype\fR
|
||||
/* portion can be either \fBunix\fR or \fBinet\fR. The \fIserver\fR
|
||||
/* portion is the path or address of the LMTP server, depending on the
|
||||
/* value of \fItype\fR, as shown below:
|
||||
/* .RS
|
||||
/* .IP "\fBserv=unix:\fR\fIclass\fR\fB/\fR\fIservname\fR"
|
||||
/* This specifies that the local LMTP server \fIservname\fR should be
|
||||
/* contacted for final delivery. Both \fIclass\fR (either \fBpublic\fR
|
||||
/* or \fBprivate\fR) and \fIservname\fR correspond to the LMTP server
|
||||
/* entry in the \fBmaster.cf\fR file. This LMTP server will likely
|
||||
/* be defined as a \fBspawn\fR(8) service.
|
||||
/* .IP "\fBserv=inet:"
|
||||
/* If nothing follows the \fBinet:\fR type specifier, a connection will
|
||||
/* be attempted to the destination host indicated in the delivery request.
|
||||
/* This simplest case is identical to defining the LMTP client without
|
||||
/* any server attributes at all.
|
||||
/* .IP "\fBserv=inet:\fR\fIaddress\fR"
|
||||
/* In this case, an Internet socket will be made to the server
|
||||
/* specified by \fIaddress\fR. The connection will use a destination
|
||||
/* port as described in the previous section.
|
||||
/* .IP "\fBserv=inet:\fR\fIaddress\fR\fB:\fR\fIport\fR"
|
||||
/* Connect to the LMTP server at \fIaddress\fR, but this time use port
|
||||
/* \fIport\fR instead of the default \fBlmtp\fR port.
|
||||
/* .IP "\fBserv=inet:[\fR\fIipaddr\fR\fB]\fR"
|
||||
/* The LMTP server to contact is specified using an Internet address
|
||||
/* in the "dot notation". That is, the numeric IP address rather
|
||||
/* than the DNS name for the server. The default \fBlmtp\fR port
|
||||
/* is used.
|
||||
/* .IP "\fBserv=inet:[\fR\fIipaddr\fR\fB]:\fR\fIport\fR"
|
||||
/* The LMTP server to contact is specified using the numeric IP address,
|
||||
/* at the port specified.
|
||||
/* .RE
|
||||
/* .PP
|
||||
/* SECURITY
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The LMTP client is moderately security-sensitive. It talks to LMTP
|
||||
/* servers and to DNS servers on the network. The LMTP client can be
|
||||
/* run chrooted at fixed low privilege.
|
||||
/* STANDARDS
|
||||
/* RFC 2033 (LMTP protocol)
|
||||
/* RFC 821 (SMTP protocol)
|
||||
/* RFC 1651 (SMTP service extensions)
|
||||
/* RFC 1870 (Message Size Declaration)
|
||||
/* RFC 2197 (Pipelining)
|
||||
/* DIAGNOSTICS
|
||||
/* Problems and transactions are logged to \fBsyslogd\fR(8).
|
||||
/* Corrupted message files are marked so that the queue manager can
|
||||
/* move them to the \fBcorrupt\fR queue for further inspection.
|
||||
/*
|
||||
/* Depending on the setting of the \fBnotify_classes\fR parameter,
|
||||
/* the postmaster is notified of bounces, protocol problems, and of
|
||||
/* other trouble.
|
||||
/* BUGS
|
||||
/* CONFIGURATION PARAMETERS
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The following \fBmain.cf\fR parameters are especially relevant to
|
||||
/* this program. See the Postfix \fBmain.cf\fR file for syntax details
|
||||
/* and for default values. Use the \fBpostfix reload\fR command after
|
||||
/* a configuration change.
|
||||
/* .SH Miscellaneous
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* .IP \fBdebug_peer_level\fR
|
||||
/* Verbose logging level increment for hosts that match a
|
||||
/* pattern in the \fBdebug_peer_list\fR parameter.
|
||||
/* .IP \fBdebug_peer_list\fR
|
||||
/* List of domain or network patterns. When a remote host matches
|
||||
/* a pattern, increase the verbose logging level by the amount
|
||||
/* specified in the \fBdebug_peer_level\fR parameter.
|
||||
/* .IP \fBerror_notice_recipient\fR
|
||||
/* Recipient of protocol/policy/resource/software error notices.
|
||||
/* .IP \fBnotify_classes\fR
|
||||
/* When this parameter includes the \fBprotocol\fR class, send mail to the
|
||||
/* postmaster with transcripts of LMTP sessions with protocol errors.
|
||||
/* .IP \fBlmtp_skip_quit_response\fR
|
||||
/* Do not wait for the server response after sending QUIT.
|
||||
/* .IP \fBlmtp_tcp_port\fR
|
||||
/* The TCP port to be used when connecting to a LMTP server. Used as
|
||||
/* backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
|
||||
/* .SH "Resource controls"
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* .IP \fBlmtp_cache_connection\fR
|
||||
/* Should we cache the connection to the LMTP server? The effectiveness
|
||||
/* of cached connections will be determined by the number of LMTP servers
|
||||
/* in use, and the concurrency limit specified for the LMTP client.
|
||||
/* Cached connections are closed under any of the following conditions:
|
||||
/* .RS
|
||||
/* .IP \(bu
|
||||
/* The idle timeout for the LMTP client is reached. This limit is
|
||||
/* enforced by \fBmaster\fR(8).
|
||||
/* .IP \(bu
|
||||
/* A message request to a different destination than the one currently
|
||||
/* cached.
|
||||
/* .IP \(bu
|
||||
/* The maximum number of requests per session is reached. This limit is
|
||||
/* enforced by \fBmaster\fR(8).
|
||||
/* .IP \(bu
|
||||
/* Upon the onset of another delivery request, the LMTP server associated
|
||||
/* with the current session does not respond to the \fBRSET\fR command.
|
||||
/* .RE
|
||||
/* .IP \fBlmtp_destination_concurrency_limit\fR
|
||||
/* Limit the number of parallel deliveries to the same destination.
|
||||
/* The default limit is taken from the
|
||||
/* \fBdefault_destination_concurrency_limit\fR parameter.
|
||||
/* .IP \fBlmtp_destination_recipient_limit\fR
|
||||
/* Limit the number of recipients per message delivery.
|
||||
/* The default limit is taken from the
|
||||
/* \fBdefault_destination_recipient_limit\fR parameter.
|
||||
/* .IP \fBlocal_destination_recipient_limit\fR
|
||||
/* Limit the number of recipients per message delivery.
|
||||
/* The default limit is taken from the
|
||||
/* \fBdefault_destination_recipient_limit\fR parameter.
|
||||
/*
|
||||
/* This parameter becomes significant if the LMTP client is used
|
||||
/* for local delivery. Some LMTP servers can optimize final delivery
|
||||
/* if multiple recipients are allowed. Therefore, it may be advantageous
|
||||
/* to set this to some number greater than one, depending on the capabilities
|
||||
/* of the machine.
|
||||
/*
|
||||
/* Setting this parameter to 0 will lead to an unlimited number of
|
||||
/* recipients per delivery. However, this could be risky since it may
|
||||
/* make the machine vulnerable to running out of resources if messages
|
||||
/* are encountered with an inordinate number of recipients. Exercise
|
||||
/* care when setting this parameter.
|
||||
/* .SH "Timeout controls"
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* .IP \fBlmtp_connect_timeout\fR
|
||||
/* Timeout in seconds for opening a connection to the LMTP server.
|
||||
/* If no connection can be made within the deadline, the message
|
||||
/* is deferred.
|
||||
/* .IP \fBlmtp_lhlo_timeout\fR
|
||||
/* Timeout in seconds for sending the \fBLHLO\fR command, and for
|
||||
/* receiving the server response.
|
||||
/* .IP \fBlmtp_mail_timeout\fR
|
||||
/* Timeout in seconds for sending the \fBMAIL FROM\fR command, and for
|
||||
/* receiving the server response.
|
||||
/* .IP \fBlmtp_rcpt_timeout\fR
|
||||
/* Timeout in seconds for sending the \fBRCPT TO\fR command, and for
|
||||
/* receiving the server response.
|
||||
/* .IP \fBlmtp_data_init_timeout\fR
|
||||
/* Timeout in seconds for sending the \fBDATA\fR command, and for
|
||||
/* receiving the server response.
|
||||
/* .IP \fBlmtp_data_xfer_timeout\fR
|
||||
/* Timeout in seconds for sending the message content.
|
||||
/* .IP \fBlmtp_data_done_timeout\fR
|
||||
/* Timeout in seconds for sending the "\fB.\fR" command, and for
|
||||
/* receiving the server response. When no response is received, a
|
||||
/* warning is logged that the mail may be delivered multiple times.
|
||||
/* .IP \fBlmtp_rset_timeout\fR
|
||||
/* Timeout in seconds for sending the \fBRSET\fR command, and for
|
||||
/* receiving the server response.
|
||||
/* .IP \fBlmtp_quit_timeout\fR
|
||||
/* Timeout in seconds for sending the \fBQUIT\fR command, and for
|
||||
/* receiving the server response.
|
||||
/* SEE ALSO
|
||||
/* bounce(8) non-delivery status reports
|
||||
/* local(8) local mail delivery
|
||||
/* master(8) process manager
|
||||
/* qmgr(8) queue manager
|
||||
/* services(4) Internet services and aliases
|
||||
/* spawn(8) auxiliary command spawner
|
||||
/* syslogd(8) system logging
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <dict.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <argv.h>
|
||||
#include <mymalloc.h>
|
||||
#include <name_mask.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <deliver_request.h>
|
||||
#include <mail_queue.h>
|
||||
#include <mail_params.h>
|
||||
#include <mail_conf.h>
|
||||
#include <debug_peer.h>
|
||||
#include <mail_error.h>
|
||||
|
||||
/* Single server skeleton. */
|
||||
|
||||
#include <mail_server.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "lmtp.h"
|
||||
|
||||
/*
|
||||
* Tunable parameters. These have compiled-in defaults that can be overruled
|
||||
* by settings in the global Postfix configuration file.
|
||||
*/
|
||||
int var_lmtp_tcp_port;
|
||||
int var_lmtp_conn_tmout;
|
||||
int var_lmtp_rset_tmout;
|
||||
int var_lmtp_lhlo_tmout;
|
||||
int var_lmtp_mail_tmout;
|
||||
int var_lmtp_rcpt_tmout;
|
||||
int var_lmtp_data0_tmout;
|
||||
int var_lmtp_data1_tmout;
|
||||
int var_lmtp_data2_tmout;
|
||||
int var_lmtp_quit_tmout;
|
||||
char *var_debug_peer_list;
|
||||
int var_debug_peer_level;
|
||||
int var_lmtp_cache_conn;
|
||||
int var_lmtp_skip_quit_resp;
|
||||
char *var_notify_classes;
|
||||
char *var_error_rcpt;
|
||||
|
||||
/*
|
||||
* Global variables.
|
||||
*
|
||||
* lmtp_errno is set by the address lookup routines and by the connection
|
||||
* management routines.
|
||||
*
|
||||
* state is global for the connection caching to work.
|
||||
*/
|
||||
int lmtp_errno;
|
||||
static LMTP_STATE *state = 0;
|
||||
|
||||
|
||||
/* get_service_attr - get command-line attributes */
|
||||
|
||||
static LMTP_ATTR *get_service_attr(char **argv)
|
||||
{
|
||||
char *myname = "get_service_attr";
|
||||
LMTP_ATTR *attr = (LMTP_ATTR *) mymalloc(sizeof(*attr));
|
||||
char *type;
|
||||
char *dest;
|
||||
char *name;
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
attr->type = 0;
|
||||
attr->class = "";
|
||||
attr->name = "";
|
||||
|
||||
/*
|
||||
* Iterate over the command-line attribute list.
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("%s: checking argv for lmtp server", myname);
|
||||
|
||||
for ( /* void */ ; *argv != 0; argv++) {
|
||||
|
||||
/*
|
||||
* Are we configured to speak to a particular LMTP server?
|
||||
*/
|
||||
if (strncasecmp("serv=", *argv, sizeof("serv=") - 1) == 0) {
|
||||
type = *argv + sizeof("serv=") - 1;
|
||||
if ((dest = split_at(type, ':')) == 0) /* XXX clobbers argv */
|
||||
msg_fatal("%s: invalid serv= arguments: %s", myname, *argv);
|
||||
|
||||
/*
|
||||
* What kind of socket connection are we to make?
|
||||
*/
|
||||
if (strcasecmp("unix", type) == 0) {
|
||||
attr->type = LMTP_SERV_TYPE_UNIX;
|
||||
attr->class = dest;
|
||||
if ((name = split_at(dest, '/')) == 0) /* XXX clobbers argv */
|
||||
msg_fatal("%s: invalid serv= arguments: %s", myname, *argv);
|
||||
attr->name = name;
|
||||
} else if (strcasecmp("inet", type) == 0) {
|
||||
attr->type = LMTP_SERV_TYPE_INET;
|
||||
attr->name = dest;
|
||||
} else
|
||||
msg_fatal("%s: invalid serv= arguments: %s", myname, *argv);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Bad.
|
||||
*/
|
||||
else
|
||||
msg_fatal("%s: unknown attribute name: %s", myname, *argv);
|
||||
}
|
||||
|
||||
/*
|
||||
* Give the poor tester a clue of what is going on.
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("%s: type %d, class \"%s\", name \"%s\".", myname,
|
||||
attr->type, attr->class, attr->name);
|
||||
return (attr);
|
||||
}
|
||||
|
||||
/* deliver_message - deliver message with extreme prejudice */
|
||||
|
||||
static int deliver_message(DELIVER_REQUEST *request, char **argv)
|
||||
{
|
||||
char *myname = "deliver_message";
|
||||
static LMTP_ATTR *attr = 0;
|
||||
VSTRING *why;
|
||||
int result;
|
||||
|
||||
/*
|
||||
* Macro for readability. We're going to the same destination if the
|
||||
* destination was specified on the command line (attr->name is not
|
||||
* null), or if the destination of the current session is the same as
|
||||
* request->nexthop.
|
||||
*/
|
||||
#define SAME_DESTINATION() \
|
||||
(*(attr)->name \
|
||||
|| strcasecmp(state->session->destination, request->nexthop) == 0)
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: from %s", myname, request->sender);
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (attr == 0)
|
||||
attr = get_service_attr(argv);
|
||||
if (request->rcpt_list.len <= 0)
|
||||
msg_fatal("%s: recipient count: %d", myname, request->rcpt_list.len);
|
||||
|
||||
/*
|
||||
* Initialize. Bundle all information about the delivery request, so that
|
||||
* we can produce understandable diagnostics when something goes wrong
|
||||
* many levels below. The alternative would be to make everything global.
|
||||
*
|
||||
* Note: `state' is global (to this file) so that we can close a cached
|
||||
* connection via the MAIL_SERVER_EXIT function (cleanup). The alloc for
|
||||
* `state' is performed in the MAIL_SERVER_PRE_INIT function (pre_init).
|
||||
*
|
||||
*/
|
||||
why = vstring_alloc(100);
|
||||
state->request = request;
|
||||
state->src = request->fp;
|
||||
|
||||
/*
|
||||
* See if we can reuse an existing connection.
|
||||
*/
|
||||
if (state->session != 0) {
|
||||
|
||||
/*
|
||||
* Session already exists from a previous delivery. If we're not
|
||||
* going to the same destination as before, disconnect and establish
|
||||
* a connection to the specified destination.
|
||||
*/
|
||||
if (!SAME_DESTINATION()) {
|
||||
lmtp_quit(state);
|
||||
lmtp_chat_reset(state);
|
||||
lmtp_session_reset(state);
|
||||
debug_peer_restore();
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe the session by sending RSET. If the connection is broken,
|
||||
* clean up our side of the connection.
|
||||
*/
|
||||
else if (lmtp_rset(state) != 0) {
|
||||
lmtp_chat_reset(state);
|
||||
lmtp_session_reset(state);
|
||||
debug_peer_restore();
|
||||
}
|
||||
|
||||
/*
|
||||
* Ready to go with another load.
|
||||
*/
|
||||
else {
|
||||
++state->reuse;
|
||||
if (msg_verbose)
|
||||
msg_info("%s: reusing (count %d) session with: %s",
|
||||
myname, state->reuse, state->session->host);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If no LMTP session exists, establish one.
|
||||
*/
|
||||
if (state->session == 0) {
|
||||
|
||||
/*
|
||||
* Bounce or defer the recipients if no connection can be made.
|
||||
*/
|
||||
state->session = lmtp_connect(attr, request, why);
|
||||
if (state->session == 0) {
|
||||
lmtp_site_fail(state, lmtp_errno == LMTP_RETRY ? 450 : 550,
|
||||
"%s", vstring_str(why));
|
||||
}
|
||||
|
||||
/*
|
||||
* Further check connection by sending the LHLO greeting. If we
|
||||
* cannot talk LMTP to this destination give up, at least for now.
|
||||
*/
|
||||
else {
|
||||
debug_peer_check(state->session->host, state->session->addr);
|
||||
if (lmtp_lhlo(state) != 0) {
|
||||
lmtp_session_reset(state);
|
||||
debug_peer_restore();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* If a session exists, deliver this message to all requested recipients.
|
||||
*
|
||||
*/
|
||||
if (state->session != 0)
|
||||
lmtp_xfer(state);
|
||||
|
||||
/*
|
||||
* At the end, notify the postmaster of any protocol errors.
|
||||
*/
|
||||
if (state->history != 0
|
||||
&& (state->error_mask
|
||||
& name_mask(mail_error_masks, var_notify_classes)))
|
||||
lmtp_chat_notify(state);
|
||||
|
||||
/*
|
||||
* Disconnect if we're not cacheing connections.
|
||||
*/
|
||||
if (!var_lmtp_cache_conn && state->session != 0) {
|
||||
lmtp_quit(state);
|
||||
lmtp_session_reset(state);
|
||||
debug_peer_restore();
|
||||
}
|
||||
|
||||
/*
|
||||
* Clean up.
|
||||
*/
|
||||
vstring_free(why);
|
||||
result = state->status;
|
||||
lmtp_chat_reset(state);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
/* lmtp_service - perform service for client */
|
||||
|
||||
static void lmtp_service(VSTREAM *client_stream, char *unused_service, char **argv)
|
||||
{
|
||||
DELIVER_REQUEST *request;
|
||||
int status;
|
||||
|
||||
/*
|
||||
* This routine runs whenever a client connects to the UNIX-domain socket
|
||||
* dedicated to remote LMTP delivery service. What we see below is a
|
||||
* little protocol to (1) tell the queue manager that we are ready, (2)
|
||||
* read a request from the queue manager, and (3) report the completion
|
||||
* status of that request. All connection-management stuff is handled by
|
||||
* the common code in single_server.c.
|
||||
*/
|
||||
if ((request = deliver_request_read(client_stream)) != 0) {
|
||||
status = deliver_message(request, argv);
|
||||
deliver_request_done(client_stream, request, status);
|
||||
}
|
||||
}
|
||||
|
||||
/* pre_init - pre-jail initialization */
|
||||
|
||||
static void pre_init(char *unused_name, char **unused_argv)
|
||||
{
|
||||
debug_peer_init();
|
||||
state = lmtp_state_alloc();
|
||||
}
|
||||
|
||||
/* cleanup - close any open connections, etc. */
|
||||
|
||||
static void cleanup()
|
||||
{
|
||||
if (state == 0)
|
||||
return;
|
||||
|
||||
if (state->session != 0) {
|
||||
lmtp_quit(state);
|
||||
lmtp_chat_reset(state);
|
||||
lmtp_session_free(state->session);
|
||||
debug_peer_restore();
|
||||
if (msg_verbose)
|
||||
msg_info("cleanup: just closed down session");
|
||||
}
|
||||
lmtp_state_free(state);
|
||||
}
|
||||
|
||||
/* pre_accept - see if tables have changed
|
||||
|
||||
static void pre_accept(char *unused_name, char **unused_argv)
|
||||
{
|
||||
if (dict_changed()) {
|
||||
msg_info("table has changed -- exiting");
|
||||
cleanup();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
main - pass control to the single-threaded skeleton
|
||||
*/
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
static CONFIG_STR_TABLE str_table[] = {
|
||||
VAR_DEBUG_PEER_LIST, DEF_DEBUG_PEER_LIST, &var_debug_peer_list, 0, 0,
|
||||
VAR_NOTIFY_CLASSES, DEF_NOTIFY_CLASSES, &var_notify_classes, 0, 0,
|
||||
VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
|
||||
0,
|
||||
};
|
||||
static CONFIG_INT_TABLE int_table[] = {
|
||||
VAR_LMTP_TCP_PORT, DEF_LMTP_TCP_PORT, &var_lmtp_tcp_port, 0, 0,
|
||||
VAR_LMTP_CONN_TMOUT, DEF_LMTP_CONN_TMOUT, &var_lmtp_conn_tmout, 0, 0,
|
||||
VAR_LMTP_RSET_TMOUT, DEF_LMTP_RSET_TMOUT, &var_lmtp_rset_tmout, 1, 0,
|
||||
VAR_LMTP_LHLO_TMOUT, DEF_LMTP_LHLO_TMOUT, &var_lmtp_lhlo_tmout, 1, 0,
|
||||
VAR_LMTP_MAIL_TMOUT, DEF_LMTP_MAIL_TMOUT, &var_lmtp_mail_tmout, 1, 0,
|
||||
VAR_LMTP_RCPT_TMOUT, DEF_LMTP_RCPT_TMOUT, &var_lmtp_rcpt_tmout, 1, 0,
|
||||
VAR_LMTP_DATA0_TMOUT, DEF_LMTP_DATA0_TMOUT, &var_lmtp_data0_tmout, 1, 0,
|
||||
VAR_LMTP_DATA1_TMOUT, DEF_LMTP_DATA1_TMOUT, &var_lmtp_data1_tmout, 1, 0,
|
||||
VAR_LMTP_DATA2_TMOUT, DEF_LMTP_DATA2_TMOUT, &var_lmtp_data2_tmout, 1, 0,
|
||||
VAR_LMTP_QUIT_TMOUT, DEF_LMTP_QUIT_TMOUT, &var_lmtp_quit_tmout, 1, 0,
|
||||
VAR_DEBUG_PEER_LEVEL, DEF_DEBUG_PEER_LEVEL, &var_debug_peer_level, 1, 0,
|
||||
0,
|
||||
};
|
||||
static CONFIG_BOOL_TABLE bool_table[] = {
|
||||
VAR_LMTP_CACHE_CONN, DEF_LMTP_CACHE_CONN, &var_lmtp_cache_conn,
|
||||
VAR_LMTP_SKIP_QUIT_RESP, DEF_LMTP_SKIP_QUIT_RESP, &var_lmtp_skip_quit_resp,
|
||||
0,
|
||||
};
|
||||
|
||||
single_server_main(argc, argv, lmtp_service,
|
||||
MAIL_SERVER_INT_TABLE, int_table,
|
||||
MAIL_SERVER_STR_TABLE, str_table,
|
||||
MAIL_SERVER_BOOL_TABLE, bool_table,
|
||||
MAIL_SERVER_PRE_INIT, pre_init,
|
||||
MAIL_SERVER_PRE_ACCEPT, pre_accept,
|
||||
MAIL_SERVER_EXIT, cleanup,
|
||||
0);
|
||||
}
|
155
postfix/lmtp/lmtp.h
Normal file
155
postfix/lmtp/lmtp.h
Normal file
@ -0,0 +1,155 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp 3h
|
||||
/* SUMMARY
|
||||
/* lmtp client program
|
||||
/* SYNOPSIS
|
||||
/* #include "lmtp.h"
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* Utility library.
|
||||
*/
|
||||
#include <vstream.h>
|
||||
#include <vstring.h>
|
||||
#include <argv.h>
|
||||
|
||||
/*
|
||||
* Global library.
|
||||
*/
|
||||
#include <deliver_request.h>
|
||||
|
||||
/*
|
||||
* State information associated with each LMTP delivery. We're bundling the
|
||||
* state so that we can give meaningful diagnostics in case of problems.
|
||||
*/
|
||||
typedef struct LMTP_STATE {
|
||||
VSTREAM *src; /* queue file stream */
|
||||
DELIVER_REQUEST *request; /* envelope info, offsets */
|
||||
struct LMTP_SESSION *session; /* network connection */
|
||||
VSTRING *buffer; /* I/O buffer */
|
||||
VSTRING *scratch; /* scratch buffer */
|
||||
VSTRING *scratch2; /* scratch buffer */
|
||||
int status; /* delivery status */
|
||||
int features; /* server features */
|
||||
ARGV *history; /* transaction log */
|
||||
int error_mask; /* error classes */
|
||||
int sndbufsize; /* total window size */
|
||||
int sndbuffree; /* remaining window */
|
||||
int reuse; /* connection being reused */
|
||||
} LMTP_STATE;
|
||||
|
||||
#define LMTP_FEATURE_ESMTP (1<<0)
|
||||
#define LMTP_FEATURE_8BITMIME (1<<1)
|
||||
#define LMTP_FEATURE_PIPELINING (1<<2)
|
||||
#define LMTP_FEATURE_SIZE (1<<3)
|
||||
|
||||
/*
|
||||
* lmtp.c
|
||||
*/
|
||||
extern int lmtp_errno; /* XXX can we get rid of this? */
|
||||
|
||||
/*
|
||||
* Structure for connection to LMTP server.
|
||||
*/
|
||||
typedef struct LMTP_ATTR {
|
||||
int type; /* UNIX-domain, INET, etc. */
|
||||
char *class; /* class ("public" or "private") */
|
||||
char *name; /* service endpoint name */
|
||||
} LMTP_ATTR;
|
||||
|
||||
/*
|
||||
* Service types.
|
||||
*/
|
||||
#define LMTP_SERV_TYPE_UNIX 1 /* AF_UNIX domain socket */
|
||||
#define LMTP_SERV_TYPE_INET 2 /* AF_INET domain socket */
|
||||
|
||||
/*
|
||||
* lmtp_session.c
|
||||
*/
|
||||
typedef struct LMTP_SESSION {
|
||||
VSTREAM *stream; /* network connection */
|
||||
char *host; /* mail exchanger */
|
||||
char *addr; /* mail exchanger */
|
||||
char *destination; /* domain originally sent to */
|
||||
int type; /* type of connection */
|
||||
} LMTP_SESSION;
|
||||
|
||||
extern LMTP_SESSION *lmtp_session_alloc(VSTREAM *, char *, char *);
|
||||
extern void lmtp_session_free(LMTP_SESSION *);
|
||||
extern void lmtp_session_reset(LMTP_STATE *);
|
||||
|
||||
/*
|
||||
* lmtp_connect.c
|
||||
*/
|
||||
extern LMTP_SESSION *lmtp_connect(LMTP_ATTR *, DELIVER_REQUEST *request, VSTRING *);
|
||||
extern LMTP_SESSION *lmtp_connect_host(char *, unsigned, VSTRING *);
|
||||
extern LMTP_SESSION *lmtp_connect_local(const char *, const char *, VSTRING *);
|
||||
|
||||
/*
|
||||
* lmtp_proto.c
|
||||
*/
|
||||
extern int lmtp_lhlo(LMTP_STATE *);
|
||||
extern int lmtp_xfer(LMTP_STATE *);
|
||||
extern int lmtp_quit(LMTP_STATE *);
|
||||
extern int lmtp_rset(LMTP_STATE *);
|
||||
|
||||
/*
|
||||
* lmtp_chat.c
|
||||
*/
|
||||
typedef struct LMTP_RESP { /* server response */
|
||||
int code; /* status */
|
||||
char *str; /* text */
|
||||
VSTRING *buf; /* origin of text */
|
||||
} LMTP_RESP;
|
||||
|
||||
extern void lmtp_chat_cmd(LMTP_STATE *, char *,...);
|
||||
extern LMTP_RESP *lmtp_chat_resp(LMTP_STATE *);
|
||||
extern void lmtp_chat_reset(LMTP_STATE *);
|
||||
extern void lmtp_chat_notify(LMTP_STATE *);
|
||||
|
||||
/*
|
||||
* lmtp_trouble.c
|
||||
*/
|
||||
extern int lmtp_conn_fail(LMTP_STATE *, int, char *,...);
|
||||
extern int lmtp_site_fail(LMTP_STATE *, int, char *,...);
|
||||
extern int lmtp_mesg_fail(LMTP_STATE *, int, char *,...);
|
||||
extern void lmtp_rcpt_fail(LMTP_STATE *, int, RECIPIENT *, char *,...);
|
||||
extern int lmtp_stream_except(LMTP_STATE *, int, char *);
|
||||
|
||||
/*
|
||||
* lmtp_state.c
|
||||
*/
|
||||
extern LMTP_STATE *lmtp_state_alloc(void);
|
||||
extern void lmtp_state_free(LMTP_STATE *);
|
||||
|
||||
/*
|
||||
* Status codes. Errors must have negative codes so that they do not
|
||||
* interfere with useful counts of work done.
|
||||
*/
|
||||
#define LMTP_OK 0 /* so far, so good */
|
||||
#define LMTP_RETRY (-1) /* transient error */
|
||||
#define LMTP_FAIL (-2) /* hard error */
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
202
postfix/lmtp/lmtp_addr.c
Normal file
202
postfix/lmtp/lmtp_addr.c
Normal file
@ -0,0 +1,202 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp_addr 3
|
||||
/* SUMMARY
|
||||
/* LMTP server address lookup
|
||||
/* SYNOPSIS
|
||||
/* #include "lmtp_addr.h"
|
||||
/*
|
||||
/* DNS_RR *lmtp_host_addr(name, why)
|
||||
/* char *name;
|
||||
/* VSTRING *why;
|
||||
/* DESCRIPTION
|
||||
/* This module implements Internet address lookups. By default,
|
||||
/* lookups are done via the Internet domain name service (DNS).
|
||||
/* A reasonable number of CNAME indirections is permitted.
|
||||
/*
|
||||
/* lmtp_host_addr() looks up all addresses listed for the named
|
||||
/* host. The host can be specified as a numerical Internet network
|
||||
/* address, or as a symbolic host name.
|
||||
/*
|
||||
/* Fortunately, we don't have to worry about MX records because
|
||||
/* those are for SMTP servers, not LMTP servers.
|
||||
/*
|
||||
/* Results from lmtp_host_addr() are destroyed by dns_rr_free(),
|
||||
/* including null lists.
|
||||
/* DIAGNOSTICS
|
||||
/* This routine either returns a DNS_RR pointer, or return a null
|
||||
/* pointer and sets the \fIlmtp_errno\fR global variable accordingly:
|
||||
/* .IP LMTP_RETRY
|
||||
/* The request failed due to a soft error, and should be retried later.
|
||||
/* .IP LMTP_FAIL
|
||||
/* The request attempt failed due to a hard error.
|
||||
/* .PP
|
||||
/* In addition, a textual description of the problem is made available
|
||||
/* via the \fIwhy\fR argument.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <stdlib.h>
|
||||
#include <netdb.h>
|
||||
#include <ctype.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#ifndef INADDR_NONE
|
||||
#define INADDR_NONE 0xffffffff
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <vstring.h>
|
||||
#include <mymalloc.h>
|
||||
#include <inet_addr_list.h>
|
||||
#include <stringops.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_params.h>
|
||||
#include <own_inet_addr.h>
|
||||
|
||||
/* DNS library. */
|
||||
|
||||
#include <dns.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "lmtp.h"
|
||||
#include "lmtp_addr.h"
|
||||
|
||||
/* lmtp_print_addr - print address list */
|
||||
|
||||
static void lmtp_print_addr(char *what, DNS_RR *addr_list)
|
||||
{
|
||||
DNS_RR *addr;
|
||||
struct in_addr in_addr;
|
||||
|
||||
msg_info("begin %s address list", what);
|
||||
for (addr = addr_list; addr; addr = addr->next) {
|
||||
if (addr->data_len > sizeof(addr)) {
|
||||
msg_warn("skipping address length %d", addr->data_len);
|
||||
} else {
|
||||
memcpy((char *) &in_addr, addr->data, sizeof(in_addr));
|
||||
msg_info("pref %4d host %s/%s",
|
||||
addr->pref, addr->name,
|
||||
inet_ntoa(in_addr));
|
||||
}
|
||||
}
|
||||
msg_info("end %s address list", what);
|
||||
}
|
||||
|
||||
/* lmtp_addr_one - address lookup for one host name */
|
||||
|
||||
static DNS_RR *lmtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why)
|
||||
{
|
||||
char *myname = "lmtp_addr_one";
|
||||
struct in_addr inaddr;
|
||||
DNS_FIXED fixed;
|
||||
DNS_RR *addr = 0;
|
||||
DNS_RR *rr;
|
||||
struct hostent *hp;
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: host %s", myname, host);
|
||||
|
||||
/*
|
||||
* Interpret a numerical name as an address.
|
||||
*/
|
||||
if (ISDIGIT(host[0]) && (inaddr.s_addr = inet_addr(host)) != INADDR_NONE) {
|
||||
memset((char *) &fixed, 0, sizeof(fixed));
|
||||
return (dns_rr_append(addr_list,
|
||||
dns_rr_create(host, &fixed, pref,
|
||||
(char *) &inaddr, sizeof(inaddr))));
|
||||
}
|
||||
|
||||
/*
|
||||
* Use gethostbyname() when DNS is disabled.
|
||||
*/
|
||||
if (var_disable_dns) {
|
||||
memset((char *) &fixed, 0, sizeof(fixed));
|
||||
if ((hp = gethostbyname(host)) == 0) {
|
||||
vstring_sprintf(why, "%s: host not found", host);
|
||||
lmtp_errno = LMTP_FAIL;
|
||||
} else if (hp->h_addrtype != AF_INET) {
|
||||
vstring_sprintf(why, "%s: host not found", host);
|
||||
msg_warn("%s: unknown address family %d for %s",
|
||||
myname, hp->h_addrtype, host);
|
||||
lmtp_errno = LMTP_FAIL;
|
||||
} else {
|
||||
while (hp->h_addr_list[0]) {
|
||||
addr_list = dns_rr_append(addr_list,
|
||||
dns_rr_create(host, &fixed, pref,
|
||||
hp->h_addr_list[0],
|
||||
sizeof(inaddr)));
|
||||
hp->h_addr_list++;
|
||||
}
|
||||
}
|
||||
return (addr_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* Append the addresses for this host to the address list.
|
||||
*/
|
||||
switch (dns_lookup(host, T_A, 0, &addr, (VSTRING *) 0, why)) {
|
||||
case DNS_OK:
|
||||
for (rr = addr; rr; rr = rr->next)
|
||||
rr->pref = pref;
|
||||
addr_list = dns_rr_append(addr_list, addr);
|
||||
break;
|
||||
default:
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
break;
|
||||
case DNS_NOTFOUND:
|
||||
case DNS_FAIL:
|
||||
lmtp_errno = LMTP_FAIL;
|
||||
break;
|
||||
}
|
||||
return (addr_list);
|
||||
}
|
||||
|
||||
/* lmtp_host_addr - direct host lookup */
|
||||
|
||||
DNS_RR *lmtp_host_addr(char *host, VSTRING *why)
|
||||
{
|
||||
DNS_RR *addr_list;
|
||||
|
||||
/*
|
||||
* If the host is specified by numerical address, just convert the
|
||||
* address to internal form. Otherwise, the host is specified by name.
|
||||
*/
|
||||
#define PREF0 0
|
||||
addr_list = lmtp_addr_one((DNS_RR *) 0, host, PREF0, why);
|
||||
if (msg_verbose)
|
||||
lmtp_print_addr(host, addr_list);
|
||||
return (addr_list);
|
||||
}
|
||||
|
41
postfix/lmtp/lmtp_addr.h
Normal file
41
postfix/lmtp/lmtp_addr.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp_addr 3h
|
||||
/* SUMMARY
|
||||
/* LMTP server address lookup
|
||||
/* SYNOPSIS
|
||||
/* #include "lmtp_addr.h"
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* DNS library.
|
||||
*/
|
||||
#include <dns.h>
|
||||
|
||||
/*
|
||||
* Internal interfaces.
|
||||
*/
|
||||
extern DNS_RR *lmtp_host_addr(char *, VSTRING *);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
285
postfix/lmtp/lmtp_chat.c
Normal file
285
postfix/lmtp/lmtp_chat.c
Normal file
@ -0,0 +1,285 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp_chat 3
|
||||
/* SUMMARY
|
||||
/* LMTP client request/response support
|
||||
/* SYNOPSIS
|
||||
/* #include "lmtp.h"
|
||||
/*
|
||||
/* typedef struct {
|
||||
/* .in +4
|
||||
/* int code;
|
||||
/* char *str;
|
||||
/* VSTRING *buf;
|
||||
/* .in -4
|
||||
/* } LMTP_RESP;
|
||||
/*
|
||||
/* void lmtp_chat_cmd(state, format, ...)
|
||||
/* LMTP_STATE *state;
|
||||
/* char *format;
|
||||
/*
|
||||
/* LMTP_RESP *lmtp_chat_resp(state)
|
||||
/* LMTP_STATE *state;
|
||||
/*
|
||||
/* void lmtp_chat_notify(state)
|
||||
/* LMTP_STATE *state;
|
||||
/*
|
||||
/* void lmtp_chat_reset(state)
|
||||
/* LMTP_STATE *state;
|
||||
/* DESCRIPTION
|
||||
/* This module implements LMTP client support for request/reply
|
||||
/* conversations, and maintains a limited LMTP transaction log.
|
||||
/*
|
||||
/* lmtp_chat_cmd() formats a command and sends it to an LMTP server.
|
||||
/* Optionally, the command is logged.
|
||||
/*
|
||||
/* lmtp_chat_resp() read one LMTP server response. It separates the
|
||||
/* numerical status code from the text, and concatenates multi-line
|
||||
/* responses to one string, using a newline as separator.
|
||||
/* Optionally, the server response is logged.
|
||||
/*
|
||||
/* lmtp_chat_notify() sends a copy of the LMTP transaction log
|
||||
/* to the postmaster for review. The postmaster notice is sent only
|
||||
/* when delivery is possible immediately. It is an error to call
|
||||
/* lmtp_chat_notify() when no LMTP transaction log exists.
|
||||
/*
|
||||
/* lmtp_chat_reset() resets the transaction log. This is
|
||||
/* typically done at the beginning or end of an LMTP session,
|
||||
/* or within a session to discard non-error information.
|
||||
/* DIAGNOSTICS
|
||||
/* Fatal errors: memory allocation problem, server response exceeds
|
||||
/* configurable limit.
|
||||
/* All other exceptions are handled by long jumps (see smtp_stream(3)).
|
||||
/* SEE ALSO
|
||||
/* smtp_stream(3) LMTP session I/O support
|
||||
/* msg(3) generic logging interface
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
|
||||
#include <stdarg.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <vstring.h>
|
||||
#include <vstream.h>
|
||||
#include <argv.h>
|
||||
#include <stringops.h>
|
||||
#include <line_wrap.h>
|
||||
#include <mymalloc.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <recipient_list.h>
|
||||
#include <deliver_request.h>
|
||||
#include <smtp_stream.h>
|
||||
#include <mail_params.h>
|
||||
#include <mail_addr.h>
|
||||
#include <post_mail.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "lmtp.h"
|
||||
|
||||
#define STR(x) ((char *) vstring_str(x))
|
||||
#define LEN VSTRING_LEN
|
||||
|
||||
/* lmtp_chat_reset - reset LMTP transaction log */
|
||||
|
||||
void lmtp_chat_reset(LMTP_STATE *state)
|
||||
{
|
||||
if (state->history) {
|
||||
argv_free(state->history);
|
||||
state->history = 0;
|
||||
}
|
||||
|
||||
/* What's status without history? */
|
||||
state->status = 0;
|
||||
state->error_mask = 0;
|
||||
}
|
||||
|
||||
/* lmtp_chat_append - append record to LMTP transaction log */
|
||||
|
||||
static void lmtp_chat_append(LMTP_STATE *state, char *direction, char *data)
|
||||
{
|
||||
char *line;
|
||||
|
||||
if (state->history == 0)
|
||||
state->history = argv_alloc(10);
|
||||
line = concatenate(direction, data, (char *) 0);
|
||||
argv_add(state->history, line, (char *) 0);
|
||||
myfree(line);
|
||||
}
|
||||
|
||||
/* lmtp_chat_cmd - send an LMTP command */
|
||||
|
||||
void lmtp_chat_cmd(LMTP_STATE *state, char *fmt,...)
|
||||
{
|
||||
LMTP_SESSION *session = state->session;
|
||||
va_list ap;
|
||||
|
||||
/*
|
||||
* Format the command, and update the transaction log.
|
||||
*/
|
||||
va_start(ap, fmt);
|
||||
vstring_vsprintf(state->buffer, fmt, ap);
|
||||
va_end(ap);
|
||||
lmtp_chat_append(state, "Out: ", STR(state->buffer));
|
||||
|
||||
/*
|
||||
* Optionally log the command first, so we can see in the log what the
|
||||
* program is trying to do.
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("> %s: %s", session->host, STR(state->buffer));
|
||||
|
||||
/*
|
||||
* Send the command to the LMTP server.
|
||||
*/
|
||||
smtp_fputs(STR(state->buffer), LEN(state->buffer), session->stream);
|
||||
}
|
||||
|
||||
/* lmtp_chat_resp - read and process LMTP server response */
|
||||
|
||||
LMTP_RESP *lmtp_chat_resp(LMTP_STATE *state)
|
||||
{
|
||||
LMTP_SESSION *session = state->session;
|
||||
static LMTP_RESP rdata;
|
||||
int more;
|
||||
char *cp;
|
||||
int last_char;
|
||||
|
||||
/*
|
||||
* Initialize the response data buffer.
|
||||
*/
|
||||
if (rdata.buf == 0)
|
||||
rdata.buf = vstring_alloc(100);
|
||||
|
||||
/*
|
||||
* Censor out non-printable characters in server responses. Concatenate
|
||||
* multi-line server responses. Separate the status code from the text.
|
||||
* Leave further parsing up to the application.
|
||||
*/
|
||||
VSTRING_RESET(rdata.buf);
|
||||
for (;;) {
|
||||
last_char = smtp_get(state->buffer, session->stream, var_line_limit);
|
||||
cp = printable(STR(state->buffer), '?');
|
||||
if (last_char != '\n')
|
||||
msg_warn("%s: response longer than %d: %.30s...",
|
||||
session->host, var_line_limit, cp);
|
||||
if (msg_verbose)
|
||||
msg_info("< %s: %s", session->host, cp);
|
||||
while (ISDIGIT(*cp))
|
||||
cp++;
|
||||
rdata.code = (cp - STR(state->buffer) == 3 ?
|
||||
atoi(STR(state->buffer)) : 0);
|
||||
more = (*cp == '-');
|
||||
|
||||
/*
|
||||
* Defend against a denial of service attack by limiting the amount
|
||||
* of multi-line text that we are willing to store.
|
||||
*/
|
||||
if (LEN(rdata.buf) < var_line_limit) {
|
||||
if (VSTRING_LEN(rdata.buf))
|
||||
VSTRING_ADDCH(rdata.buf, '\n');
|
||||
vstring_strcat(rdata.buf, STR(state->buffer));
|
||||
lmtp_chat_append(state, "In: ", STR(state->buffer));
|
||||
}
|
||||
if (VSTRING_LEN(state->buffer) == 0) /* XXX remote brain damage */
|
||||
continue;
|
||||
if (!ISDIGIT(STR(state->buffer)[0])) /* XXX remote brain damage */
|
||||
continue;
|
||||
if (more == 0)
|
||||
break;
|
||||
}
|
||||
VSTRING_TERMINATE(rdata.buf);
|
||||
rdata.str = STR(rdata.buf);
|
||||
return (&rdata);
|
||||
}
|
||||
|
||||
/* print_line - line_wrap callback */
|
||||
|
||||
static void print_line(const char *str, int len, int indent, char *context)
|
||||
{
|
||||
VSTREAM *notice = (VSTREAM *) context;
|
||||
|
||||
post_mail_fprintf(notice, " %*s%.*s", indent, "", len, str);
|
||||
}
|
||||
|
||||
/* lmtp_chat_notify - notify postmaster */
|
||||
|
||||
void lmtp_chat_notify(LMTP_STATE *state)
|
||||
{
|
||||
char *myname = "lmtp_chat_notify";
|
||||
LMTP_SESSION *session = state->session;
|
||||
VSTREAM *notice;
|
||||
char **cpp;
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (state->history == 0)
|
||||
msg_panic("%s: no conversation history", myname);
|
||||
if (msg_verbose)
|
||||
msg_info("%s: notify postmaster", myname);
|
||||
|
||||
/*
|
||||
* Construct a message for the postmaster, explaining what this is all
|
||||
* about. This is junk mail: don't send it when the mail posting service
|
||||
* is unavailable, and use the double bounce sender address, to prevent
|
||||
* mail bounce wars. Always prepend one space to message content that we
|
||||
* generate from untrusted data.
|
||||
*/
|
||||
#define NULL_CLEANUP_FLAGS 0
|
||||
#define LENGTH 78
|
||||
#define INDENT 4
|
||||
|
||||
notice = post_mail_fopen_nowait(mail_addr_double_bounce(),
|
||||
var_error_rcpt,
|
||||
NULL_CLEANUP_FLAGS, "NOTICE");
|
||||
if (notice == 0) {
|
||||
msg_warn("postmaster notify: %m");
|
||||
return;
|
||||
}
|
||||
post_mail_fprintf(notice, "From: %s (Mail Delivery System)",
|
||||
mail_addr_mail_daemon());
|
||||
post_mail_fprintf(notice, "To: %s (Postmaster)", var_error_rcpt);
|
||||
post_mail_fprintf(notice, "Subject: %s LMTP client: errors from %s",
|
||||
var_mail_name, session->host);
|
||||
post_mail_fputs(notice, "");
|
||||
post_mail_fprintf(notice, "Unexpected response from %s.", session->host);
|
||||
post_mail_fputs(notice, "");
|
||||
post_mail_fputs(notice, "Transcript of session follows.");
|
||||
post_mail_fputs(notice, "");
|
||||
argv_terminate(state->history);
|
||||
for (cpp = state->history->argv; *cpp; cpp++)
|
||||
line_wrap(printable(*cpp, '?'), LENGTH, INDENT, print_line,
|
||||
(char *) notice);
|
||||
(void) post_mail_fclose(notice);
|
||||
}
|
395
postfix/lmtp/lmtp_connect.c
Normal file
395
postfix/lmtp/lmtp_connect.c
Normal file
@ -0,0 +1,395 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp_connect 3
|
||||
/* SUMMARY
|
||||
/* connect to LMTP server
|
||||
/* SYNOPSIS
|
||||
/* #include "lmtp.h"
|
||||
/*
|
||||
/* LMTP_SESSION *lmtp_connect(destination, why)
|
||||
/* char *destination;
|
||||
/* VSTRING *why;
|
||||
/* DESCRIPTION
|
||||
/* This module implements LMTP connection management.
|
||||
/*
|
||||
/* lmtp_connect() attempts to establish an LMTP session with a host.
|
||||
/*
|
||||
/* The destination is either a host name or a numeric address.
|
||||
/* Symbolic or numeric service port information may be appended,
|
||||
/* separated by a colon (":").
|
||||
/*
|
||||
/* Numerical address information should always be quoted with `[]'.
|
||||
/*
|
||||
/* DIAGNOSTICS
|
||||
/* This routine either returns an LMTP_SESSION pointer, or
|
||||
/* returns a null pointer and set the \fIlmtp_errno\fR
|
||||
/* global variable accordingly:
|
||||
/* .IP LMTP_RETRY
|
||||
/* The connection attempt failed, but should be retried later.
|
||||
/* .IP LMTP_FAIL
|
||||
/* The connection attempt failed.
|
||||
/* .PP
|
||||
/* In addition, a textual description of the error is made available
|
||||
/* via the \fIwhy\fR argument.
|
||||
/* SEE ALSO
|
||||
/* lmtp_proto(3) LMTP client protocol
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <sys/socket.h>
|
||||
#include <netinet/in.h>
|
||||
#include <arpa/inet.h>
|
||||
#include <errno.h>
|
||||
#include <netdb.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef STRCASECMP_IN_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <vstream.h>
|
||||
#include <vstring.h>
|
||||
#include <split_at.h>
|
||||
#include <mymalloc.h>
|
||||
#include <inet_addr_list.h>
|
||||
#include <iostuff.h>
|
||||
#include <timed_connect.h>
|
||||
#include <stringops.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_params.h>
|
||||
#include <own_inet_addr.h>
|
||||
|
||||
/* DNS library. */
|
||||
|
||||
#include <dns.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "lmtp.h"
|
||||
#include "lmtp_addr.h"
|
||||
|
||||
/* lmtp_connect_addr - connect to explicit address */
|
||||
|
||||
static LMTP_SESSION *lmtp_connect_addr(DNS_RR *addr, unsigned port,
|
||||
VSTRING *why)
|
||||
{
|
||||
char *myname = "lmtp_connect_addr";
|
||||
struct sockaddr_in sin;
|
||||
int sock;
|
||||
INET_ADDR_LIST *addr_list;
|
||||
int conn_stat;
|
||||
int saved_errno;
|
||||
VSTREAM *stream;
|
||||
int ch;
|
||||
unsigned long inaddr;
|
||||
|
||||
/*
|
||||
* Sanity checks.
|
||||
*/
|
||||
if (addr->data_len > sizeof(sin.sin_addr)) {
|
||||
msg_warn("%s: skip address with length %d", myname, addr->data_len);
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
memset((char *) &sin, 0, sizeof(sin));
|
||||
sin.sin_family = AF_INET;
|
||||
|
||||
if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0)
|
||||
msg_fatal("%s: socket: %m", myname);
|
||||
|
||||
/* do we still need this if? */
|
||||
addr_list = own_inet_addr_list();
|
||||
if (addr_list->used == 1) {
|
||||
sin.sin_port = 0;
|
||||
memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr));
|
||||
inaddr = ntohl(sin.sin_addr.s_addr);
|
||||
if (!IN_CLASSA(inaddr)
|
||||
|| !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) {
|
||||
if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0)
|
||||
msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr));
|
||||
if (msg_verbose)
|
||||
msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Connect to the LMTP server.
|
||||
*/
|
||||
sin.sin_port = port;
|
||||
memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr));
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: trying: %s[%s] port %d...",
|
||||
myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port));
|
||||
if (var_lmtp_conn_tmout > 0) {
|
||||
non_blocking(sock, NON_BLOCKING);
|
||||
conn_stat = timed_connect(sock, (struct sockaddr *) & sin,
|
||||
sizeof(sin), var_lmtp_conn_tmout);
|
||||
saved_errno = errno;
|
||||
non_blocking(sock, BLOCKING);
|
||||
errno = saved_errno;
|
||||
} else {
|
||||
conn_stat = connect(sock, (struct sockaddr *) & sin, sizeof(sin));
|
||||
}
|
||||
if (conn_stat < 0) {
|
||||
vstring_sprintf(why, "connect to %s[%s]: %m",
|
||||
addr->name, inet_ntoa(sin.sin_addr));
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
close(sock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip this host if it takes no action within some time limit.
|
||||
*/
|
||||
if (read_wait(sock, var_lmtp_lhlo_tmout) < 0) {
|
||||
vstring_sprintf(why, "connect to %s[%s]: read timeout",
|
||||
addr->name, inet_ntoa(sin.sin_addr));
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
close(sock);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip this host if it disconnects without talking to us.
|
||||
*/
|
||||
stream = vstream_fdopen(sock, O_RDWR);
|
||||
if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
|
||||
vstring_sprintf(why, "connect to %s[%s]: server dropped connection",
|
||||
addr->name, inet_ntoa(sin.sin_addr));
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
vstream_fclose(stream);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip this host if it sends a 4xx greeting.
|
||||
*/
|
||||
if (ch == '4') {
|
||||
vstring_sprintf(why, "connect to %s[%s]: server refused mail service",
|
||||
addr->name, inet_ntoa(sin.sin_addr));
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
vstream_fclose(stream);
|
||||
return (0);
|
||||
}
|
||||
vstream_ungetc(stream, ch);
|
||||
return (lmtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr)));
|
||||
}
|
||||
|
||||
/* lmtp_connect_host - direct connection to host */
|
||||
|
||||
LMTP_SESSION *lmtp_connect_host(char *host, unsigned port, VSTRING *why)
|
||||
{
|
||||
LMTP_SESSION *session = 0;
|
||||
DNS_RR *addr_list;
|
||||
DNS_RR *addr;
|
||||
|
||||
/*
|
||||
* Try each address in the specified order until we find one that works.
|
||||
* The addresses belong to the same A record, so we have no information
|
||||
* on what address is "best".
|
||||
*/
|
||||
addr_list = lmtp_host_addr(host, why);
|
||||
for (addr = addr_list; addr; addr = addr->next) {
|
||||
if ((session = lmtp_connect_addr(addr, port, why)) != 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
dns_rr_free(addr_list);
|
||||
return (session);
|
||||
}
|
||||
|
||||
/* lmtp_parse_destination - parse destination */
|
||||
|
||||
static char *lmtp_parse_destination(char *destination, char *def_service,
|
||||
char **hostp, unsigned *portp)
|
||||
{
|
||||
char *myname = "lmtp_parse_destination";
|
||||
char *buf = mystrdup(destination);
|
||||
char *host = buf;
|
||||
char *service;
|
||||
struct servent *sp;
|
||||
char *protocol = "tcp"; /* XXX configurable? */
|
||||
unsigned port;
|
||||
|
||||
if (msg_verbose)
|
||||
msg_info("%s: %s %s", myname, destination, def_service);
|
||||
|
||||
/*
|
||||
* Strip quoting. We're working with a copy of the destination argument
|
||||
* so the stripping can be destructive.
|
||||
*/
|
||||
if (*host == '[') {
|
||||
host++;
|
||||
host[strcspn(host, "]")] = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Separate host and service information, or use the default service
|
||||
* specified by the caller. XXX the ":" character is used in the IPV6
|
||||
* address notation, so using split_at_right() is not sufficient. We'd
|
||||
* have to count the number of ":" instances.
|
||||
*/
|
||||
if ((service = split_at_right(host, ':')) == 0)
|
||||
service = def_service;
|
||||
if (*service == 0)
|
||||
msg_fatal("%s: empty service name: %s", myname, destination);
|
||||
*hostp = host;
|
||||
|
||||
/*
|
||||
* Convert service to port number, network byte order.
|
||||
*/
|
||||
if ((port = atoi(service)) != 0) {
|
||||
*portp = htons(port);
|
||||
} else {
|
||||
/*
|
||||
* Since most folks aren't going to have lmtp defined as a service,
|
||||
* use a default value instead of just blowing up.
|
||||
*/
|
||||
if ((sp = getservbyname(service, protocol)) == 0)
|
||||
*portp = htons(var_lmtp_tcp_port);
|
||||
else
|
||||
*portp = sp->s_port;
|
||||
}
|
||||
return (buf);
|
||||
}
|
||||
|
||||
/* lmtp_connect_local - local connect to unix domain socket */
|
||||
|
||||
LMTP_SESSION *lmtp_connect_local(const char *class, const char *name, VSTRING *why)
|
||||
{
|
||||
char *myname = "lmtp_connect_local";
|
||||
VSTREAM *stream;
|
||||
int ch;
|
||||
|
||||
/*
|
||||
* Connect to the LMTP server.
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("%s: trying: %s/%s...", myname, class, name);
|
||||
if ((stream = mail_connect_wait(class, name)) == 0) {
|
||||
vstring_sprintf(why, "connect to %s: connection failed.", name);
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip this process if it takes no action within some time limit.
|
||||
*/
|
||||
if (read_wait(vstream_fileno(stream), var_lmtp_lhlo_tmout) < 0) {
|
||||
vstring_sprintf(why, "connect to %s: read timeout", name);
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
vstream_fclose(stream);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip this process if it disconnects without talking to us.
|
||||
*/
|
||||
if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
|
||||
vstring_sprintf(why, "connect to %s: server dropped connection", name);
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
vstream_fclose(stream);
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Skip this host if it sends a 4xx greeting.
|
||||
*/
|
||||
if (ch == '4') {
|
||||
vstring_sprintf(why, "connect to %s: server refused mail service", name);
|
||||
lmtp_errno = LMTP_RETRY;
|
||||
vstream_fclose(stream);
|
||||
return (0);
|
||||
}
|
||||
vstream_ungetc(stream, ch);
|
||||
return (lmtp_session_alloc(stream, name, ""));
|
||||
}
|
||||
|
||||
/* lmtp_connect - establish LMTP connection */
|
||||
|
||||
LMTP_SESSION *lmtp_connect(LMTP_ATTR *attr, DELIVER_REQUEST *request, VSTRING *why)
|
||||
{
|
||||
char *myname = "lmtp_connect";
|
||||
LMTP_SESSION *session;
|
||||
char *dest_buf;
|
||||
char *host;
|
||||
unsigned port;
|
||||
char *def_service = "lmtp"; /* XXX configurable? */
|
||||
|
||||
/*
|
||||
* Are we connecting to a local or inet socket?
|
||||
*/
|
||||
if (attr->type == LMTP_SERV_TYPE_UNIX) {
|
||||
/*
|
||||
* Connect to local LMTP server.
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("%s: connecting to %s", myname, attr->name);
|
||||
session = lmtp_connect_local(attr->class, attr->name, why);
|
||||
if (session != 0) {
|
||||
session->destination = mystrdup(attr->name);
|
||||
session->type = attr->type;
|
||||
}
|
||||
} else {
|
||||
/*
|
||||
* Connect to LMTP server via inet socket, but where?
|
||||
*/
|
||||
if (!*(attr)->name) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: attr->name not set; using request->nexthop", myname);
|
||||
attr->name = request->nexthop;
|
||||
}
|
||||
dest_buf = lmtp_parse_destination(attr->name, def_service,
|
||||
&host, &port);
|
||||
|
||||
/*
|
||||
* Now that the inet LMTP server has been determined, connect to it.
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("%s: connecting to %s port %d", myname, host, ntohs(port));
|
||||
session = lmtp_connect_host(host, port, why);
|
||||
if (session != 0) {
|
||||
session->destination = mystrdup(attr->name);
|
||||
session->type = attr->type;
|
||||
}
|
||||
myfree(dest_buf);
|
||||
}
|
||||
return (session);
|
||||
}
|
||||
|
686
postfix/lmtp/lmtp_proto.c
Normal file
686
postfix/lmtp/lmtp_proto.c
Normal file
@ -0,0 +1,686 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp_proto 3
|
||||
/* SUMMARY
|
||||
/* client LMTP protocol
|
||||
/* SYNOPSIS
|
||||
/* #include "lmtp.h"
|
||||
/*
|
||||
/* int lmtp_lhlo(state)
|
||||
/* LMTP_STATE *state;
|
||||
/*
|
||||
/* int lmtp_xfer(state)
|
||||
/* LMTP_STATE *state;
|
||||
/*
|
||||
/* int lmtp_rset(state)
|
||||
/* LMTP_STATE *state;
|
||||
/*
|
||||
/* int lmtp_quit(state)
|
||||
/* LMTP_STATE *state;
|
||||
/* DESCRIPTION
|
||||
/* This module implements the client side of the LMTP protocol.
|
||||
/*
|
||||
/* lmtp_lhlo() performs the initial handshake with the LMTP server.
|
||||
/*
|
||||
/* lmtp_xfer() sends message envelope information followed by the
|
||||
/* message data, but does not finish the conversation. These operations
|
||||
/* are combined in one function, in order to implement LMTP pipelining.
|
||||
/* Recipients are marked as "done" in the mail queue file when
|
||||
/* bounced or delivered. The message delivery status is updated
|
||||
/* accordingly.
|
||||
/*
|
||||
/* lmtp_rset() sends an RSET command and waits for the response.
|
||||
/*
|
||||
/* lmtp_quit() sends a QUIT command and waits for the response.
|
||||
/* DIAGNOSTICS
|
||||
/* lmtp_lhlo(), lmtp_xfer(), lmtp_rset() and lmtp_quit() return 0 in
|
||||
/* case of success, -1 in case of failure. For lmtp_xfer(), lmtp_rset()
|
||||
/* and lmtp_quit(), success means the ability to perform an LMTP
|
||||
/* conversation, not necessarily OK replies from the server.
|
||||
/*
|
||||
/* Warnings: corrupt message file. A corrupt message is marked
|
||||
/* as "corrupt" by changing its queue file permissions.
|
||||
/* SEE ALSO
|
||||
/* lmtp(3h) internal data structures
|
||||
/* lmtp_chat(3) query/reply LMTP support
|
||||
/* lmtp_trouble(3) error handlers
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Pipelining code in cooperation with:
|
||||
/* Jon Ribbens
|
||||
/* Oaktree Internet Solutions Ltd.,
|
||||
/* Internet House,
|
||||
/* Canal Basin,
|
||||
/* Coventry,
|
||||
/* CV1 4LY, United Kingdom.
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h> /* shutdown(2) */
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
|
||||
#include <stdarg.h>
|
||||
|
||||
#ifdef STRCASECMP_IN_STRINGS_H
|
||||
#include <strings.h>
|
||||
#endif
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <vstring.h>
|
||||
#include <vstream.h>
|
||||
#include <vstring_vstream.h>
|
||||
#include <stringops.h>
|
||||
#include <mymalloc.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <mail_params.h>
|
||||
#include <smtp_stream.h>
|
||||
#include <mail_queue.h>
|
||||
#include <recipient_list.h>
|
||||
#include <deliver_request.h>
|
||||
#include <deliver_completed.h>
|
||||
#include <defer.h>
|
||||
#include <bounce.h>
|
||||
#include <sent.h>
|
||||
#include <record.h>
|
||||
#include <rec_type.h>
|
||||
#include <off_cvt.h>
|
||||
#include <mark_corrupt.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "lmtp.h"
|
||||
#include "quote_821_local.h"
|
||||
|
||||
/*
|
||||
* Sender and receiver state. A session does not necessarily go through a
|
||||
* linear progression, but states are guaranteed to not jump backwards.
|
||||
* Normal sessions go from MAIL->RCPT->DATA->DOT->LAST. The states MAIL,
|
||||
* RCPT, and DATA may also be followed by ABORT->LAST.
|
||||
*
|
||||
* In order to support connection cacheing, no QUIT is send at the end of mail
|
||||
* delivery. Instead, at the start of the next mail delivery, the client
|
||||
* sends RSET to find out if the server is still there, and sends QUIT only
|
||||
* when closing a connection. The RSET and QUIT commands are sent all by
|
||||
* themselves in non-pipelining mode. The respective state transitions are
|
||||
* RSET->LAST and QUIT->LAST.
|
||||
*
|
||||
* For the sake of code reuse, the non-pipelined RSET and QUIT commands are
|
||||
* sent by the same code that implements command pipelining, so that we can
|
||||
* borrow from the existing code for exception handling and error reporting.
|
||||
*
|
||||
*/
|
||||
#define LMTP_STATE_MAIL 0
|
||||
#define LMTP_STATE_RCPT 1
|
||||
#define LMTP_STATE_DATA 2
|
||||
#define LMTP_STATE_DOT 3
|
||||
#define LMTP_STATE_ABORT 4
|
||||
#define LMTP_STATE_RSET 5
|
||||
#define LMTP_STATE_QUIT 6
|
||||
#define LMTP_STATE_LAST 7
|
||||
|
||||
int *xfer_timeouts[LMTP_STATE_LAST] = {
|
||||
&var_lmtp_mail_tmout,
|
||||
&var_lmtp_rcpt_tmout,
|
||||
&var_lmtp_data0_tmout,
|
||||
&var_lmtp_data2_tmout,
|
||||
&var_lmtp_rset_tmout,
|
||||
&var_lmtp_rset_tmout,
|
||||
&var_lmtp_quit_tmout,
|
||||
};
|
||||
|
||||
char *xfer_states[LMTP_STATE_LAST] = {
|
||||
"sending MAIL FROM",
|
||||
"sending RCPT TO",
|
||||
"sending DATA command",
|
||||
"sending end of data -- message may be sent more than once",
|
||||
"sending RSET",
|
||||
"sending RSET",
|
||||
"sending QUIT",
|
||||
};
|
||||
|
||||
/* lmtp_lhlo - perform initial handshake with LMTP server */
|
||||
|
||||
int lmtp_lhlo(LMTP_STATE *state)
|
||||
{
|
||||
char *myname = "lmtp_lhlo";
|
||||
LMTP_SESSION *session = state->session;
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
LMTP_RESP *resp;
|
||||
int except;
|
||||
char *lines;
|
||||
char *words;
|
||||
char *word;
|
||||
int n;
|
||||
SOCKOPT_SIZE optlen = sizeof(state->sndbufsize);
|
||||
|
||||
/*
|
||||
* Prepare for disaster.
|
||||
*/
|
||||
smtp_timeout_setup(state->session->stream, var_lmtp_lhlo_tmout);
|
||||
if ((except = vstream_setjmp(state->session->stream)) != 0)
|
||||
return (lmtp_stream_except(state, except, "sending LHLO"));
|
||||
|
||||
/*
|
||||
* Read and parse the server's LMTP greeting banner.
|
||||
*/
|
||||
if (((resp = lmtp_chat_resp(state))->code / 100) != 2)
|
||||
return (lmtp_site_fail(state, resp->code,
|
||||
"%s refused to talk to me: %s",
|
||||
session->host, translit(resp->str, "\n", " ")));
|
||||
|
||||
/*
|
||||
* See if we are talking to ourself. This should not be possible with the
|
||||
* way we implement DNS lookups. However, people are known to sometimes
|
||||
* screw up the naming service. And, mailer loops are still possible when
|
||||
* our own mailer routing tables are mis-configured.
|
||||
*/
|
||||
words = resp->str;
|
||||
|
||||
/*
|
||||
* Return the compliment.
|
||||
*/
|
||||
lmtp_chat_cmd(state, "LHLO %s", var_myhostname);
|
||||
if ((resp = lmtp_chat_resp(state))->code / 100 != 2)
|
||||
return (lmtp_site_fail(state, resp->code,
|
||||
"%s refused to talk to me: %s",
|
||||
session->host,
|
||||
translit(resp->str, "\n", " ")));
|
||||
|
||||
/*
|
||||
* Pick up some useful features offered by the LMTP server. XXX Until we
|
||||
* have a portable routine to convert from string to off_t with proper
|
||||
* overflow detection, ignore the message size limit advertised by the
|
||||
* LMTP server. Otherwise, we might do the wrong thing when the server
|
||||
* advertises a really huge message size limit.
|
||||
*/
|
||||
lines = resp->str;
|
||||
(void) mystrtok(&lines, "\n");
|
||||
while ((words = mystrtok(&lines, "\n")) != 0) {
|
||||
if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t")) != 0) {
|
||||
if (strcasecmp(word, "8BITMIME") == 0)
|
||||
state->features |= LMTP_FEATURE_8BITMIME;
|
||||
else if (strcasecmp(word, "PIPELINING") == 0)
|
||||
state->features |= LMTP_FEATURE_PIPELINING;
|
||||
else if (strcasecmp(word, "SIZE") == 0)
|
||||
state->features |= LMTP_FEATURE_SIZE;
|
||||
}
|
||||
}
|
||||
if (msg_verbose)
|
||||
msg_info("server features: 0x%x", state->features);
|
||||
|
||||
/*
|
||||
* We use LMTP command pipelining if the server said it supported it.
|
||||
* Since we use blocking I/O, RFC 2197 says that we should inspect the
|
||||
* TCP window size and not send more than this amount of information.
|
||||
* Unfortunately this information is not available using the sockets
|
||||
* interface. However, we *can* get the TCP send buffer size on the local
|
||||
* TCP/IP stack. We should be able to fill this buffer without being
|
||||
* blocked, and then the kernel will effectively do non-blocking I/O for
|
||||
* us by automatically writing out the contents of its send buffer while
|
||||
* we are reading in the responses. In addition to TCP buffering we have
|
||||
* to be aware of application-level buffering by the vstream module,
|
||||
* which is limited to a couple kbytes.
|
||||
*
|
||||
* Don't worry about command pipelining for local connections.
|
||||
*/
|
||||
if (state->features & LMTP_FEATURE_PIPELINING
|
||||
&& state->session->type != LMTP_SERV_TYPE_UNIX) {
|
||||
if (getsockopt(vstream_fileno(state->session->stream), SOL_SOCKET,
|
||||
SO_SNDBUF, (char *) &state->sndbufsize, &optlen) < 0)
|
||||
msg_fatal("%s: getsockopt: %m", myname);
|
||||
if (msg_verbose)
|
||||
msg_info("Using LMTP PIPELINING, TCP send buffer size is %d",
|
||||
state->sndbufsize);
|
||||
} else
|
||||
state->sndbufsize = 0;
|
||||
state->sndbuffree = state->sndbufsize;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/* lmtp_loop - the LMTP state machine */
|
||||
|
||||
static int lmtp_loop(LMTP_STATE *state, int init_state)
|
||||
{
|
||||
char *myname = "lmtp_loop";
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
LMTP_SESSION *session = state->session;
|
||||
LMTP_RESP *resp;
|
||||
RECIPIENT *rcpt;
|
||||
VSTRING *next_command = vstring_alloc(100);
|
||||
int *survivors = 0;
|
||||
int next_state;
|
||||
int next_rcpt;
|
||||
int send_state;
|
||||
int recv_state;
|
||||
int send_rcpt;
|
||||
int recv_rcpt;
|
||||
int nrcpt;
|
||||
int except;
|
||||
int rec_type;
|
||||
int prev_type = 0;
|
||||
int mail_from_rejected;
|
||||
int recv_dot;
|
||||
|
||||
/*
|
||||
* Macros for readability. XXX Isn't LMTP supposed to be case
|
||||
* insensitive?
|
||||
*/
|
||||
#define REWRITE_ADDRESS(addr) do { \
|
||||
if (*(addr)) { \
|
||||
quote_821_local(state->scratch, addr); \
|
||||
myfree(addr); \
|
||||
addr = mystrdup(vstring_str(state->scratch)); \
|
||||
lowercase(addr); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define RETURN(x) do { \
|
||||
vstring_free(next_command); \
|
||||
if (survivors) \
|
||||
myfree((char *) survivors); \
|
||||
return (x); \
|
||||
} while (0)
|
||||
|
||||
#define SENDER_IS_AHEAD \
|
||||
(recv_state < send_state || recv_rcpt != send_rcpt)
|
||||
|
||||
#define SENDER_IN_WAIT_STATE \
|
||||
(send_state == LMTP_STATE_DOT || send_state == LMTP_STATE_LAST)
|
||||
|
||||
/*
|
||||
* Pipelining support requires two loops: one loop for sending and one
|
||||
* for receiving. Each loop has its own independent state. Most of the
|
||||
* time the sender can run ahead of the receiver by as much as the TCP
|
||||
* send buffer permits. There are only two places where the sender must
|
||||
* wait for status information from the receiver: once after sending DATA
|
||||
* and once after sending QUIT.
|
||||
*
|
||||
* The sender state advances until the TCP send buffer would overflow, or
|
||||
* until the sender needs status information from the receiver. At that
|
||||
* point the receiver starts processing responses. Once the receiver has
|
||||
* caught up with the sender, the sender resumes sending commands. If the
|
||||
* receiver detects a serious problem (MAIL FROM rejected, all RCPT TO
|
||||
* commands rejected, DATA rejected) it forces the sender to abort the
|
||||
* LMTP dialog with RSET.
|
||||
*/
|
||||
nrcpt = 0;
|
||||
recv_state = send_state = init_state;
|
||||
next_rcpt = send_rcpt = recv_rcpt = recv_dot = 0;
|
||||
mail_from_rejected = 0;
|
||||
|
||||
while (recv_state != LMTP_STATE_LAST) {
|
||||
|
||||
/*
|
||||
* Build the next command.
|
||||
*/
|
||||
switch (send_state) {
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
default:
|
||||
msg_panic("%s: bad sender state %d", myname, send_state);
|
||||
|
||||
/*
|
||||
* Build the MAIL FROM command.
|
||||
*/
|
||||
case LMTP_STATE_MAIL:
|
||||
if (*request->sender)
|
||||
REWRITE_ADDRESS(request->sender);
|
||||
vstring_sprintf(next_command, "MAIL FROM:<%s>", request->sender);
|
||||
if (state->features & LMTP_FEATURE_SIZE)
|
||||
vstring_sprintf_append(next_command, " SIZE=%lu",
|
||||
request->data_size);
|
||||
next_state = LMTP_STATE_RCPT;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Build one RCPT TO command before we have seen the MAIL FROM
|
||||
* response.
|
||||
*/
|
||||
case LMTP_STATE_RCPT:
|
||||
rcpt = request->rcpt_list.info + send_rcpt;
|
||||
REWRITE_ADDRESS(rcpt->address);
|
||||
vstring_sprintf(next_command, "RCPT TO:<%s>", rcpt->address);
|
||||
if ((next_rcpt = send_rcpt + 1) == request->rcpt_list.len)
|
||||
next_state = LMTP_STATE_DATA;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Build the DATA command before we have seen all the RCPT TO
|
||||
* responses.
|
||||
*/
|
||||
case LMTP_STATE_DATA:
|
||||
vstring_strcpy(next_command, "DATA");
|
||||
next_state = LMTP_STATE_DOT;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Build the "." command before we have seen the DATA response.
|
||||
*/
|
||||
case LMTP_STATE_DOT:
|
||||
vstring_strcpy(next_command, ".");
|
||||
next_state = LMTP_STATE_LAST;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Can't happen. The LMTP_STATE_ABORT sender state is entered by
|
||||
* the receiver and is left before the bottom of the main loop.
|
||||
*/
|
||||
case LMTP_STATE_ABORT:
|
||||
msg_panic("%s: sender abort state", myname);
|
||||
|
||||
/*
|
||||
* Build the RSET command. XXX This command does not belong here
|
||||
* because it will be sent in non-pipelining mode. But having it
|
||||
* here means that we can reuse existing code for error handling.
|
||||
*/
|
||||
case LMTP_STATE_RSET:
|
||||
vstring_strcpy(next_command, "RSET");
|
||||
next_state = LMTP_STATE_LAST;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Build the QUIT command. XXX This command does not belong here
|
||||
* because it will be sent in non-pipelining mode. But having it
|
||||
* here means that we can reuse existing code for error handling.
|
||||
*/
|
||||
case LMTP_STATE_QUIT:
|
||||
vstring_strcpy(next_command, "QUIT");
|
||||
next_state = LMTP_STATE_LAST;
|
||||
break;
|
||||
|
||||
/*
|
||||
* The final sender state has no action associated with it.
|
||||
*/
|
||||
case LMTP_STATE_LAST:
|
||||
VSTRING_RESET(next_command);
|
||||
break;
|
||||
}
|
||||
VSTRING_TERMINATE(next_command);
|
||||
|
||||
/*
|
||||
* Process responses until the receiver has caught up. Vstreams
|
||||
* automatically flush buffered output when reading new data.
|
||||
*/
|
||||
if (SENDER_IN_WAIT_STATE
|
||||
|| (SENDER_IS_AHEAD
|
||||
&& VSTRING_LEN(next_command) + 2 > state->sndbuffree)) {
|
||||
while (SENDER_IS_AHEAD) {
|
||||
|
||||
/*
|
||||
* Sanity check.
|
||||
*/
|
||||
if (recv_state < LMTP_STATE_MAIL
|
||||
|| recv_state > LMTP_STATE_QUIT)
|
||||
msg_panic("%s: bad receiver state %d (sender state %d)",
|
||||
myname, recv_state, send_state);
|
||||
|
||||
/*
|
||||
* Receive the next server response. Use the proper timeout,
|
||||
* and log the proper client state in case of trouble.
|
||||
*/
|
||||
smtp_timeout_setup(state->session->stream,
|
||||
*xfer_timeouts[recv_state]);
|
||||
if ((except = vstream_setjmp(state->session->stream)) != 0)
|
||||
RETURN(lmtp_stream_except(state, except,
|
||||
xfer_states[recv_state]));
|
||||
resp = lmtp_chat_resp(state);
|
||||
|
||||
/*
|
||||
* Process the response.
|
||||
*/
|
||||
switch (recv_state) {
|
||||
|
||||
/*
|
||||
* Process the MAIL FROM response. When the server
|
||||
* rejects the sender, set the mail_from_rejected flag so
|
||||
* that the receiver may apply a course correction.
|
||||
*/
|
||||
case LMTP_STATE_MAIL:
|
||||
if (resp->code / 100 != 2) {
|
||||
lmtp_mesg_fail(state, resp->code,
|
||||
"%s said: %s", session->host,
|
||||
translit(resp->str, "\n", " "));
|
||||
mail_from_rejected = 1;
|
||||
}
|
||||
recv_state = LMTP_STATE_RCPT;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Process one RCPT TO response. If MAIL FROM was
|
||||
* rejected, ignore RCPT TO responses: all recipients are
|
||||
* dead already. When all recipients are rejected the
|
||||
* receiver may apply a course correction.
|
||||
*/
|
||||
case LMTP_STATE_RCPT:
|
||||
if (!mail_from_rejected) {
|
||||
rcpt = request->rcpt_list.info + recv_rcpt;
|
||||
if (resp->code / 100 == 2) {
|
||||
if (survivors == 0)
|
||||
survivors = (int *)
|
||||
mymalloc(request->rcpt_list.len
|
||||
* sizeof(int));
|
||||
survivors[nrcpt++] = recv_rcpt;
|
||||
} else {
|
||||
lmtp_rcpt_fail(state, resp->code, rcpt,
|
||||
"%s said: %s", session->host,
|
||||
translit(resp->str, "\n", " "));
|
||||
rcpt->offset = 0; /* in case deferred */
|
||||
}
|
||||
}
|
||||
if (++recv_rcpt == request->rcpt_list.len)
|
||||
recv_state = LMTP_STATE_DATA;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Process the DATA response. When the server rejects
|
||||
* DATA, set nrcpt to a negative value so that the
|
||||
* receiver can apply a course correction.
|
||||
*/
|
||||
case LMTP_STATE_DATA:
|
||||
if (resp->code / 100 != 3) {
|
||||
if (nrcpt > 0)
|
||||
lmtp_mesg_fail(state, resp->code,
|
||||
"%s said: %s", session->host,
|
||||
translit(resp->str, "\n", " "));
|
||||
nrcpt = -1;
|
||||
}
|
||||
recv_state = LMTP_STATE_DOT;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Process the end of message response. Ignore the
|
||||
* response when no recipient was accepted: all
|
||||
* recipients are dead already, and the next receiver
|
||||
* state is LMTP_STATE_LAST regardless. Otherwise, if the
|
||||
* message transfer fails, bounce all remaining
|
||||
* recipients, else cross off the recipients that were
|
||||
* delivered.
|
||||
*/
|
||||
case LMTP_STATE_DOT:
|
||||
if (nrcpt > 0) {
|
||||
rcpt = request->rcpt_list.info + survivors[recv_dot];
|
||||
if (resp->code / 100 == 2) {
|
||||
if (rcpt->offset) {
|
||||
sent(request->queue_id, rcpt->address,
|
||||
session->host, request->arrival_time,
|
||||
"%s", resp->str);
|
||||
deliver_completed(state->src, rcpt->offset);
|
||||
rcpt->offset = 0;
|
||||
}
|
||||
} else {
|
||||
lmtp_rcpt_fail(state, resp->code, rcpt,
|
||||
"%s said: %s", session->host,
|
||||
translit(resp->str, "\n", " "));
|
||||
rcpt->offset = 0; /* in case deferred */
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We get one response per valid RCPT TO:
|
||||
*/
|
||||
if (msg_verbose)
|
||||
msg_info("%s: recv_dot = %d", myname, recv_dot);
|
||||
if (++recv_dot >= nrcpt) {
|
||||
if (msg_verbose)
|
||||
msg_info("%s: finished . command", myname);
|
||||
recv_state = LMTP_STATE_LAST;
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* Ignore the RSET response.
|
||||
*/
|
||||
case LMTP_STATE_ABORT:
|
||||
recv_state = LMTP_STATE_LAST;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Ignore the RSET response.
|
||||
*/
|
||||
case LMTP_STATE_RSET:
|
||||
recv_state = LMTP_STATE_LAST;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Ignore the QUIT response.
|
||||
*/
|
||||
case LMTP_STATE_QUIT:
|
||||
recv_state = LMTP_STATE_LAST;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, the sender and receiver are fully synchronized,
|
||||
* so that the entire TCP send buffer becomes available again.
|
||||
*/
|
||||
state->sndbuffree = state->sndbufsize;
|
||||
|
||||
/*
|
||||
* We know the server response to every command that was sent.
|
||||
* Apply a course correction if necessary: the sender wants to
|
||||
* send RCPT TO but MAIL FROM was rejected; the sender wants to
|
||||
* send DATA but all recipients were rejected; the sender wants
|
||||
* to deliver the message but DATA was rejected.
|
||||
*/
|
||||
if ((send_state == LMTP_STATE_RCPT && mail_from_rejected)
|
||||
|| (send_state == LMTP_STATE_DATA && nrcpt == 0)
|
||||
|| (send_state == LMTP_STATE_DOT && nrcpt < 0)) {
|
||||
send_state = recv_state = LMTP_STATE_ABORT;
|
||||
send_rcpt = recv_rcpt = 0;
|
||||
vstring_strcpy(next_command, "RSET");
|
||||
next_state = LMTP_STATE_LAST;
|
||||
next_rcpt = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Make the next sender state the current sender state.
|
||||
*/
|
||||
if (send_state == LMTP_STATE_LAST)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Special case if the server accepted the DATA command. If the
|
||||
* server accepted at least one recipient send the entire message.
|
||||
* Otherwise, just send "." as per RFC 2197.
|
||||
*/
|
||||
if (send_state == LMTP_STATE_DOT && nrcpt > 0) {
|
||||
smtp_timeout_setup(state->session->stream,
|
||||
var_lmtp_data1_tmout);
|
||||
if ((except = vstream_setjmp(state->session->stream)) != 0)
|
||||
RETURN(lmtp_stream_except(state, except,
|
||||
"sending message body"));
|
||||
|
||||
if (vstream_fseek(state->src, request->data_offset, SEEK_SET) < 0)
|
||||
msg_fatal("seek queue file: %m");
|
||||
|
||||
while ((rec_type = rec_get(state->src, state->scratch, 0)) > 0) {
|
||||
if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
|
||||
break;
|
||||
if (prev_type != REC_TYPE_CONT)
|
||||
if (vstring_str(state->scratch)[0] == '.')
|
||||
smtp_fputc('.', session->stream);
|
||||
if (rec_type == REC_TYPE_CONT)
|
||||
smtp_fwrite(vstring_str(state->scratch),
|
||||
VSTRING_LEN(state->scratch),
|
||||
session->stream);
|
||||
else
|
||||
smtp_fputs(vstring_str(state->scratch),
|
||||
VSTRING_LEN(state->scratch),
|
||||
session->stream);
|
||||
prev_type = rec_type;
|
||||
}
|
||||
|
||||
if (prev_type == REC_TYPE_CONT) /* missing newline at end */
|
||||
smtp_fputs("", 0, session->stream);
|
||||
if (vstream_ferror(state->src))
|
||||
msg_fatal("queue file read error");
|
||||
if (rec_type != REC_TYPE_XTRA)
|
||||
RETURN(mark_corrupt(state->src));
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the next command to the buffer and update the sender state.
|
||||
*/
|
||||
if (state->sndbuffree > 0)
|
||||
state->sndbuffree -= VSTRING_LEN(next_command) + 2;
|
||||
lmtp_chat_cmd(state, "%s", vstring_str(next_command));
|
||||
send_state = next_state;
|
||||
send_rcpt = next_rcpt;
|
||||
}
|
||||
|
||||
RETURN(0);
|
||||
}
|
||||
|
||||
/* lmtp_xfer - send a batch of envelope information and the message data */
|
||||
|
||||
int lmtp_xfer(LMTP_STATE *state)
|
||||
{
|
||||
return (lmtp_loop(state, LMTP_STATE_MAIL));
|
||||
}
|
||||
|
||||
/* lmtp_rset - reset dialog with peer */
|
||||
|
||||
int lmtp_rset(LMTP_STATE *state)
|
||||
{
|
||||
return (lmtp_loop(state, LMTP_STATE_RSET));
|
||||
}
|
||||
|
||||
/* lmtp_quit - say goodbye to peer */
|
||||
|
||||
int lmtp_quit(LMTP_STATE *state)
|
||||
{
|
||||
return (lmtp_loop(state, LMTP_STATE_QUIT));
|
||||
}
|
105
postfix/lmtp/lmtp_session.c
Normal file
105
postfix/lmtp/lmtp_session.c
Normal file
@ -0,0 +1,105 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp_session 3
|
||||
/* SUMMARY
|
||||
/* LMTP_SESSION structure management
|
||||
/* SYNOPSIS
|
||||
/* #include "lmtp.h"
|
||||
/*
|
||||
/* LMTP_SESSION *lmtp_session_alloc(stream, host, addr)
|
||||
/* VSTREAM *stream;
|
||||
/* char *host;
|
||||
/* char *addr;
|
||||
/*
|
||||
/* void lmtp_session_free(session)
|
||||
/* LMTP_SESSION *session;
|
||||
/*
|
||||
/* void lmtp_session_reset(state)
|
||||
/* LMTP_STATE *state;
|
||||
/* DESCRIPTION
|
||||
/* lmtp_session_alloc() allocates memory for an LMTP_SESSION structure
|
||||
/* and initializes it with the given stream and host name and address
|
||||
/* information. The host name and address strings are copied. The code
|
||||
/* assumes that the stream is connected to the "best" alternative.
|
||||
/*
|
||||
/* lmtp_session_free() destroys an LMTP_SESSION structure and its
|
||||
/* members, making memory available for reuse.
|
||||
/*
|
||||
/* lmtp_session_reset() is just a little helper to make sure everything
|
||||
/* is set to zero after the session has been freed. This means I don't
|
||||
/* have to keep repeating the same chunks of code for cached connections.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <mymalloc.h>
|
||||
#include <vstream.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "lmtp.h"
|
||||
|
||||
/* lmtp_session_alloc - allocate and initialize LMTP_SESSION structure */
|
||||
|
||||
LMTP_SESSION *lmtp_session_alloc(VSTREAM *stream, char *host, char *addr)
|
||||
{
|
||||
LMTP_SESSION *session;
|
||||
|
||||
session = (LMTP_SESSION *) mymalloc(sizeof(*session));
|
||||
session->stream = stream;
|
||||
session->host = mystrdup(host);
|
||||
session->addr = mystrdup(addr);
|
||||
session->destination = 0;
|
||||
return (session);
|
||||
}
|
||||
|
||||
/* lmtp_session_free - destroy LMTP_SESSION structure and contents */
|
||||
|
||||
void lmtp_session_free(LMTP_SESSION *session)
|
||||
{
|
||||
if (vstream_ispipe(session->stream))
|
||||
vstream_pclose(session->stream);
|
||||
else
|
||||
vstream_fclose(session->stream);
|
||||
myfree(session->host);
|
||||
myfree(session->addr);
|
||||
if (session->destination)
|
||||
myfree(session->destination);
|
||||
myfree((char *) session);
|
||||
}
|
||||
|
||||
/* lmtp_session_reset - clean things up so a new session can be created */
|
||||
|
||||
void lmtp_session_reset(LMTP_STATE *state)
|
||||
{
|
||||
if (state->session) {
|
||||
lmtp_session_free(state->session);
|
||||
state->session = 0;
|
||||
}
|
||||
state->reuse = 0;
|
||||
}
|
||||
|
92
postfix/lmtp/lmtp_state.c
Normal file
92
postfix/lmtp/lmtp_state.c
Normal file
@ -0,0 +1,92 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp_state 8
|
||||
/* SUMMARY
|
||||
/* initialize/cleanup shared state
|
||||
/* SYNOPSIS
|
||||
/* #include "lmtp.h"
|
||||
/*
|
||||
/* LMTP_STATE *lmtp_state_alloc()
|
||||
/*
|
||||
/* void lmtp_state_free(state)
|
||||
/* LMTP_STATE *state;
|
||||
/* DESCRIPTION
|
||||
/* lmtp_state_init() initializes the shared state, and allocates
|
||||
/* memory for buffers etc.
|
||||
/*
|
||||
/* lmtp_cleanup() destroys memory allocated by lmtp_state_init().
|
||||
/* STANDARDS
|
||||
/* DIAGNOSTICS
|
||||
/* BUGS
|
||||
/* SEE ALSO
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <mymalloc.h>
|
||||
#include <vstring.h>
|
||||
#include <vstream.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <config.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "lmtp.h"
|
||||
|
||||
/* lmtp_state_alloc - initialize */
|
||||
|
||||
LMTP_STATE *lmtp_state_alloc(void)
|
||||
{
|
||||
LMTP_STATE *state = (LMTP_STATE *) mymalloc(sizeof(*state));
|
||||
|
||||
state->src = 0;
|
||||
state->request = 0;
|
||||
state->session = 0;
|
||||
state->buffer = vstring_alloc(100);
|
||||
state->scratch = vstring_alloc(100);
|
||||
state->scratch2 = vstring_alloc(100);
|
||||
state->status = 0;
|
||||
state->features = 0;
|
||||
state->history = 0;
|
||||
state->error_mask = 0;
|
||||
state->sndbufsize = 0;
|
||||
state->sndbuffree = 0;
|
||||
state->reuse = 0;
|
||||
return (state);
|
||||
}
|
||||
|
||||
/* lmtp_state_free - destroy state */
|
||||
|
||||
void lmtp_state_free(LMTP_STATE *state)
|
||||
{
|
||||
vstring_free(state->buffer);
|
||||
vstring_free(state->scratch);
|
||||
vstring_free(state->scratch2);
|
||||
myfree((char *) state);
|
||||
}
|
318
postfix/lmtp/lmtp_trouble.c
Normal file
318
postfix/lmtp/lmtp_trouble.c
Normal file
@ -0,0 +1,318 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* lmtp_trouble 3
|
||||
/* SUMMARY
|
||||
/* error handler policies
|
||||
/* SYNOPSIS
|
||||
/* #include "lmtp.h"
|
||||
/*
|
||||
/* int lmtp_site_fail(state, code, format, ...)
|
||||
/* LMTP_STATE *state;
|
||||
/* int code;
|
||||
/* char *format;
|
||||
/*
|
||||
/* int lmtp_mesg_fail(state, code, format, ...)
|
||||
/* LMTP_STATE *state;
|
||||
/* int code;
|
||||
/* char *format;
|
||||
/*
|
||||
/* void lmtp_rcpt_fail(state, code, recipient, format, ...)
|
||||
/* LMTP_STATE *state;
|
||||
/* int code;
|
||||
/* RECIPIENT *recipient;
|
||||
/* char *format;
|
||||
/*
|
||||
/* int lmtp_stream_except(state, exception, description)
|
||||
/* LMTP_STATE *state;
|
||||
/* int exception;
|
||||
/* char *description;
|
||||
/* DESCRIPTION
|
||||
/* This module handles all non-fatal errors that can happen while
|
||||
/* attempting to deliver mail via LMTP, and implements the policy
|
||||
/* of how to deal with the error. Depending on the nature of
|
||||
/* the problem, delivery of a single message is deferred, delivery
|
||||
/* of all messages to the same domain is deferred, or one or more
|
||||
/* recipients are given up as non-deliverable and a bounce log is
|
||||
/* updated.
|
||||
/*
|
||||
/* In addition, when an unexpected response code is seen such
|
||||
/* as 3xx where only 4xx or 5xx are expected, or any error code
|
||||
/* that suggests a syntax error or something similar, the
|
||||
/* protocol error flag is set so that the postmaster receives
|
||||
/* a transcript of the session. No notification is generated for
|
||||
/* what appear to be configuration errors - very likely, they
|
||||
/* would suffer the same problem and just cause more trouble.
|
||||
/*
|
||||
/* lmtp_site_fail() handles the case where the program fails to
|
||||
/* complete the initial LMTP handshake: the server is not reachable,
|
||||
/* is not running, does not want talk to us, or we talk to ourselves.
|
||||
/* The \fIcode\fR gives an error status code; the \fIformat\fR
|
||||
/* argument gives a textual description. The policy is: soft
|
||||
/* error: defer delivery of all messages to this domain; hard
|
||||
/* error: bounce all recipients of this message.
|
||||
/* The result is non-zero.
|
||||
/*
|
||||
/* lmtp_mesg_fail() handles the case where the lmtp server
|
||||
/* does not accept the sender address or the message data.
|
||||
/* The policy is: soft errors: defer delivery of this message;
|
||||
/* hard error: bounce all recipients of this message.
|
||||
/* The result is non-zero.
|
||||
/*
|
||||
/* lmtp_rcpt_fail() handles the case where a recipient is not
|
||||
/* accepted by the server for reasons other than that the server
|
||||
/* recipient limit is reached. The policy is: soft error: defer
|
||||
/* delivery to this recipient; hard error: bounce this recipient.
|
||||
/*
|
||||
/* lmtp_stream_except() handles the exceptions generated by
|
||||
/* the smtp_stream(3) module (i.e. timeouts and I/O errors).
|
||||
/* The \fIexception\fR argument specifies the type of problem.
|
||||
/* The \fIdescription\fR argument describes at what stage of
|
||||
/* the LMTP dialog the problem happened. The policy is to defer
|
||||
/* delivery of all messages to the same domain. The result is non-zero.
|
||||
/* DIAGNOSTICS
|
||||
/* Panic: unknown exception code.
|
||||
/* SEE ALSO
|
||||
/* lmtp_proto(3) lmtp high-level protocol
|
||||
/* smtp_stream(3) lmtp low-level protocol
|
||||
/* defer(3) basic message defer interface
|
||||
/* bounce(3) basic message bounce interface
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <msg.h>
|
||||
#include <vstring.h>
|
||||
#include <stringops.h>
|
||||
#include <mymalloc.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include <smtp_stream.h>
|
||||
#include <deliver_request.h>
|
||||
#include <deliver_completed.h>
|
||||
#include <bounce.h>
|
||||
#include <defer.h>
|
||||
#include <mail_error.h>
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#include "lmtp.h"
|
||||
|
||||
#define LMTP_SOFT(code) (((code) / 100) == 4)
|
||||
#define LMTP_HARD(code) (((code) / 100) == 5)
|
||||
#define KEEP BOUNCE_FLAG_KEEP
|
||||
|
||||
/* lmtp_check_code - check response code */
|
||||
|
||||
static void lmtp_check_code(LMTP_STATE *state, int code)
|
||||
{
|
||||
|
||||
/*
|
||||
* The intention of this stuff is to alert the postmaster when the local
|
||||
* Postfix LMTP client screws up, protocol wise. RFC 821 says that x0z
|
||||
* replies "refer to syntax errors, syntactically correct commands that
|
||||
* don't fit any functional category, and unimplemented or superfluous
|
||||
* commands". Unfortunately, this also triggers postmaster notices when
|
||||
* remote servers screw up, protocol wise. This is becoming a common
|
||||
* problem now that response codes are configured manually as part of
|
||||
* anti-UCE systems, by people who aren't aware of RFC details.
|
||||
*/
|
||||
if ((!LMTP_SOFT(code) && !LMTP_HARD(code))
|
||||
|| code == 555 /* RFC 1869, section 6.1. */
|
||||
|| (code >= 500 && code < 510))
|
||||
state->error_mask |= MAIL_ERROR_PROTOCOL;
|
||||
}
|
||||
|
||||
/* lmtp_site_fail - defer site or bounce recipients */
|
||||
|
||||
int lmtp_site_fail(LMTP_STATE *state, int code, char *format,...)
|
||||
{
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
LMTP_SESSION *session = state->session;
|
||||
RECIPIENT *rcpt;
|
||||
int status;
|
||||
int nrcpt;
|
||||
int soft_error = LMTP_SOFT(code);
|
||||
va_list ap;
|
||||
VSTRING *why = vstring_alloc(100);
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
va_start(ap, format);
|
||||
vstring_vsprintf(why, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/*
|
||||
* If this is a soft error, postpone further deliveries to this domain.
|
||||
* Otherwise, generate a bounce record for each recipient.
|
||||
*/
|
||||
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
||||
rcpt = request->rcpt_list.info + nrcpt;
|
||||
if (rcpt->offset == 0)
|
||||
continue;
|
||||
status = (soft_error ? defer_append : bounce_append)
|
||||
(KEEP, request->queue_id, rcpt->address,
|
||||
session ? session->host : "none",
|
||||
request->arrival_time, "%s", vstring_str(why));
|
||||
if (status == 0) {
|
||||
deliver_completed(state->src, rcpt->offset);
|
||||
rcpt->offset = 0;
|
||||
}
|
||||
state->status |= status;
|
||||
}
|
||||
if (soft_error && request->hop_status == 0)
|
||||
request->hop_status = mystrdup(vstring_str(why));
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
vstring_free(why);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* lmtp_mesg_fail - defer message or bounce all recipients */
|
||||
|
||||
int lmtp_mesg_fail(LMTP_STATE *state, int code, char *format,...)
|
||||
{
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
LMTP_SESSION *session = state->session;
|
||||
RECIPIENT *rcpt;
|
||||
int status;
|
||||
int nrcpt;
|
||||
va_list ap;
|
||||
VSTRING *why = vstring_alloc(100);
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
va_start(ap, format);
|
||||
vstring_vsprintf(why, format, ap);
|
||||
va_end(ap);
|
||||
|
||||
/*
|
||||
* If this is a soft error, postpone delivery of this message. Otherwise,
|
||||
* generate a bounce record for each recipient.
|
||||
*/
|
||||
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
||||
rcpt = request->rcpt_list.info + nrcpt;
|
||||
if (rcpt->offset == 0)
|
||||
continue;
|
||||
status = (LMTP_SOFT(code) ? defer_append : bounce_append)
|
||||
(KEEP, request->queue_id, rcpt->address,
|
||||
session->host, request->arrival_time,
|
||||
"%s", vstring_str(why));
|
||||
if (status == 0) {
|
||||
deliver_completed(state->src, rcpt->offset);
|
||||
rcpt->offset = 0;
|
||||
}
|
||||
state->status |= status;
|
||||
}
|
||||
lmtp_check_code(state, code);
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
vstring_free(why);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* lmtp_rcpt_fail - defer or bounce recipient */
|
||||
|
||||
void lmtp_rcpt_fail(LMTP_STATE *state, int code, RECIPIENT *rcpt,
|
||||
char *format,...)
|
||||
{
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
LMTP_SESSION *session = state->session;
|
||||
int status;
|
||||
va_list ap;
|
||||
|
||||
/*
|
||||
* If this is a soft error, postpone delivery to this recipient.
|
||||
* Otherwise, generate a bounce record for this recipient.
|
||||
*/
|
||||
va_start(ap, format);
|
||||
status = (LMTP_SOFT(code) ? vdefer_append : vbounce_append)
|
||||
(KEEP, request->queue_id, rcpt->address, session->host,
|
||||
request->arrival_time, format, ap);
|
||||
va_end(ap);
|
||||
if (status == 0) {
|
||||
deliver_completed(state->src, rcpt->offset);
|
||||
rcpt->offset = 0;
|
||||
}
|
||||
lmtp_check_code(state, code);
|
||||
state->status |= status;
|
||||
}
|
||||
|
||||
/* lmtp_stream_except - defer domain after I/O problem */
|
||||
|
||||
int lmtp_stream_except(LMTP_STATE *state, int code, char *description)
|
||||
{
|
||||
DELIVER_REQUEST *request = state->request;
|
||||
LMTP_SESSION *session = state->session;
|
||||
RECIPIENT *rcpt;
|
||||
int nrcpt;
|
||||
VSTRING *why = vstring_alloc(100);
|
||||
|
||||
/*
|
||||
* Initialize.
|
||||
*/
|
||||
switch (code) {
|
||||
default:
|
||||
msg_panic("lmtp_stream_except: unknown exception %d", code);
|
||||
case SMTP_ERR_EOF:
|
||||
vstring_sprintf(why, "lost connection with %s while %s",
|
||||
session->host, description);
|
||||
break;
|
||||
case SMTP_ERR_TIME:
|
||||
vstring_sprintf(why, "conversation with %s timed out while %s",
|
||||
session->host, description);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* At this point, the status of individual recipients remains unresolved.
|
||||
* All we know is that we should stay away from this host for a while.
|
||||
*/
|
||||
for (nrcpt = 0; nrcpt < request->rcpt_list.len; nrcpt++) {
|
||||
rcpt = request->rcpt_list.info + nrcpt;
|
||||
if (rcpt->offset == 0)
|
||||
continue;
|
||||
state->status |= defer_append(KEEP, request->queue_id,
|
||||
rcpt->address, session->host,
|
||||
request->arrival_time,
|
||||
"%s", vstring_str(why));
|
||||
}
|
||||
|
||||
/*
|
||||
* Cleanup.
|
||||
*/
|
||||
vstring_free(why);
|
||||
return (-1);
|
||||
}
|
753
postfix/lmtp/mail
Normal file
753
postfix/lmtp/mail
Normal file
@ -0,0 +1,753 @@
|
||||
From wietse@porcupine.org Sat Apr 15 10:47:09 2000
|
||||
Return-Path: <wietse@porcupine.org>
|
||||
Delivered-To: wietse@hades.porcupine.org
|
||||
Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
|
||||
by hades.porcupine.org (Postfix) with ESMTP id 567DC18A54
|
||||
for <wietse@hades.porcupine.org>; Sat, 15 Apr 2000 10:47:09 -0400 (EDT)
|
||||
Received: by spike.porcupine.org (Postfix, from userid 100)
|
||||
id BE9C14563D; Sat, 15 Apr 2000 10:47:08 -0400 (EDT)
|
||||
Delivered-To: wietse@porcupine.org
|
||||
Received: from ns0.utdallas.edu (ns0.utdallas.edu [129.110.10.1])
|
||||
by spike.porcupine.org (Postfix) with ESMTP id E91E045630
|
||||
for <wietse@porcupine.org>; Sat, 15 Apr 2000 09:37:17 -0400 (EDT)
|
||||
Received: from spartacus.utdallas.edu (spartacus.utdallas.edu [129.110.3.11])
|
||||
by ns0.utdallas.edu (Postfix) with SMTP id 7D0601A00B9
|
||||
for <wietse@porcupine.org>; Sat, 15 Apr 2000 08:36:35 -0500 (CDT)
|
||||
To: Wietse Venema <wietse@porcupine.org>
|
||||
Subject: [Markku Järvinen <Markku.Jarvinen@tpo.fi>] postfix lmtp
|
||||
From: Amos Gouaux <amos@utdallas.edu>
|
||||
Date: 15 Apr 2000 08:37:54 -0500
|
||||
Message-ID: <q6m66tj32od.fsf@spartacus.utdallas.edu>
|
||||
Lines: 73
|
||||
User-Agent: Gnus/5.0804 (Gnus v5.8.4) XEmacs/21.1 (Bryce Canyon)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="=-=-="
|
||||
Sender: wietse@porcupine.org
|
||||
Status: ROr
|
||||
|
||||
--=-=-=
|
||||
|
||||
I suspect you've already dealt with this one during the merging, but
|
||||
forwarding in case not.
|
||||
|
||||
I do recall one reason why I just inserted RSET into the state
|
||||
machine as I did--I wanted to check the response. Though, this is
|
||||
easily remedied by having a mini state machine in the lmtp_rset
|
||||
function.
|
||||
|
||||
I guess I thought that having RSET in the state machine would be
|
||||
okay because of this:
|
||||
|
||||
while ((rec_type = rec_get(state->src, state->scratch, 0)) > 0) {
|
||||
if (rec_type != REC_TYPE_NORM && rec_type != REC_TYPE_CONT)
|
||||
break;
|
||||
if (prev_type != REC_TYPE_CONT)
|
||||
if (vstring_str(state->scratch)[0] == '.')
|
||||
smtp_fputc('.', session->stream);
|
||||
if (rec_type == REC_TYPE_CONT)
|
||||
smtp_fwrite(vstring_str(state->scratch),
|
||||
VSTRING_LEN(state->scratch),
|
||||
session->stream);
|
||||
else
|
||||
smtp_fputs(vstring_str(state->scratch),
|
||||
VSTRING_LEN(state->scratch),
|
||||
session->stream);
|
||||
prev_type = rec_type;
|
||||
}
|
||||
|
||||
Wouldn't this just suck in the entire message text, then put a '.'
|
||||
into the dialog? How would a RSET in the message text jumble up the
|
||||
state machine?
|
||||
|
||||
Amos
|
||||
|
||||
|
||||
|
||||
--=-=-=
|
||||
Content-Type: message/rfc822; charset=""
|
||||
Content-Disposition: inline
|
||||
Content-Transfer-Encoding: quoted-printable
|
||||
|
||||
Return-Path: <markku.jarvinen@tpo.fi>
|
||||
X-Sieve: cmu-sieve 1.3
|
||||
Received: from antivirus.tpo.fi (ns3.tpo.fi [212.63.10.250])
|
||||
by ns0.utdallas.edu (Postfix) with ESMTP id 0700019FFF2
|
||||
for <amos@utdallas.edu>; Fri, 14 Apr 2000 04:14:18 -0500 (CDT)
|
||||
Received: from ky.tpo.fi (localhost [127.0.0.1])
|
||||
by antivirus.tpo.fi (8.9.3/8.9.3) with ESMTP id MAA09192
|
||||
for <amos@utdallas.edu>; Fri, 14 Apr 2000 12:14:51 +0300 (EET DST)
|
||||
Rec=
|
||||
eived: from mtaj (home-f.ttk.tpo.fi [212.63.14.2])
|
||||
by ky.tpo.fi (Postfix) with SMTP id 801AFF568
|
||||
for <amos@utdallas.edu>; Fri, 14 Apr 2000 12:14:50 +0300 (EET DST)
|
||||
Mes=
|
||||
sage-ID: <05f601bfa5f1$bb2097c0$69fd1fac@ttk.tpo.fi>
|
||||
From: Markku J=E4rvinen <Markku.Jarvinen@tpo.fi>
|
||||
To: <amos@utdallas.edu>
|
||||
Subject: postfix lmtp
|
||||
Date: Fri, 14 Apr 2000 12:13:42 +0300
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain;
|
||||
charset=3D"iso-8859-1"
|
||||
Content-Transfer-Encoding: 7bit
|
||||
X-Priority: 3
|
||||
X-MSMail-Priority: Normal
|
||||
X-Mailer: Microsoft Outlook Express 5.00.2919.6600
|
||||
X-MimeOLE: Produced By Microsoft MimeOLE V5.00.2919.6600
|
||||
|
||||
Hi!
|
||||
|
||||
In line 349 of lmtp_proto.c you just print the sender into LMTP-transac=
|
||||
tion.
|
||||
vstring_sprintf(next_command, "MAIL FROM:<%s>", request->sender);
|
||||
This fails when the sender address has spaces in it, you should first r=
|
||||
un it
|
||||
through quota_821_local to get it into the right format for LMTP (same =
|
||||
as
|
||||
SMTP).
|
||||
|
||||
- Markku
|
||||
|
||||
|
||||
|
||||
--=-=-=--
|
||||
|
||||
|
||||
|
||||
|
||||
From wietse@porcupine.org Sat Feb 26 09:17:05 2000
|
||||
Return-Path: <wietse@porcupine.org>
|
||||
Delivered-To: wietse@hades.porcupine.org
|
||||
Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
|
||||
by hades.porcupine.org (Postfix) with ESMTP id E0D7F1886D
|
||||
for <wietse@hades.porcupine.org>; Sat, 26 Feb 2000 09:17:04 -0500 (EST)
|
||||
Received: by spike.porcupine.org (Postfix, from userid 100)
|
||||
id A520145659; Sat, 26 Feb 2000 09:17:04 -0500 (EST)
|
||||
Delivered-To: wietse@porcupine.org
|
||||
Received: from ns0.utdallas.edu (ns0.utdallas.edu [129.110.10.1])
|
||||
by spike.porcupine.org (Postfix) with ESMTP id 5773F45657
|
||||
for <wietse@porcupine.org>; Fri, 25 Feb 2000 19:41:51 -0500 (EST)
|
||||
Received: from spartacus.utdallas.edu (spartacus.utdallas.edu [129.110.3.11])
|
||||
by ns0.utdallas.edu (Postfix) with SMTP id 782F91A00D7
|
||||
for <wietse@porcupine.org>; Fri, 25 Feb 2000 18:04:16 -0600 (CST)
|
||||
To: wietse@porcupine.org (Wietse Venema)
|
||||
Subject: Re: lmtp update
|
||||
References: <20000221181534.11F7C45659@spike.porcupine.org>
|
||||
From: Amos Gouaux <amos@utdallas.edu>
|
||||
Date: 25 Feb 2000 18:04:54 -0600
|
||||
In-Reply-To: wietse@porcupine.org's message of "Mon, 21 Feb 2000 13:15:34 -0500 (EST)"
|
||||
Message-ID: <q6mitzcvnfd.fsf@spartacus.utdallas.edu>
|
||||
Lines: 6
|
||||
User-Agent: Gnus/5.0804 (Gnus v5.8.4) XEmacs/21.1 (Bryce Canyon)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: multipart/mixed; boundary="=-=-="
|
||||
Sender: wietse@porcupine.org
|
||||
Status: RO
|
||||
|
||||
--=-=-=
|
||||
|
||||
How's this?
|
||||
|
||||
Amos
|
||||
|
||||
|
||||
--=-=-=
|
||||
Content-Disposition: attachment; filename=lmtp-man
|
||||
Content-Description: lmtp-man
|
||||
|
||||
.TH LMTP 8
|
||||
.ad
|
||||
.fi
|
||||
.SH NAME
|
||||
lmtp
|
||||
\-
|
||||
Postfix local delivery via LMTP
|
||||
.SH SYNOPSIS
|
||||
.na
|
||||
.nf
|
||||
\fBlmtp\fR [generic Postfix daemon options] [server attributes...]
|
||||
.SH DESCRIPTION
|
||||
.ad
|
||||
.fi
|
||||
The LMTP client processes message delivery requests from
|
||||
the queue manager. Each request specifies a queue file, a sender
|
||||
address, a domain or host to deliver to, and recipient information.
|
||||
This program expects to be run from the \fBmaster\fR(8) process
|
||||
manager.
|
||||
|
||||
The LMTP client updates the queue file and marks recipients
|
||||
as finished, or it informs the queue manager that delivery should
|
||||
be tried again at a later time. Delivery problem reports are sent
|
||||
to the \fBbounce\fR(8) or \fBdefer\fR(8) daemon as appropriate.
|
||||
|
||||
There are two basic modes of operation for the LMTP client:
|
||||
.IP \(bu
|
||||
Communication with a local LMTP server via UNIX domain sockets.
|
||||
.IP \(bu
|
||||
Communication with a (possibly remote) LMTP server via
|
||||
Internet sockets.
|
||||
.PP
|
||||
If no server attributes are specified, the LMTP client will contact
|
||||
the destination host derived from the message delivery request using
|
||||
the TCP port defined as \fBlmtp\fR in \fBservices\fR(4). If no such
|
||||
service is found, the \fBlmtp_tcp_port\fR configuration parameter
|
||||
(default value of 24) will be used.
|
||||
|
||||
In order to use a local LMTP server, this LMTP server will need to
|
||||
be specified via the server attributes described in the following
|
||||
section. Typically, the LMTP client would also be configured as the
|
||||
\fBlocal\fR delivery agent in the \fBmaster.cf\fR file.
|
||||
.SH SERVER ATTRIBUTE SYNTAX
|
||||
.na
|
||||
.nf
|
||||
.ad
|
||||
.fi
|
||||
The server attributes are given in the \fBmaster.cf\fR file at
|
||||
the end of a service definition. The syntax is as follows:
|
||||
.IP "\fBserv\fR=\fItype\fR:\fIserver\fR"
|
||||
The LMTP server to connect to for final delivery. The \fItype\fR
|
||||
portion can be either \fBunix\fR or \fBinet\fR. The \fIserver\fR
|
||||
portion is the path or address of the LMTP server, depending on the
|
||||
value of \fItype\fR, as shown below:
|
||||
.RS
|
||||
.IP "\fBserv=unix:\fR\fIclass\fR\fB/\fR\fIservname\fR"
|
||||
This specifies that the local LMTP server \fIservname\fR should be
|
||||
contacted for final delivery. Both \fIclass\fR (either \fBpublic\fR
|
||||
or \fBprivate\fR) and \fIservname\fR correspond to the LMTP server
|
||||
entry in the \fBmaster.cf\fR file. This LMTP server will likely
|
||||
be defined as a \fBspawn\fR(8) service.
|
||||
.IP "\fBserv=inet:"
|
||||
If nothing follows the \fBinet:\fR type specifier, a connection will
|
||||
be attempted to the destination host indicated in the delivery request.
|
||||
This simplest case is identical to defining the LMTP client without
|
||||
any server attributes at all.
|
||||
.IP "\fBserv=inet:\fR\fIaddress\fR"
|
||||
In this case, an Internet socket will be made to the server
|
||||
specified by \fIaddress\fR. The connection will use a destination
|
||||
port as described in the previous section.
|
||||
.IP "\fBserv=inet:\fR\fIaddress\fR\fB:\fR\fIport\fR"
|
||||
Connect to the LMTP server at \fIaddress\fR, but this time use port
|
||||
\fIport\fR instead of the default \fBlmtp\fR port.
|
||||
.IP "\fBserv=inet:[\fR\fIipaddr\fR\fB]\fR"
|
||||
The LMTP server to contact is specified using an Internet address
|
||||
in the "dot notation". That is, the numeric IP address rather
|
||||
than the DNS name for the server. The default \fBlmtp\fR port
|
||||
is used.
|
||||
.IP "\fBserv=inet:[\fR\fIipaddr\fR\fB]:\fR\fIport\fR"
|
||||
The LMTP server to contact is specified using the numeric IP address,
|
||||
at the port specified.
|
||||
.RE
|
||||
.PP
|
||||
.SH SECURITY
|
||||
.na
|
||||
.nf
|
||||
.ad
|
||||
.fi
|
||||
The LMTP client is moderately security-sensitive. It talks to LMTP
|
||||
servers and to DNS servers on the network. The LMTP client can be
|
||||
run chrooted at fixed low privilege.
|
||||
.SH STANDARDS
|
||||
.na
|
||||
.nf
|
||||
RFC 2033 (LMTP protocol)
|
||||
RFC 821 (SMTP protocol)
|
||||
RFC 1651 (SMTP service extensions)
|
||||
RFC 1870 (Message Size Declaration)
|
||||
RFC 2197 (Pipelining)
|
||||
.SH DIAGNOSTICS
|
||||
.ad
|
||||
.fi
|
||||
Problems and transactions are logged to \fBsyslogd\fR(8).
|
||||
Corrupted message files are marked so that the queue manager can
|
||||
move them to the \fBcorrupt\fR queue for further inspection.
|
||||
|
||||
Depending on the setting of the \fBnotify_classes\fR parameter,
|
||||
the postmaster is notified of bounces, protocol problems, and of
|
||||
other trouble.
|
||||
.SH BUGS
|
||||
.ad
|
||||
.fi
|
||||
.SH CONFIGURATION PARAMETERS
|
||||
.na
|
||||
.nf
|
||||
.ad
|
||||
.fi
|
||||
The following \fBmain.cf\fR parameters are especially relevant to
|
||||
this program. See the Postfix \fBmain.cf\fR file for syntax details
|
||||
and for default values. Use the \fBpostfix reload\fR command after
|
||||
a configuration change.
|
||||
.SH Miscellaneous
|
||||
.ad
|
||||
.fi
|
||||
.IP \fBdebug_peer_level\fR
|
||||
Verbose logging level increment for hosts that match a
|
||||
pattern in the \fBdebug_peer_list\fR parameter.
|
||||
.IP \fBdebug_peer_list\fR
|
||||
List of domain or network patterns. When a remote host matches
|
||||
a pattern, increase the verbose logging level by the amount
|
||||
specified in the \fBdebug_peer_level\fR parameter.
|
||||
.IP \fBerror_notice_recipient\fR
|
||||
Recipient of protocol/policy/resource/software error notices.
|
||||
.IP \fBnotify_classes\fR
|
||||
When this parameter includes the \fBprotocol\fR class, send mail to the
|
||||
postmaster with transcripts of LMTP sessions with protocol errors.
|
||||
.IP \fBlmtp_skip_quit_response\fR
|
||||
Do not wait for the server response after sending QUIT.
|
||||
.IP \fBlmtp_tcp_port\fR
|
||||
The TCP port to be used when connecting to a LMTP server. Used as
|
||||
backup if the \fBlmtp\fR service is not found in \fBservices\fR(4).
|
||||
.SH "Resource controls"
|
||||
.ad
|
||||
.fi
|
||||
.IP \fBlmtp_cache_connection\fR
|
||||
Should we cache the connection to the LMTP server? The effectiveness
|
||||
of cached connections will be determined by the number of LMTP servers
|
||||
in use, and the concurrency limit specified for the LMTP client.
|
||||
Cached connections are closed under any of the following conditions:
|
||||
.RS
|
||||
.IP \(bu
|
||||
The idle timeout for the LMTP client is reached. This limit is
|
||||
enforced by \fBmaster\fR(8).
|
||||
.IP \(bu
|
||||
A message request to a different destination than the one currently
|
||||
cached.
|
||||
.IP \(bu
|
||||
The maximum number of requests per session is reached. This limit is
|
||||
enforced by \fBmaster\fR(8).
|
||||
.IP \(bu
|
||||
Upon the onset of another delivery request, the LMTP server associated
|
||||
with the current session does not respond to the \fBRSET\fR command.
|
||||
.RE
|
||||
.IP \fBlmtp_destination_concurrency_limit\fR
|
||||
Limit the number of parallel deliveries to the same destination.
|
||||
The default limit is taken from the
|
||||
\fBdefault_destination_concurrency_limit\fR parameter.
|
||||
.IP \fBlmtp_destination_recipient_limit\fR
|
||||
Limit the number of recipients per message delivery.
|
||||
The default limit is taken from the
|
||||
\fBdefault_destination_recipient_limit\fR parameter.
|
||||
.IP \fBlocal_destination_recipient_limit\fR
|
||||
Limit the number of recipients per message delivery.
|
||||
The default limit is taken from the
|
||||
\fBdefault_destination_recipient_limit\fR parameter.
|
||||
|
||||
This parameter becomes significant if the LMTP client is used
|
||||
for local delivery. Some LMTP servers can optimize final delivery
|
||||
if multiple recipients are allowed. Therefore, it may be advantageous
|
||||
to set this to some number greater than one, depending on the capabilities
|
||||
of the machine.
|
||||
|
||||
Setting this parameter to 0 will lead to an unlimited number of
|
||||
recipients per delivery. However, this could be risky since it may
|
||||
make the machine vulnerable to running out of resources if messages
|
||||
are encountered with an inordinate number of recipients. Exercise
|
||||
care when setting this parameter.
|
||||
.SH "Timeout controls"
|
||||
.ad
|
||||
.fi
|
||||
.IP \fBlmtp_connect_timeout\fR
|
||||
Timeout in seconds for opening a connection to the LMTP server.
|
||||
If no connection can be made within the deadline, the message
|
||||
is deferred.
|
||||
.IP \fBlmtp_lhlo_timeout\fR
|
||||
Timeout in seconds for sending the \fBLHLO\fR command, and for
|
||||
receiving the server response.
|
||||
.IP \fBlmtp_mail_timeout\fR
|
||||
Timeout in seconds for sending the \fBMAIL FROM\fR command, and for
|
||||
receiving the server response.
|
||||
.IP \fBlmtp_rcpt_timeout\fR
|
||||
Timeout in seconds for sending the \fBRCPT TO\fR command, and for
|
||||
receiving the server response.
|
||||
.IP \fBlmtp_data_init_timeout\fR
|
||||
Timeout in seconds for sending the \fBDATA\fR command, and for
|
||||
receiving the server response.
|
||||
.IP \fBlmtp_data_xfer_timeout\fR
|
||||
Timeout in seconds for sending the message content.
|
||||
.IP \fBlmtp_data_done_timeout\fR
|
||||
Timeout in seconds for sending the "\fB.\fR" command, and for
|
||||
receiving the server response. When no response is received, a
|
||||
warning is logged that the mail may be delivered multiple times.
|
||||
.IP \fBlmtp_rset_timeout\fR
|
||||
Timeout in seconds for sending the \fBRSET\fR command, and for
|
||||
receiving the server response.
|
||||
.IP \fBlmtp_quit_timeout\fR
|
||||
Timeout in seconds for sending the \fBQUIT\fR command, and for
|
||||
receiving the server response.
|
||||
.SH SEE ALSO
|
||||
.na
|
||||
.nf
|
||||
bounce(8) non-delivery status reports
|
||||
local(8) local mail delivery
|
||||
master(8) process manager
|
||||
qmgr(8) queue manager
|
||||
services(4) Internet services and aliases
|
||||
spawn(8) auxiliary command spawner
|
||||
syslogd(8) system logging
|
||||
.SH LICENSE
|
||||
.na
|
||||
.nf
|
||||
.ad
|
||||
.fi
|
||||
The Secure Mailer license must be distributed with this software.
|
||||
.SH AUTHOR(S)
|
||||
.na
|
||||
.nf
|
||||
Wietse Venema
|
||||
IBM T.J. Watson Research
|
||||
P.O. Box 704
|
||||
Yorktown Heights, NY 10598, USA
|
||||
|
||||
Alterations for LMTP by:
|
||||
Philip A. Prindeville
|
||||
Mirapoint, Inc.
|
||||
USA.
|
||||
|
||||
Additional work on LMTP by:
|
||||
Amos Gouaux
|
||||
University of Texas at Dallas
|
||||
P.O. Box 830688, MC34
|
||||
Richardson, TX 75083, USA
|
||||
|
||||
--=-=-=--
|
||||
|
||||
|
||||
|
||||
|
||||
From wietse@porcupine.org Sat Feb 5 09:32:03 2000
|
||||
Return-Path: <wietse@porcupine.org>
|
||||
Delivered-To: wietse@hades.porcupine.org
|
||||
Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
|
||||
by hades.porcupine.org (Postfix) with ESMTP id A7661188A7
|
||||
for <wietse@hades.porcupine.org>; Sat, 5 Feb 2000 09:32:03 -0500 (EST)
|
||||
Received: by spike.porcupine.org (Postfix, from userid 100)
|
||||
id 700394563E; Sat, 5 Feb 2000 09:32:03 -0500 (EST)
|
||||
Delivered-To: wietse@porcupine.org
|
||||
Received: from ns0.utdallas.edu (ns0.utdallas.edu [129.110.10.1])
|
||||
by spike.porcupine.org (Postfix) with ESMTP id 605FE4563C
|
||||
for <wietse@porcupine.org>; Mon, 31 Jan 2000 18:35:02 -0500 (EST)
|
||||
Received: from spartacus.utdallas.edu (spartacus.utdallas.edu [129.110.3.11])
|
||||
by ns0.utdallas.edu (Postfix) with SMTP id 02E4C1A005D
|
||||
for <wietse@porcupine.org>; Mon, 31 Jan 2000 17:34:59 -0600 (CST)
|
||||
To: wietse@porcupine.org (Wietse Venema)
|
||||
Subject: Re: lmtp-20000130.tar.gz
|
||||
References: <20000131225228.008114563F@spike.porcupine.org>
|
||||
From: Amos Gouaux <amos@utdallas.edu>
|
||||
Date: 31 Jan 2000 17:35:34 -0600
|
||||
In-Reply-To: wietse@porcupine.org's message of "Mon, 31 Jan 2000 17:52:28 -0500 (EST)"
|
||||
Message-ID: <q6mzotlvmpl.fsf@spartacus.utdallas.edu>
|
||||
Lines: 119
|
||||
User-Agent: Gnus/5.0803 (Gnus v5.8.3) XEmacs/21.1 (Bryce Canyon)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
Sender: wietse@porcupine.org
|
||||
Status: O
|
||||
|
||||
>>>>> On Mon, 31 Jan 2000 17:52:28 -0500 (EST),
|
||||
>>>>> Wietse Venema <wietse@porcupine.org> (wv) writes:
|
||||
|
||||
wv> For local transports, command pipelining does not have the benefit
|
||||
wv> that it has for TCP over non-local connections.
|
||||
|
||||
So in other words I was making things too complicated.
|
||||
Figures. I have a knack for doing that.
|
||||
|
||||
I've updated alpha-lmtp.tar.gz again.
|
||||
|
||||
Here's the CHANGES file:
|
||||
|
||||
|
||||
2000 Jan 31
|
||||
|
||||
* lmtp_proto.c:lmtp_lhlo: Don't worry about LMTP_FEATURE_PIPELINING
|
||||
for sessions of type LMTP_SERV_TYPE_UNIX.
|
||||
|
||||
|
||||
2000 Jan 30
|
||||
|
||||
* BIG changes. Removed all the pipe stuff from lmtp.c and
|
||||
lmtp_connect.c Now, lmtp will either do a remote connection much
|
||||
like the smtp client, or it will connect to a UNIX domain socket
|
||||
to an auxiliary service (spawn). This makes the lmtp patch
|
||||
simpler because it doesn't have to worry at all about exec-ing an
|
||||
external command, and all the resulting security implications.
|
||||
See README.local for details.
|
||||
|
||||
NOTE: postfix-19991231-pl04 is REQUIRED for this to work!
|
||||
(Need the "spawn" service.)
|
||||
|
||||
* Updated the makefile-patch for postfix-19991231-pl03.
|
||||
|
||||
* lmtp.h: changed the LMTP_ATTR structure to contain "type", "class", and
|
||||
"name" fields, reflecting the change from the pipe mechanism to
|
||||
the local sockets connection. Changed LMTP_SESSION to contain the
|
||||
"type" field. The connection type is recorded in this field in
|
||||
case it is needed elsewhere, like in lmtp_proto.
|
||||
|
||||
* lmtp.c:get_service_attr altered for new command syntax. Examples:
|
||||
|
||||
serv=unix:private/lmtpd
|
||||
serv=inet:public/lmtpd
|
||||
|
||||
After `serv=' is the "type", followed by `:', then the "class",
|
||||
followed by '/', and then finally the "name".
|
||||
|
||||
* Added SAME_DESTINATION macro to lmtp.c:deliver_message for
|
||||
readability, and simpler logic.
|
||||
|
||||
* lmtp_connect.c: changed lmtp_connect to contain logic to determine
|
||||
just what kind of connection to make, removing it from lmtp.c;
|
||||
removed lmtp_connect_pipe; and added lmtp_connect_local, which
|
||||
uses mail_connect_wait to connect to the service running the LMTP
|
||||
server (spawn). In lmtp_connect, the connection type stored in
|
||||
attr.type is saved into session.type, so it can be used later if
|
||||
necessary.
|
||||
|
||||
* lmtp_proto.c:lmtp_lhlo: towards the end of this function we check
|
||||
to see if service->type is LMTP_SERV_TYPE_UNIX so that we don't
|
||||
try to do a getsockopt on a descriptor that doesn't support it.
|
||||
Is this the best way to handle this? Or maybe we should just try
|
||||
it and if it bombs, check the error code before simply going
|
||||
fatal?
|
||||
|
||||
* Snagged the latest quota_821_local.c from the smtp client.
|
||||
|
||||
* Updated the README files accordingly.
|
||||
|
||||
|
||||
2000 Jan 28
|
||||
|
||||
* Well, wondering about using REWRITE_ADDRESS in lmtp_proto.c,
|
||||
putting the lowercase thing in there. Though, that would also
|
||||
apply to sender address. Is that okay?
|
||||
|
||||
* We shouldn't be doing DNS lookups at this stage, so can get rid
|
||||
of lmtp_unalias.c. Also cut out the unalias portion in
|
||||
REWRITE_ADDRESS in lmtp_proto.c
|
||||
|
||||
|
||||
2000 Jan 11
|
||||
|
||||
* At the suggestion of Rupa Schomaker, added the following to
|
||||
lmtp_proto.c:
|
||||
|
||||
lowercase(rcpt->address); /* [AAG] rupa */
|
||||
|
||||
|
||||
1999 Dec 1 (or thereabouts)
|
||||
|
||||
* Added lmtp_session_reset to make it easier to remember to reset
|
||||
certain things to 0. Did this to lmtp_chat_reset too.
|
||||
|
||||
* Finally, did some work with the connection caching so that an RSET
|
||||
is sent to the LMTP server. This is done for two reasons: first,
|
||||
to tell the LMTP server to flush out any status information
|
||||
because we're about to feed it another message, and second, to
|
||||
test the link to see if it is still alive. If the link has died
|
||||
for some reason, it is reestablished. Changes to lmtp.c and
|
||||
lmtp_proto.c.
|
||||
|
||||
* There was also some tidying in lmtp.c so that things were a little
|
||||
clearer as to what was going on. I added a few more comments as
|
||||
well.
|
||||
|
||||
* I tried to make the master.cf argument parsing a little more
|
||||
consistent with the other Postfix services. Changes to lmtp.c.
|
||||
|
||||
* On the postfix-users mailing list, Valery Brasseur pointed out that
|
||||
errors encountered during LMTP delivery were not getting bounced
|
||||
as appropriate. This lead me to investigate the matter, wanting
|
||||
to put this LMTP capability into service myself. I then realized
|
||||
that some of the error checking was a tad over zealous, and so
|
||||
simplified things a bit in lmtp_proto.c.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
From wietse@porcupine.org Wed Dec 8 19:50:01 1999
|
||||
Return-Path: <wietse@porcupine.org>
|
||||
Delivered-To: wietse@hades.porcupine.org
|
||||
Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
|
||||
by hades.porcupine.org (Postfix) with ESMTP id D83EE18868
|
||||
for <wietse@hades.porcupine.org>; Wed, 8 Dec 1999 19:50:00 -0500 (EST)
|
||||
Received: by spike.porcupine.org (Postfix, from userid 100)
|
||||
id 827F645AFB; Wed, 8 Dec 1999 10:51:18 -0500 (EST)
|
||||
Delivered-To: wietse@porcupine.org
|
||||
Received: from ns0.utdallas.edu (ns0.utdallas.edu [129.110.10.1])
|
||||
by spike.porcupine.org (Postfix) with ESMTP id 90E1A457F8
|
||||
for <wietse@porcupine.org>; Tue, 7 Dec 1999 11:37:16 -0500 (EST)
|
||||
Received: from spartacus.utdallas.edu (spartacus.utdallas.edu [129.110.3.11])
|
||||
by ns0.utdallas.edu (Postfix) with SMTP id 139E719FFFE
|
||||
for <wietse@porcupine.org>; Tue, 7 Dec 1999 10:37:02 -0600 (CST)
|
||||
To: wietse@porcupine.org (Wietse Venema)
|
||||
Subject: Re: LMTP stuff
|
||||
References: <19991206162939.1C9BB458EB@spike.porcupine.org>
|
||||
From: Amos Gouaux <amos+lists.postfix@utdallas.edu>
|
||||
Date: 07 Dec 1999 10:37:25 -0600
|
||||
In-Reply-To: wietse@porcupine.org's message of "Mon, 6 Dec 1999 11:29:38 -0500 (EST)"
|
||||
Message-ID: <q6m7liqiu62.fsf@spartacus.utdallas.edu>
|
||||
Lines: 46
|
||||
User-Agent: Gnus/5.070099 (Pterodactyl Gnus v0.99) XEmacs/21.1 (Bryce Canyon)
|
||||
MIME-Version: 1.0
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
Sender: wietse@porcupine.org
|
||||
Status: RO
|
||||
|
||||
Okay, I put out the following tar file:
|
||||
|
||||
ftp://ftp.utdallas.edu/pub/staff/amos/postfix/lmtp-19990427-02.tar.gz
|
||||
|
||||
It's not quite as tidy as I would like it, and hope to eventually
|
||||
make it. I've been making changes gradually, in part because it
|
||||
might be fun to play with the connection caching later, and in part
|
||||
because I'm new to the internals of Postfix. Speaking of which, I
|
||||
must say it has been a real pleasure poking around this code. It's
|
||||
fascinating to see how you've created this infrastructure by which
|
||||
all the various components communicate with one another. Pretty
|
||||
slick stuff. Very educational too.
|
||||
|
||||
Most of the changes are in lmtp_proto.c and lmtp.c. I noticed in
|
||||
the former that he's passing status around a lot, using the
|
||||
recv_state and send_state members instead of using local vars for
|
||||
these values. I'm guess that was to keep track of the state
|
||||
throughout the connection caching. I left that as is.
|
||||
|
||||
In lmtp.c I removed the for loop he had, and parse the argv in a
|
||||
separate function to make it a bit cleaner. I'm assuming that with
|
||||
the lmtp service there won't be much of a need to expand the argv
|
||||
like it is with the pipe service, correct?
|
||||
|
||||
After seeing one of your posts yesterday about the nexthop arg to
|
||||
pipe, I'm wondering if this lmtp should support that as well. I
|
||||
noticed in the LMTP RFC that this LMTP can either be a local
|
||||
program, or communicate to a "Gateway Delivery Agent". If there was
|
||||
a nexthop arg to lmtp, folks could specify this gateway host there.
|
||||
Or, they could use the transport map and not define any args to lmtp
|
||||
at all.
|
||||
|
||||
It's amazing how much time can be consumed just contemplating what
|
||||
args should be permissible, and what's the most efficient way to
|
||||
process them. I was even wondering, if no variable expansion should
|
||||
take place, if `LMTP_ATTR attr' should be global, and the call to
|
||||
get_service_attr placed in a function pointed to by
|
||||
MAIL_SERVER_PRE_INIT so it's only invoked once. Still more things
|
||||
to learn.
|
||||
|
||||
Oh well, I've flung quite a bit mail at this thing and it seems to
|
||||
be handling it fine. So perhaps it will at least be sufficient to
|
||||
satisfy folks for the time being.
|
||||
|
||||
Amos
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
From wietse@porcupine.org Tue Nov 23 18:09:44 1999
|
||||
Return-Path: <wietse@porcupine.org>
|
||||
Delivered-To: wietse@hades.porcupine.org
|
||||
Received: from spike.porcupine.org (spike.porcupine.org [168.100.189.2])
|
||||
by hades.porcupine.org (Postfix) with ESMTP id BD43F18864
|
||||
for <wietse@hades.porcupine.org>; Tue, 23 Nov 1999 18:09:44 -0500 (EST)
|
||||
Received: by spike.porcupine.org (Postfix, from userid 100)
|
||||
id 4CC0445A9B; Tue, 23 Nov 1999 13:24:06 -0500 (EST)
|
||||
Delivered-To: wietse@porcupine.org
|
||||
Received: from russian-caravan.cloud9.net (russian-caravan.cloud9.net [168.100.1.4])
|
||||
by spike.porcupine.org (Postfix) with ESMTP id 979F145A9A
|
||||
for <wietse@porcupine.org>; Tue, 23 Nov 1999 13:19:06 -0500 (EST)
|
||||
Received: by russian-caravan.cloud9.net (Postfix)
|
||||
id AE6E576434; Tue, 23 Nov 1999 13:16:34 -0500 (EST)
|
||||
Delivered-To: postfix-users-outgoing@cloud9.net
|
||||
Received: by russian-caravan.cloud9.net (Postfix, from userid 54)
|
||||
id 340DA76423; Tue, 23 Nov 1999 13:16:34 -0500 (EST)
|
||||
Delivered-To: postfix-users@cloud9.net
|
||||
Received: from atn01.axime.com (atn01.axime.com [160.92.1.141])
|
||||
by russian-caravan.cloud9.net (Postfix) with ESMTP id 32BE6763C6
|
||||
for <postfix-users@postfix.org>; Tue, 23 Nov 1999 13:16:32 -0500 (EST)
|
||||
Received: from atos-group.com (sys-pc21.segin.com [172.18.2.119])
|
||||
by atn01.axime.com (8.8.8/8.8.8[Atos Multimedia]) with ESMTP id TAA25333;
|
||||
Tue, 23 Nov 1999 19:16:20 +0100 (MET)
|
||||
Message-ID: <383AD9F2.8915CCA6@atos-group.com>
|
||||
Date: Tue, 23 Nov 1999 18:16:18 +0000
|
||||
From: valery brasseur <vbrasseur@atos-group.com>
|
||||
Organization: Atos Multimedia
|
||||
X-Mailer: Mozilla 4.7 [en] (X11; I; Linux 2.2.12 i686)
|
||||
X-Accept-Language: en, fr-FR
|
||||
MIME-Version: 1.0
|
||||
To: Amos Gouaux <amos+lists.postfix@utdallas.edu>
|
||||
Cc: postfix-users@postfix.org
|
||||
Subject: Re: LMTP?
|
||||
References: <q6memdj3djk.fsf@spartacus.utdallas.edu> <3839189C.C4E94EA1@atos-group.com> <q6mso1yn00k.fsf@spartacus.utdallas.edu>
|
||||
Content-Type: text/plain; charset=us-ascii
|
||||
Content-Transfer-Encoding: 7bit
|
||||
Precedence: bulk
|
||||
Sender: wietse@porcupine.org
|
||||
Status: RO
|
||||
|
||||
Here is the patch a use on the lmtp part of postfix for using LMTP on
|
||||
Solaris (note that these diffs are not necessary for Linux !)
|
||||
It's seems that the probleme come from the interpretation of the return
|
||||
code from cyrus-deliver.
|
||||
|
||||
note : they are against lmtp-19990427.tar.gz
|
||||
|
||||
--- lmtp/lmtp_proto.c Tue Apr 20 09:42:45 1999
|
||||
+++ /postfix-19990906/lmtp/lmtp_proto.c Thu Sep 2 15:04:57 1999
|
||||
@@ -445,12 +445,12 @@
|
||||
if (resp->code / 100 == 2) {
|
||||
++nrcpt;
|
||||
recipient_list_add(&survivors, rcpt->offset,
|
||||
rcpt->address);
|
||||
- } else if (resp->code == 550
|
||||
+ } else /* if (resp->code == 550
|
||||
&& strncmp(resp->str, "550 5.1.1", 9)
|
||||
== 0) {
|
||||
deliver_completed(state->src, -1);
|
||||
state->status |= -1;
|
||||
rcpt->offset = 0;
|
||||
- } else {
|
||||
+ } else */ {o
|
||||
lmtp_rcpt_fail(state, resp->code, rcpt,
|
||||
"host %s said: %s",
|
||||
session->host,
|
||||
translit(resp->str, "\n", "
|
||||
"));
|
||||
|
||||
|
||||
Hope it will help.
|
||||
|
||||
Amos Gouaux wrote:
|
||||
>
|
||||
> >>>>> On Mon, 22 Nov 1999 10:19:08 +0000,
|
||||
> >>>>> valery brasseur <vbrasseur@atos-group.com> (vb) writes:
|
||||
>
|
||||
> vb> I use it with cyrus, but I have done made some patch to the LMTP code
|
||||
> vb> and deliver code because return code where not what the other was
|
||||
> vb> expected !!!
|
||||
>
|
||||
> Do you think you could submit these patches to the list?
|
||||
>
|
||||
> I knew something had to be amiss. Using the Postfix sendmail
|
||||
> command I attempted to send mail to a non-existent user, jdoe. The
|
||||
> syslog from Postfix indicated successful delivery:
|
||||
>
|
||||
> Nov 22 07:03:45 area52 postfix/pipe[3082]: 6316124718: to=<jdoe@area52.utdallas.edu>, relay=lmtp, delay=0, status=sent (jdoe@area52.utdallas.edu)
|
||||
>
|
||||
> However, when I run deliver by hand, the response isn't so positive:
|
||||
>
|
||||
> rcpt to:<jdoe@area52.utdallas.edu>
|
||||
> 550 5.1.1 User unknown
|
||||
>
|
||||
> Thanks,
|
||||
> Amos
|
||||
|
||||
--
|
||||
Valery BRASSEUR | Phone # +33 320 60 7982
|
||||
Atos Branche Multimedia | Fax # +33 320 60 7649
|
||||
"Unix -- where you can do anything in two keystrokes or less..."
|
||||
-- Unknown
|
||||
|
||||
|
||||
|
||||
|
19
postfix/lmtp/makefile-patch
Normal file
19
postfix/lmtp/makefile-patch
Normal file
@ -0,0 +1,19 @@
|
||||
*** ../../orig/Makefile.in Fri Dec 31 09:49:41 1999
|
||||
--- Makefile.in Fri Feb 25 16:27:24 2000
|
||||
***************
|
||||
*** 4,10 ****
|
||||
DIRS = util global dns master postfix smtpstone sendmail error \
|
||||
pickup cleanup smtpd local trivial-rewrite qmgr smtp bounce pipe \
|
||||
showq postalias postcat postconf postdrop postkick postlock postlog \
|
||||
! postmap postsuper # spawn man html
|
||||
|
||||
default: update
|
||||
|
||||
--- 4,10 ----
|
||||
DIRS = util global dns master postfix smtpstone sendmail error \
|
||||
pickup cleanup smtpd local trivial-rewrite qmgr smtp bounce pipe \
|
||||
showq postalias postcat postconf postdrop postkick postlock postlog \
|
||||
! postmap postsuper lmtp spawn man # html
|
||||
|
||||
default: update
|
||||
|
218
postfix/lmtp/man-patch
Normal file
218
postfix/lmtp/man-patch
Normal file
@ -0,0 +1,218 @@
|
||||
*** ../../orig/man/Makefile.in Thu Jun 24 18:39:22 1999
|
||||
--- man/Makefile.in Fri Feb 25 16:35:53 2000
|
||||
***************
|
||||
*** 2,8 ****
|
||||
|
||||
DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
|
||||
man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 man8/showq.8 \
|
||||
! man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8
|
||||
COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
|
||||
man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
|
||||
man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
|
||||
--- 2,8 ----
|
||||
|
||||
DAEMONS = man8/bounce.8 man8/defer.8 man8/cleanup.8 man8/error.8 man8/local.8 \
|
||||
man8/master.8 man8/pickup.8 man8/pipe.8 man8/qmgr.8 man8/showq.8 \
|
||||
! man8/smtp.8 man8/smtpd.8 man8/trivial-rewrite.8 man8/lmtp.8
|
||||
COMMANDS= man1/postalias.1 man1/postcat.1 man1/postconf.1 man1/postfix.1 \
|
||||
man1/postkick.1 man1/postlock.1 man1/postlog.1 man1/postdrop.1 \
|
||||
man1/postmap.1 man1/sendmail.1 man1/mailq.1 man1/newaliases.1 \
|
||||
***************
|
||||
*** 24,99 ****
|
||||
rm -f $(DAEMONS) $(COMMANDS) $(CONFIG)
|
||||
|
||||
man8/bounce.8: ../bounce/bounce.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/defer.8:
|
||||
echo .so man8/bounce.8 >$@
|
||||
|
||||
man8/cleanup.8: ../cleanup/cleanup.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/error.8: ../error/error.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/local.8: ../local/local.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/master.8: ../master/master.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/pickup.8: ../pickup/pickup.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/pipe.8: ../pipe/pipe.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/qmgr.8: ../qmgr/qmgr.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/showq.8: ../showq/showq.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/smtp.8: ../smtp/smtp.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/smtpd.8: ../smtpd/smtpd.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man8/trivial-rewrite.8: ../trivial-rewrite/trivial-rewrite.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postalias.1: ../postalias/postalias.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postcat.1: ../postcat/postcat.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postconf.1: ../postconf/postconf.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postdrop.1: ../postdrop/postdrop.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postfix.1: ../postfix/postfix.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postkick.1: ../postkick/postkick.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postlock.1: ../postlock/postlock.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postlog.1: ../postlog/postlog.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postmap.1: ../postmap/postmap.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/postsuper.1: ../postsuper/postsuper.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/sendmail.1: ../sendmail/sendmail.c
|
||||
! srctoman $? >$@
|
||||
|
||||
man1/mailq.1:
|
||||
echo .so man1/sendmail.1 >$@
|
||||
--- 24,102 ----
|
||||
rm -f $(DAEMONS) $(COMMANDS) $(CONFIG)
|
||||
|
||||
man8/bounce.8: ../bounce/bounce.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/defer.8:
|
||||
echo .so man8/bounce.8 >$@
|
||||
|
||||
man8/cleanup.8: ../cleanup/cleanup.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/error.8: ../error/error.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/local.8: ../local/local.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/master.8: ../master/master.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/pickup.8: ../pickup/pickup.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/pipe.8: ../pipe/pipe.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/qmgr.8: ../qmgr/qmgr.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/showq.8: ../showq/showq.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/smtp.8: ../smtp/smtp.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/smtpd.8: ../smtpd/smtpd.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man8/trivial-rewrite.8: ../trivial-rewrite/trivial-rewrite.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
+ man8/lmtp.8: ../lmtp/lmtp.c
|
||||
+ ../mantools/srctoman $? >$@
|
||||
+
|
||||
man1/postalias.1: ../postalias/postalias.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/postcat.1: ../postcat/postcat.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/postconf.1: ../postconf/postconf.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/postdrop.1: ../postdrop/postdrop.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/postfix.1: ../postfix/postfix.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/postkick.1: ../postkick/postkick.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/postlock.1: ../postlock/postlock.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/postlog.1: ../postlog/postlog.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/postmap.1: ../postmap/postmap.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/postsuper.1: ../postsuper/postsuper.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/sendmail.1: ../sendmail/sendmail.c
|
||||
! ../mantools/srctoman $? >$@
|
||||
|
||||
man1/mailq.1:
|
||||
echo .so man1/sendmail.1 >$@
|
||||
***************
|
||||
*** 102,120 ****
|
||||
echo .so man1/sendmail.1 >$@
|
||||
|
||||
man5/access.5: ../conf/access
|
||||
! srctoman - $? >$@
|
||||
|
||||
man5/aliases.5: ../conf/aliases
|
||||
! srctoman - $? >$@
|
||||
|
||||
man5/canonical.5: ../conf/canonical
|
||||
! srctoman - $? >$@
|
||||
|
||||
man5/relocated.5: ../conf/relocated
|
||||
! srctoman - $? >$@
|
||||
|
||||
man5/transport.5: ../conf/transport
|
||||
! srctoman - $? >$@
|
||||
|
||||
man5/virtual.5: ../conf/virtual
|
||||
! srctoman - $? >$@
|
||||
--- 105,123 ----
|
||||
echo .so man1/sendmail.1 >$@
|
||||
|
||||
man5/access.5: ../conf/access
|
||||
! ../mantools/srctoman - $? >$@
|
||||
|
||||
man5/aliases.5: ../conf/aliases
|
||||
! ../mantools/srctoman - $? >$@
|
||||
|
||||
man5/canonical.5: ../conf/canonical
|
||||
! ../mantools/srctoman - $? >$@
|
||||
|
||||
man5/relocated.5: ../conf/relocated
|
||||
! ../mantools/srctoman - $? >$@
|
||||
|
||||
man5/transport.5: ../conf/transport
|
||||
! ../mantools/srctoman - $? >$@
|
||||
|
||||
man5/virtual.5: ../conf/virtual
|
||||
! ../mantools/srctoman - $? >$@
|
170
postfix/lmtp/quote_821_local.c
Normal file
170
postfix/lmtp/quote_821_local.c
Normal file
@ -0,0 +1,170 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* quote_821_local 3
|
||||
/* SUMMARY
|
||||
/* quote local part of address
|
||||
/* SYNOPSIS
|
||||
/* #include "quote_821_local.h"
|
||||
/*
|
||||
/* VSTRING *quote_821_local(dst, src)
|
||||
/* VSTRING *dst;
|
||||
/* char *src;
|
||||
/* DESCRIPTION
|
||||
/* quote_821_local() quotes the local part of a mailbox address and
|
||||
/* returns a result that can be used in SMTP commands as specified
|
||||
/* by RFC 821.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP dst
|
||||
/* The result.
|
||||
/* .IP src
|
||||
/* The input address.
|
||||
/* STANDARDS
|
||||
/* RFC 821 (SMTP protocol)
|
||||
/* BUGS
|
||||
/* The code assumes that the domain is RFC 821 clean.
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <vstring.h>
|
||||
|
||||
/* Global library. */
|
||||
|
||||
#include "quote_821_local.h"
|
||||
|
||||
/* Application-specific. */
|
||||
|
||||
#define YES 1
|
||||
#define NO 0
|
||||
|
||||
/* is_821_dot_string - is this local-part an rfc 821 dot-string? */
|
||||
|
||||
static int is_821_dot_string(char *local_part, char *end)
|
||||
{
|
||||
char *cp;
|
||||
int ch;
|
||||
|
||||
/*
|
||||
* Detect any deviations from the definition of dot-string. We could use
|
||||
* lookup tables to speed up some of the work, but hey, how large can a
|
||||
* local-part be anyway?
|
||||
*/
|
||||
if (local_part[0] == 0 || local_part[0] == '.')
|
||||
return (NO);
|
||||
for (cp = local_part; cp < end && (ch = *cp) != 0; cp++) {
|
||||
if (ch == '.' && cp[1] == '.')
|
||||
return (NO);
|
||||
if (ch > 127)
|
||||
return (NO);
|
||||
if (ch == ' ')
|
||||
return (NO);
|
||||
if (ISCNTRL(ch))
|
||||
return (NO);
|
||||
if (ch == '<' || ch == '>'
|
||||
|| ch == '(' || ch == ')'
|
||||
|| ch == '[' || ch == ']'
|
||||
|| ch == '\\' || ch == ','
|
||||
|| ch == ';' || ch == ':'
|
||||
/* || ch == '@' */ || ch == '"')
|
||||
return (NO);
|
||||
}
|
||||
if (cp[-1] == '.')
|
||||
return (NO);
|
||||
return (YES);
|
||||
}
|
||||
|
||||
/* make_821_quoted_string - make quoted-string from local-part */
|
||||
|
||||
static VSTRING *make_821_quoted_string(VSTRING *dst, char *local_part, char *end)
|
||||
{
|
||||
char *cp;
|
||||
int ch;
|
||||
|
||||
/*
|
||||
* Put quotes around the result, and prepend a backslash to characters
|
||||
* that need quoting when they occur in a quoted-string.
|
||||
*/
|
||||
VSTRING_RESET(dst);
|
||||
VSTRING_ADDCH(dst, '"');
|
||||
for (cp = local_part; cp < end && (ch = *cp) != 0; cp++) {
|
||||
if (ch > 127 || ch == '\r' || ch == '\n' || ch == '"' || ch == '\\')
|
||||
VSTRING_ADDCH(dst, '\\');
|
||||
VSTRING_ADDCH(dst, ch);
|
||||
}
|
||||
VSTRING_ADDCH(dst, '"');
|
||||
VSTRING_TERMINATE(dst);
|
||||
return (dst);
|
||||
}
|
||||
|
||||
/* quote_821_local - quote local part of address according to rfc 821 */
|
||||
|
||||
VSTRING *quote_821_local(VSTRING *dst, char *addr)
|
||||
{
|
||||
char *at;
|
||||
|
||||
/*
|
||||
* According to RFC 821, a local-part is a dot-string or a quoted-string.
|
||||
* We first see if the local-part is a dot-string. If it is not, we turn
|
||||
* it into a quoted-string. Anything else would be too painful.
|
||||
*/
|
||||
if ((at = strrchr(addr, '@')) == 0) /* just in case */
|
||||
at = addr + strlen(addr); /* should not happen */
|
||||
if (is_821_dot_string(addr, at)) {
|
||||
return (vstring_strcpy(dst, addr));
|
||||
} else {
|
||||
make_821_quoted_string(dst, addr, at);
|
||||
return (vstring_strcat(dst, at));
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef TEST
|
||||
|
||||
/*
|
||||
* Test program for local-part quoting as per rfc 821
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <vstream.h>
|
||||
#include <vstring_vstream.h>
|
||||
#include "quote_821_local.h"
|
||||
|
||||
main(void)
|
||||
{
|
||||
VSTRING *src = vstring_alloc(100);
|
||||
VSTRING *dst = vstring_alloc(100);
|
||||
|
||||
while (vstring_fgets_nonl(src, VSTREAM_IN)) {
|
||||
vstream_fprintf(VSTREAM_OUT, "%s\n",
|
||||
vstring_str(quote_821_local(dst, vstring_str(src))));
|
||||
vstream_fflush(VSTREAM_OUT);
|
||||
}
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#endif
|
41
postfix/lmtp/quote_821_local.h
Normal file
41
postfix/lmtp/quote_821_local.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* quote_821_local 3h
|
||||
/* SUMMARY
|
||||
/* quote rfc 821 local part
|
||||
/* SYNOPSIS
|
||||
/* #include "quote_821_local.h"
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* Utility library.
|
||||
*/
|
||||
#include <vstring.h>
|
||||
|
||||
/*
|
||||
* External interface.
|
||||
*/
|
||||
extern VSTRING *quote_821_local(VSTRING *, char *);
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*
|
||||
/* Alterations for LMTP by:
|
||||
/* Philip A. Prindeville
|
||||
/* Mirapoint, Inc.
|
||||
/* USA.
|
||||
/*
|
||||
/* Additional work on LMTP by:
|
||||
/* Amos Gouaux
|
||||
/* University of Texas at Dallas
|
||||
/* P.O. Box 830688, MC34
|
||||
/* Richardson, TX 75083, USA
|
||||
/*--*/
|
4
postfix/local/.indent.pro
vendored
4
postfix/local/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/master/.indent.pro
vendored
4
postfix/master/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/pickup/.indent.pro
vendored
4
postfix/pickup/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/pipe/.indent.pro
vendored
4
postfix/pipe/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postalias/.indent.pro
vendored
4
postfix/postalias/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postcat/.indent.pro
vendored
4
postfix/postcat/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postconf/.indent.pro
vendored
4
postfix/postconf/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postdrop/.indent.pro
vendored
4
postfix/postdrop/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postfix/.indent.pro
vendored
4
postfix/postfix/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postkick/.indent.pro
vendored
4
postfix/postkick/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postlock/.indent.pro
vendored
4
postfix/postlock/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postlog/.indent.pro
vendored
4
postfix/postlog/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postmap/.indent.pro
vendored
4
postfix/postmap/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/postsuper/.indent.pro
vendored
4
postfix/postsuper/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/qmgr/.indent.pro
vendored
4
postfix/qmgr/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/sendmail/.indent.pro
vendored
4
postfix/sendmail/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/showq/.indent.pro
vendored
4
postfix/showq/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/smtp/.indent.pro
vendored
4
postfix/smtp/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
@ -97,6 +97,7 @@
|
||||
/* .SH "Authentication controls"
|
||||
/* .IP \fBsmtp_enable_sasl_auth\fR
|
||||
/* Enable per-session authentication as per RFC 2554 (SASL).
|
||||
/* By default, Postfix is built without SASL support.
|
||||
/* .IP \fBsmtp_sasl_password_maps\fR
|
||||
/* Lookup tables with per-host \fIname\fR:\fIpassword\fR entries.
|
||||
/* No entry for a host means no attempt to authenticate.
|
||||
@ -198,7 +199,6 @@
|
||||
#include <debug_peer.h>
|
||||
#include <mail_error.h>
|
||||
#include <deliver_pass.h>
|
||||
#include <smtp_stream.h>
|
||||
|
||||
/* Single server skeleton. */
|
||||
|
||||
@ -292,7 +292,6 @@ static int deliver_message(DELIVER_REQUEST *request)
|
||||
"%s", vstring_str(why));
|
||||
} else {
|
||||
debug_peer_check(state->session->host, state->session->addr);
|
||||
smtp_jump_setup(state->session->stream, state->jbuf);
|
||||
if (smtp_helo(state) == 0)
|
||||
smtp_xfer(state);
|
||||
if (state->history != 0
|
||||
|
@ -8,11 +8,6 @@
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* System library.
|
||||
*/
|
||||
#include <setjmp.h>
|
||||
|
||||
/*
|
||||
* SASL library.
|
||||
*/
|
||||
@ -57,7 +52,6 @@ typedef struct SMTP_STATE {
|
||||
VSTRING *sasl_decoded; /* decoding buffer */
|
||||
sasl_callback_t *sasl_callbacks; /* stateful callbacks */
|
||||
#endif
|
||||
jmp_buf jbuf[1]; /* exception context */
|
||||
} SMTP_STATE;
|
||||
|
||||
#define SMTP_FEATURE_ESMTP (1<<0)
|
||||
|
@ -64,7 +64,6 @@
|
||||
#include <sys_defs.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/socket.h> /* shutdown(2) */
|
||||
#include <setjmp.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h> /* 44BSD stdarg.h uses abort() */
|
||||
@ -158,7 +157,7 @@ int smtp_helo(SMTP_STATE *state)
|
||||
* Prepare for disaster.
|
||||
*/
|
||||
smtp_timeout_setup(state->session->stream, var_smtp_helo_tmout);
|
||||
if ((except = setjmp(state->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(state->session->stream)) != 0)
|
||||
return (smtp_stream_except(state, except, "sending HELO"));
|
||||
|
||||
/*
|
||||
@ -413,6 +412,7 @@ int smtp_xfer(SMTP_STATE *state)
|
||||
* The final sender state has no action associated with it.
|
||||
*/
|
||||
case SMTP_STATE_LAST:
|
||||
VSTRING_RESET(next_command);
|
||||
break;
|
||||
}
|
||||
VSTRING_TERMINATE(next_command);
|
||||
@ -439,7 +439,7 @@ int smtp_xfer(SMTP_STATE *state)
|
||||
*/
|
||||
smtp_timeout_setup(state->session->stream,
|
||||
*xfer_timeouts[recv_state]);
|
||||
if ((except = setjmp(state->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(state->session->stream)) != 0)
|
||||
RETURN(smtp_stream_except(state, except,
|
||||
xfer_states[recv_state]));
|
||||
resp = smtp_chat_resp(state);
|
||||
@ -591,7 +591,7 @@ int smtp_xfer(SMTP_STATE *state)
|
||||
if (send_state == SMTP_STATE_DOT && nrcpt > 0) {
|
||||
smtp_timeout_setup(state->session->stream,
|
||||
var_smtp_data1_tmout);
|
||||
if ((except = setjmp(state->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(state->session->stream)) != 0)
|
||||
RETURN(smtp_stream_except(state, except,
|
||||
"sending message body"));
|
||||
|
||||
|
4
postfix/smtpd/.indent.pro
vendored
4
postfix/smtpd/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
@ -229,7 +229,6 @@
|
||||
#include <netdb.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h> /* remove() */
|
||||
#include <setjmp.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
@ -1145,10 +1144,9 @@ static void smtpd_proto(SMTPD_STATE *state)
|
||||
* cleans up, but no attempt is made to inform the client of the nature
|
||||
* of the problem.
|
||||
*/
|
||||
smtp_jump_setup(state->client, state->jbuf);
|
||||
smtp_timeout_setup(state->client, var_smtpd_tmout);
|
||||
|
||||
switch (setjmp(state->jbuf[0])) {
|
||||
switch (vstream_setjmp(state->client)) {
|
||||
|
||||
default:
|
||||
msg_panic("smtpd_proto: unknown error reading from %s[%s]",
|
||||
|
@ -8,11 +8,6 @@
|
||||
/* DESCRIPTION
|
||||
/* .nf
|
||||
|
||||
/*
|
||||
* System library
|
||||
*/
|
||||
#include <setjmp.h>
|
||||
|
||||
/*
|
||||
* SASL library.
|
||||
*/
|
||||
@ -76,7 +71,6 @@ typedef struct SMTPD_STATE {
|
||||
VSTRING *sasl_encoded;
|
||||
VSTRING *sasl_decoded;
|
||||
#endif
|
||||
jmp_buf jbuf[1];
|
||||
} SMTPD_STATE;
|
||||
|
||||
extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *);
|
||||
|
4
postfix/smtpstone/.indent.pro
vendored
4
postfix/smtpstone/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
@ -41,7 +41,6 @@
|
||||
#include <sys/socket.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <setjmp.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
@ -74,7 +73,6 @@ typedef struct SINK_STATE {
|
||||
int data_state;
|
||||
int (*read) (struct SINK_STATE *);
|
||||
int rcpts;
|
||||
jmp_buf jbuf[1];
|
||||
} SINK_STATE;
|
||||
|
||||
#define ST_ANY 0
|
||||
@ -285,7 +283,7 @@ static void read_event(int unused_event, char *context)
|
||||
SINK_STATE *state = (SINK_STATE *) context;
|
||||
|
||||
do {
|
||||
switch (setjmp(state->jbuf[0])) {
|
||||
switch (vstream_setjmp(state->stream)) {
|
||||
|
||||
default:
|
||||
msg_panic("unknown error reading input");
|
||||
@ -335,7 +333,6 @@ static void connect_event(int unused_event, char *context)
|
||||
state->stream = vstream_fdopen(fd, O_RDWR);
|
||||
state->read = command_read;
|
||||
state->data_state = 0;
|
||||
smtp_jump_setup(state->stream, state->jbuf);
|
||||
smtp_timeout_setup(state->stream, var_tmout);
|
||||
smtp_printf(state->stream, "220 %s ESMTP", var_myhostname);
|
||||
event_enable_read(fd, read_event, (char *) state);
|
||||
|
@ -65,7 +65,6 @@
|
||||
#include <sys/wait.h>
|
||||
#include <netinet/in.h>
|
||||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
@ -112,7 +111,6 @@ typedef struct SESSION {
|
||||
VSTREAM *stream; /* open connection */
|
||||
int connect_count; /* # of connect()s to retry */
|
||||
struct SESSION *next; /* connect() queue linkage */
|
||||
jmp_buf jbuf[1]; /* exception handling */
|
||||
} SESSION;
|
||||
|
||||
static SESSION *last_session; /* connect() queue tail */
|
||||
@ -390,7 +388,6 @@ static void start_connect(SESSION *session)
|
||||
(void) non_blocking(fd, NON_BLOCKING);
|
||||
session->stream = vstream_fdopen(fd, O_RDWR);
|
||||
event_enable_write(fd, connect_done, (char *) session);
|
||||
smtp_jump_setup(session->stream, session->jbuf);
|
||||
smtp_timeout_setup(session->stream, var_timeout);
|
||||
if (connect(fd, (struct sockaddr *) & sin, sizeof(sin)) < 0
|
||||
&& errno != EINPROGRESS)
|
||||
@ -429,7 +426,7 @@ static void read_banner(int unused_event, char *context)
|
||||
/*
|
||||
* Prepare for disaster.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while reading server greeting", exception_text(except));
|
||||
|
||||
/*
|
||||
@ -452,12 +449,12 @@ static void read_banner(int unused_event, char *context)
|
||||
static void send_helo(SESSION *session)
|
||||
{
|
||||
int except;
|
||||
char *protocol = (talk_lmtp ? "LHLO" : "EHLO");
|
||||
char *protocol = (talk_lmtp ? "LHLO" : "HELO");
|
||||
|
||||
/*
|
||||
* Send the standard greeting with our hostname
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending HELO", exception_text(except));
|
||||
|
||||
command(session->stream, "%s %s", protocol, var_myhostname);
|
||||
@ -480,7 +477,7 @@ static void helo_done(int unused_event, char *context)
|
||||
/*
|
||||
* Get response to HELO command.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending HELO", exception_text(except));
|
||||
|
||||
if ((resp = response(session->stream, buffer))->code / 100 != 2)
|
||||
@ -498,7 +495,7 @@ static void send_mail(SESSION *session)
|
||||
/*
|
||||
* Send the envelope sender address.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending sender", exception_text(except));
|
||||
|
||||
command(session->stream, "MAIL FROM:<%s>", sender);
|
||||
@ -521,7 +518,7 @@ static void mail_done(int unused, char *context)
|
||||
/*
|
||||
* Get response to MAIL command.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending sender", exception_text(except));
|
||||
|
||||
if ((resp = response(session->stream, buffer))->code / 100 != 2)
|
||||
@ -542,7 +539,7 @@ static void send_rcpt(int unused_event, char *context)
|
||||
/*
|
||||
* Send envelope recipient address.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending recipient", exception_text(except));
|
||||
|
||||
if (session->rcpt_count > 1)
|
||||
@ -571,7 +568,7 @@ static void rcpt_done(int unused, char *context)
|
||||
/*
|
||||
* Get response to RCPT command.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending recipient", exception_text(except));
|
||||
|
||||
if ((resp = response(session->stream, buffer))->code / 100 != 2)
|
||||
@ -596,7 +593,7 @@ static void send_data(int unused_event, char *context)
|
||||
/*
|
||||
* Request data transmission.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending DATA command", exception_text(except));
|
||||
command(session->stream, "DATA");
|
||||
|
||||
@ -620,7 +617,7 @@ static void data_done(int unused_event, char *context)
|
||||
/*
|
||||
* Get response to DATA command.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending DATA command", exception_text(except));
|
||||
if ((resp = response(session->stream, buffer))->code != 354)
|
||||
msg_fatal("data %d %s", resp->code, resp->str);
|
||||
@ -644,7 +641,7 @@ static void data_done(int unused_event, char *context)
|
||||
/*
|
||||
* Send some garbage.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending message", exception_text(except));
|
||||
if (message_length == 0) {
|
||||
smtp_fputs("La de da de da 1.", 17, session->stream);
|
||||
@ -687,7 +684,7 @@ static void dot_done(int unused_event, char *context)
|
||||
/*
|
||||
* Get response to "." command.
|
||||
*/
|
||||
if ((except = setjmp(session->jbuf[0])) != 0)
|
||||
if ((except = vstream_setjmp(session->stream)) != 0)
|
||||
msg_fatal("%s while sending message", exception_text(except));
|
||||
do { /* XXX this could block */
|
||||
if ((resp = response(session->stream, buffer))->code / 100 != 2)
|
||||
|
4
postfix/spawn/.indent.pro
vendored
4
postfix/spawn/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/trivial-rewrite/.indent.pro
vendored
4
postfix/trivial-rewrite/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
4
postfix/util/.indent.pro
vendored
4
postfix/util/.indent.pro
vendored
@ -47,6 +47,10 @@
|
||||
-TINET_ADDR_LIST
|
||||
-TINT_TABLE
|
||||
-TJMP_BUF_WRAPPER
|
||||
-TLMTP_ATTR
|
||||
-TLMTP_RESP
|
||||
-TLMTP_SESSION
|
||||
-TLMTP_STATE
|
||||
-TLOCAL_EXP
|
||||
-TLOCAL_STATE
|
||||
-TMAC_EXP
|
||||
|
@ -21,8 +21,7 @@ SRCS = argv.c argv_split.c attr.c basename.c binhash.c chroot_uid.c \
|
||||
write_buf.c write_wait.c dict_unix.c dict_pcre.c stream_listen.c \
|
||||
stream_connect.c stream_trigger.c dict_regexp.c mac_expand.c \
|
||||
clean_env.c watchdog.c spawn_command.c duplex_pipe.c sane_rename.c \
|
||||
sane_link.c unescape.c timed_read.c timed_write.c binattr.c \
|
||||
vstream_attr.c
|
||||
sane_link.c unescape.c timed_read.c timed_write.c binattr.c
|
||||
OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
|
||||
close_on_exec.o concatenate.o dict.o dict_db.o dict_dbm.o \
|
||||
dict_env.o dict_ht.o dict_ldap.o dict_mysql.o dict_ni.o dict_nis.o \
|
||||
@ -45,8 +44,7 @@ OBJS = argv.o argv_split.o attr.o basename.o binhash.o chroot_uid.o \
|
||||
write_buf.o write_wait.o dict_unix.o dict_pcre.o stream_listen.o \
|
||||
stream_connect.o stream_trigger.o dict_regexp.o mac_expand.o \
|
||||
clean_env.o watchdog.o spawn_command.o duplex_pipe.o sane_rename.o \
|
||||
sane_link.o unescape.o timed_read.o timed_write.o binattr.o \
|
||||
vstream_attr.o
|
||||
sane_link.o unescape.o timed_read.o timed_write.o binattr.o
|
||||
HDRS = argv.h attr.h binhash.h chroot_uid.h connect.h dict.h dict_db.h \
|
||||
dict_dbm.h dict_env.h dict_ht.h dict_ldap.h dict_mysql.h \
|
||||
dict_ni.h dict_nis.h dict_nisplus.h dir_forest.h events.h \
|
||||
@ -951,14 +949,8 @@ vstream.o: vbuf_print.h
|
||||
vstream.o: vbuf.h
|
||||
vstream.o: iostuff.h
|
||||
vstream.o: vstring.h
|
||||
vstream.o: binattr.h
|
||||
vstream.o: vstream.h
|
||||
vstream_attr.o: vstream_attr.c
|
||||
vstream_attr.o: sys_defs.h
|
||||
vstream_attr.o: vstream.h
|
||||
vstream_attr.o: vbuf.h
|
||||
vstream_attr.o: binattr.h
|
||||
vstream_attr.o: htable.h
|
||||
vstream.o: binattr.h
|
||||
vstream_popen.o: vstream_popen.c
|
||||
vstream_popen.o: sys_defs.h
|
||||
vstream_popen.o: msg.h
|
||||
|
@ -24,8 +24,8 @@ extern int peekfd(int);
|
||||
extern int read_wait(int, int);
|
||||
extern int write_wait(int, int);
|
||||
extern int write_buf(int, const char *, int, int);
|
||||
extern int timed_read(int, void *, unsigned, int);
|
||||
extern int timed_write(int, void *, unsigned, int);
|
||||
extern int timed_read(int, void *, unsigned, int, void *);
|
||||
extern int timed_write(int, void *, unsigned, int, void *);
|
||||
extern void doze(unsigned);
|
||||
extern int duplex_pipe(int *);
|
||||
|
||||
|
@ -6,11 +6,12 @@
|
||||
/* SYNOPSIS
|
||||
/* #include <iostuff.h>
|
||||
/*
|
||||
/* int timed_read(fd, buf, buf_len, timeout)
|
||||
/* int timed_read(fd, buf, buf_len, timeout, context)
|
||||
/* int fd;
|
||||
/* void *buf;
|
||||
/* unsigned len;
|
||||
/* int timeout;
|
||||
/* void *context;
|
||||
/* DESCRIPTION
|
||||
/* timed_read() performs a read() operation when the specified
|
||||
/* descriptor becomes readable within a user-specified deadline.
|
||||
@ -25,6 +26,9 @@
|
||||
/* .IP timeout
|
||||
/* The deadline in seconds. If this is <= 0, the deadline feature
|
||||
/* is disabled.
|
||||
/* .IP context
|
||||
/* Application context. This parameter is unused. It exists only
|
||||
/* for the sake of VSTREAM compatibility.
|
||||
/* DIAGNOSTICS
|
||||
/* When the operation does not complete within the deadline, the
|
||||
/* result value is -1, and errno is set to ETIMEDOUT.
|
||||
@ -51,7 +55,8 @@
|
||||
|
||||
/* timed_read - read with deadline */
|
||||
|
||||
int timed_read(int fd, void *buf, unsigned len, int timeout)
|
||||
int timed_read(int fd, void *buf, unsigned len,
|
||||
int timeout, void *unused_context)
|
||||
{
|
||||
|
||||
/*
|
||||
|
@ -6,11 +6,12 @@
|
||||
/* SYNOPSIS
|
||||
/* #include <iostuff.h>
|
||||
/*
|
||||
/* int timed_write(fd, buf, buf_len, timeout)
|
||||
/* int timed_write(fd, buf, buf_len, timeout, context)
|
||||
/* int fd;
|
||||
/* const void *buf;
|
||||
/* unsigned len;
|
||||
/* int timeout;
|
||||
/* void *context;
|
||||
/* DESCRIPTION
|
||||
/* timed_write() performs a write() operation when the specified
|
||||
/* descriptor becomes writable within a user-specified deadline.
|
||||
@ -25,6 +26,9 @@
|
||||
/* .IP timeout
|
||||
/* The deadline in seconds. If this is <= 0, the deadline feature
|
||||
/* is disabled.
|
||||
/* .IP context
|
||||
/* Application context. This parameter is unused. It exists only
|
||||
/* for the sake of VSTREAM compatibility.
|
||||
/* DIAGNOSTICS
|
||||
/* When the operation does not complete within the deadline, the
|
||||
/* result value is -1, and errno is set to ETIMEDOUT.
|
||||
@ -51,7 +55,8 @@
|
||||
|
||||
/* timed_write - write with deadline */
|
||||
|
||||
int timed_write(int fd, void *buf, unsigned len, int timeout)
|
||||
int timed_write(int fd, void *buf, unsigned len,
|
||||
int timeout, void *unused_context)
|
||||
{
|
||||
|
||||
/*
|
||||
|
@ -93,6 +93,14 @@
|
||||
/*
|
||||
/* int vstream_peek(stream)
|
||||
/* VSTREAM *stream;
|
||||
/*
|
||||
/* int vstream_setjmp(stream, buffer)
|
||||
/* VSTREAM *stream;
|
||||
/* jmp_buf *buffer;
|
||||
/*
|
||||
/* void longjmp(stream, val)
|
||||
/* VSTREAM *stream;
|
||||
/* int val;
|
||||
/* DESCRIPTION
|
||||
/* The \fIvstream\fR module implements light-weight buffered I/O
|
||||
/* similar to the standard I/O routines.
|
||||
@ -201,12 +209,15 @@
|
||||
/* value) pairs, terminated with VSTREAM_CTL_END.
|
||||
/* The following lists the names and the types of the corresponding
|
||||
/* value arguments.
|
||||
/* .IP "VSTREAM_CTL_READ_FN (int (*)(int, void *, unsigned))"
|
||||
/* .IP "VSTREAM_CTL_READ_FN (int (*)(int, void *, unsigned, int, void *))"
|
||||
/* The argument specifies an alternative for the timed_read(3) function,
|
||||
/* for example, a read function that performs encryption.
|
||||
/* .IP "VSTREAM_CTL_WRITE_FN (int (*)(int, void *, unsigned))"
|
||||
/* .IP "VSTREAM_CTL_WRITE_FN (int (*)(int, void *, unsigned, int, void *))"
|
||||
/* The argument specifies an alternative for the timed_write(3) function,
|
||||
/* for example, a write function that performs encryption.
|
||||
/* .IP "VSTREAM_CTL_CONTEXT (char *)"
|
||||
/* The argument specifies application context that is passed on to
|
||||
/* the application-specified read/write routines. No copy is made.
|
||||
/* .IP "VSTREAM_CTL_PATH (char *)"
|
||||
/* Updates the stored pathname of the specified stream. The pathname
|
||||
/* is copied.
|
||||
@ -228,6 +239,10 @@
|
||||
/* The deadline for a descriptor to become readable in case of a read
|
||||
/* request, or writable in case of a write request. Specify a value
|
||||
/* <= 0 to disable deadlines.
|
||||
/* .IP "VSTREAM_CTL_EXCEPT (no value)"
|
||||
/* Enable exception handling with vstream_setjmp() and vstream_longjmp().
|
||||
/* This involves allocation of additional memory that normally isn't
|
||||
/* used.
|
||||
/* .PP
|
||||
/* vstream_fileno() gives access to the file handle associated with
|
||||
/* a buffered stream. With streams that have separate read/write
|
||||
@ -254,12 +269,22 @@
|
||||
/*
|
||||
/* vstream_peek() returns the number of characters that can be
|
||||
/* read from the named stream without refilling the read buffer.
|
||||
/*
|
||||
/* vstream_setjmp() saves processing context and makes that context
|
||||
/* available for use with vstream_longjmp(). Normally, vstream_setjmp()
|
||||
/* returns zero. A non-zero result means that vstream_setjmp() returned
|
||||
/* through a vstream_longjmp() call; the result is the \fIval\fR argment
|
||||
/* given to vstream_longjmp().
|
||||
/*
|
||||
/* NB: non-local jumps such as vstream_longjmp() are not safe
|
||||
/* for jumping out of any vstream routine.
|
||||
/* DIAGNOSTICS
|
||||
/* Panics: interface violations. Fatal errors: out of memory.
|
||||
/* SEE ALSO
|
||||
/* timed_read(3) default read routine
|
||||
/* timed_write(3) default write routine
|
||||
/* vbuf_print(3) formatting engine
|
||||
/* setjmp(3) non-local jumps
|
||||
/* BUGS
|
||||
/* Should use mmap() on reasonable systems.
|
||||
/* LICENSE
|
||||
@ -291,7 +316,6 @@
|
||||
#include "vbuf_print.h"
|
||||
#include "iostuff.h"
|
||||
#include "vstring.h"
|
||||
#include "binattr.h"
|
||||
#include "vstream.h"
|
||||
|
||||
/* Application-specific. */
|
||||
@ -499,7 +523,7 @@ static int vstream_fflush_some(VSTREAM *stream, int to_flush)
|
||||
* any.
|
||||
*/
|
||||
for (data = (char *) bp->data, len = to_flush; len > 0; len -= n, data += n) {
|
||||
if ((n = stream->write_fn(stream->fd, data, len, stream->timeout)) <= 0) {
|
||||
if ((n = stream->write_fn(stream->fd, data, len, stream->timeout, stream->context)) <= 0) {
|
||||
bp->flags |= VSTREAM_FLAG_ERR;
|
||||
if (errno == ETIMEDOUT)
|
||||
bp->flags |= VSTREAM_FLAG_TIMEOUT;
|
||||
@ -625,7 +649,7 @@ static int vstream_buf_get_ready(VBUF *bp)
|
||||
* data as is available right now, whichever is less. Update the cached
|
||||
* file seek position, if any.
|
||||
*/
|
||||
switch (n = stream->read_fn(stream->fd, bp->data, bp->len, stream->timeout)) {
|
||||
switch (n = stream->read_fn(stream->fd, bp->data, bp->len, stream->timeout, stream->context)) {
|
||||
case -1:
|
||||
bp->flags |= VSTREAM_FLAG_ERR;
|
||||
if (errno == ETIMEDOUT)
|
||||
@ -874,7 +898,8 @@ VSTREAM *vstream_fdopen(int fd, int flags)
|
||||
stream->pid = 0;
|
||||
stream->waitpid_fn = 0;
|
||||
stream->timeout = 0;
|
||||
stream->attr = 0;
|
||||
stream->context = 0;
|
||||
stream->jbuf = 0;
|
||||
return (stream);
|
||||
}
|
||||
|
||||
@ -929,8 +954,8 @@ int vstream_fclose(VSTREAM *stream)
|
||||
}
|
||||
if (stream->path)
|
||||
myfree(stream->path);
|
||||
if (stream->attr)
|
||||
binattr_free(stream->attr);
|
||||
if (stream->jbuf)
|
||||
myfree((char *) stream->jbuf);
|
||||
if (!VSTREAM_STATIC(stream))
|
||||
myfree((char *) stream);
|
||||
return (err ? VSTREAM_EOF : 0);
|
||||
@ -988,6 +1013,9 @@ void vstream_control(VSTREAM *stream, int name,...)
|
||||
case VSTREAM_CTL_WRITE_FN:
|
||||
stream->write_fn = va_arg(ap, VSTREAM_FN);
|
||||
break;
|
||||
case VSTREAM_CTL_CONTEXT:
|
||||
stream->context = va_arg(ap, char *);
|
||||
break;
|
||||
case VSTREAM_CTL_PATH:
|
||||
if (stream->path)
|
||||
myfree(stream->path);
|
||||
@ -1023,6 +1051,10 @@ void vstream_control(VSTREAM *stream, int name,...)
|
||||
case VSTREAM_CTL_TIMEOUT:
|
||||
stream->timeout = va_arg(ap, int);
|
||||
break;
|
||||
case VSTREAM_CTL_EXCEPT:
|
||||
if (stream->jbuf == 0)
|
||||
stream->jbuf = (jmp_buf *) mymalloc(sizeof(jmp_buf));
|
||||
break;
|
||||
default:
|
||||
msg_panic("%s: bad name %d", myname, name);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
*/
|
||||
#include <fcntl.h>
|
||||
#include <stdarg.h>
|
||||
#include <setjmp.h>
|
||||
|
||||
/*
|
||||
* Utility library.
|
||||
@ -27,7 +28,7 @@
|
||||
* Simple buffered stream. The members of this structure are not part of the
|
||||
* official interface and can change without prior notice.
|
||||
*/
|
||||
typedef int (*VSTREAM_FN) (int, void *, unsigned, int);
|
||||
typedef int (*VSTREAM_FN) (int, void *, unsigned, int, void *);
|
||||
typedef int (*VSTREAM_WAITPID_FN) (pid_t, WAIT_STATUS_T *, int);
|
||||
|
||||
typedef struct VSTREAM {
|
||||
@ -35,16 +36,17 @@ typedef struct VSTREAM {
|
||||
int fd; /* file handle, no 256 limit */
|
||||
VSTREAM_FN read_fn; /* buffer fill action */
|
||||
VSTREAM_FN write_fn; /* buffer fill action */
|
||||
void *context; /* application context */
|
||||
long offset; /* cached seek info */
|
||||
char *path; /* give it at least try */
|
||||
int read_fd; /* read channel (double-buffered) */
|
||||
int write_fd; /* write channel (double-buffered) */
|
||||
VBUF read_buf; /* read buffer (double-buffered) */
|
||||
VBUF write_buf; /* write buffer (double-buffered) */
|
||||
int timeout; /* read/write timout */
|
||||
pid_t pid; /* vstream_popen/close() */
|
||||
VSTREAM_WAITPID_FN waitpid_fn; /* vstream_popen/close() */
|
||||
BINATTR *attr; /* optional binary attribute list */
|
||||
int timeout; /* read/write timout */
|
||||
jmp_buf *jbuf; /* exception handling */
|
||||
} VSTREAM;
|
||||
|
||||
extern VSTREAM vstream_fstd[]; /* pre-defined streams */
|
||||
@ -104,6 +106,8 @@ extern void vstream_control(VSTREAM *, int,...);
|
||||
#define VSTREAM_CTL_WRITE_FD 6
|
||||
#define VSTREAM_CTL_WAITPID_FN 7
|
||||
#define VSTREAM_CTL_TIMEOUT 8
|
||||
#define VSTREAM_CTL_EXCEPT 9
|
||||
#define VSTREAM_CTL_CONTEXT 10
|
||||
|
||||
extern VSTREAM *vstream_printf(const char *,...);
|
||||
extern VSTREAM *vstream_fprintf(VSTREAM *, const char *,...);
|
||||
@ -128,14 +132,11 @@ extern VSTREAM *vstream_vfprintf(VSTREAM *, const char *, va_list);
|
||||
extern int vstream_peek(VSTREAM *);
|
||||
|
||||
/*
|
||||
* Attribute management, a way of tacking on arbitrary information onto a
|
||||
* VSTREAM without destroying the VSTREAM abstraction itself.
|
||||
* Exception handling. We use pointer to jmp_buf to avoid a lot of unused
|
||||
* baggage for streams that don't need this functionality.
|
||||
*/
|
||||
#define VSTREAM_ATTR_FREE_FN BINATTR_FREE_FN
|
||||
|
||||
extern void vstream_attr_set(VSTREAM *, const char *, char *, VSTREAM_ATTR_FREE_FN);
|
||||
extern char *vstream_attr_get(VSTREAM *, const char *);
|
||||
extern void vstream_attr_unset(VSTREAM *, const char *);
|
||||
#define vstream_setjmp(stream) setjmp((stream)->jbuf[0])
|
||||
#define vstream_longjmp(stream, val) longjmp((stream)->jbuf[0], (val))
|
||||
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
|
@ -1,92 +0,0 @@
|
||||
/*++
|
||||
/* NAME
|
||||
/* vstream_attr 3
|
||||
/* SUMMARY
|
||||
/* per-stream attribute list management
|
||||
/* SYNOPSIS
|
||||
/* #include <vstream.h>
|
||||
/*
|
||||
/* void vstream_attr_set(stream, name, value, free_fn)
|
||||
/* VSTREAM *stream;
|
||||
/* const char *name;
|
||||
/* char *value;
|
||||
/* void (*free_fn)(char *);
|
||||
/*
|
||||
/* char *vstream_attr_get(stream, name)
|
||||
/* VSTREAM *stream;
|
||||
/* const char *name;
|
||||
/*
|
||||
/* void vstream_attr_unset(stream, name)
|
||||
/* VSTREAM *stream;
|
||||
/* const char *name;
|
||||
/* DESCRIPTION
|
||||
/* This module maintains an optional per-stream open attribute
|
||||
/* list for arbitrary binary values. It is in fact a convienience
|
||||
/* interface built on top of the binattr(3) module.
|
||||
/*
|
||||
/* vstream_attr_set() adds or replaces the named attribute.
|
||||
/*
|
||||
/* vstream_attr_get() looks up the named attribute. The result
|
||||
/* is the value stored with vstream_attr_set() or a null pointer
|
||||
/* when the requested information is not found.
|
||||
/*
|
||||
/* vstream_attr_unset() removes the named attribute. This operation
|
||||
/* is undefined for attributes that do not exist.
|
||||
/*
|
||||
/* Arguments:
|
||||
/* .IP stream
|
||||
/* Open VSTREAM.
|
||||
/* .IP name
|
||||
/* Attribute name, in the form of a null-terminated list.
|
||||
/* The name is copied.
|
||||
/* .IP value
|
||||
/* Arbitrary binary value. The value is not copied.
|
||||
/* .IP free_fn
|
||||
/* Null pointer, or pointer to function that destroys the value
|
||||
/* that was stored with vstream_attr_set().
|
||||
/* LICENSE
|
||||
/* .ad
|
||||
/* .fi
|
||||
/* The Secure Mailer license must be distributed with this software.
|
||||
/* AUTHOR(S)
|
||||
/* Wietse Venema
|
||||
/* IBM T.J. Watson Research
|
||||
/* P.O. Box 704
|
||||
/* Yorktown Heights, NY 10598, USA
|
||||
/*--*/
|
||||
|
||||
/* System library. */
|
||||
|
||||
#include <sys_defs.h>
|
||||
|
||||
/* Utility library. */
|
||||
|
||||
#include <vstream.h>
|
||||
#include <htable.h>
|
||||
|
||||
/* vstream_attr_set - add or replace per-stream attribute */
|
||||
|
||||
void vstream_attr_set(VSTREAM *stream, const char *name, char *value, BINATTR_FREE_FN free_fn)
|
||||
{
|
||||
if (stream->attr == 0)
|
||||
stream->attr = binattr_create(1);
|
||||
binattr_set(stream->attr, name, value, free_fn);
|
||||
}
|
||||
|
||||
/* vstream_attr_get - look up per-stream attribute */
|
||||
|
||||
char *vstream_attr_get(VSTREAM *stream, const char *name)
|
||||
{
|
||||
if (stream->attr == 0)
|
||||
return (0);
|
||||
else
|
||||
return (binattr_get(stream->attr, name));
|
||||
}
|
||||
|
||||
/* vstream_attr_unset - unset per-stream attribute */
|
||||
|
||||
void vstream_attr_unset(VSTREAM *stream, const char *name)
|
||||
{
|
||||
if (stream->attr)
|
||||
binattr_unset(stream->attr, name);
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user