mirror of
https://github.com/vdukhovni/postfix
synced 2025-09-01 06:35:27 +00:00
snapshot-20000418
This commit is contained in:
@@ -3819,4 +3819,11 @@ Apologies for any names omitted.
|
|||||||
20000417
|
20000417
|
||||||
|
|
||||||
The SASL authentication in the SMTP server and client works,
|
The SASL authentication in the SMTP server and client works,
|
||||||
but only on Linux and Solaris.
|
but only on Linux and Solaris, neither of which I wish to
|
||||||
|
run on my laptop.
|
||||||
|
|
||||||
|
20000418
|
||||||
|
|
||||||
|
Added LMTP support to the smtp-source and smtp-sink utilities
|
||||||
|
so that I don't have to install Cyrus IMAP just to test
|
||||||
|
LMTP.
|
||||||
|
@@ -2,14 +2,16 @@ WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
|
|||||||
===============================================================
|
===============================================================
|
||||||
|
|
||||||
Do not use this code. The Postfix SASL support is based on the
|
Do not use this code. The Postfix SASL support is based on the
|
||||||
Cyrus SASL library, which is light years away from production
|
Cyrus SASL library, which has not enough documentation about how
|
||||||
quality. There is not enough documentation to figure out how the
|
the software is supposed to work.
|
||||||
software is supposed to work.
|
|
||||||
|
|
||||||
The SASL library code works only on LINUX and Solaris. If you
|
Postfix+SASL 1.5.5 appears to work on RedHat 6.1 (pwcheck_method
|
||||||
build Postfix+SASL on other systems, the software builds without
|
of shadow or sasldb), Solaris 2.7 (pwcheck_method of shadow or
|
||||||
trouble but fails at runtime due to no available authentication
|
sasldb), and FreeBSD 3.4 (pwcheck_method of sasldb). On RedHat
|
||||||
mechanisms. It can be made to work with considerable tweaking.
|
6.1, SASL 1.5.5 needed write access to the sasldb file.
|
||||||
|
|
||||||
|
SASL is a lot of complex code. In a future version the Postfix SASL
|
||||||
|
code is likely to be put outside the SMTP server.
|
||||||
|
|
||||||
Introduction
|
Introduction
|
||||||
============
|
============
|
||||||
@@ -18,16 +20,17 @@ The Postfix SASL support (RFC 2554) was originally implemented by
|
|||||||
Till Franke of SuSE Rhein/Main AG. The present code is a trimmed-down
|
Till Franke of SuSE Rhein/Main AG. The present code is a trimmed-down
|
||||||
version with only the bare necessities.
|
version with only the bare necessities.
|
||||||
|
|
||||||
When receiving mail, Postfix logs the client-provided username and
|
When receiving mail, Postfix logs the client-provided username,
|
||||||
sender address to the maillog file, and optionally grants mail
|
authentication method, and sender address to the maillog file, and
|
||||||
relay access to authenticated clients. SASL authentication information
|
optionally grants mail access via the permit_sasl_authenticated
|
||||||
is not passed on via message headers or via SMTP. It is no-one's
|
UCE restriction. SASL authentication information is not passed on
|
||||||
business what username and authentication method the poster was
|
via message headers or via SMTP. It is no-one's business what
|
||||||
using in order to access the mail server.
|
username and authentication method the poster was using in order
|
||||||
|
to access the mail server.
|
||||||
|
|
||||||
When sending mail, Postfix looks up the server hostname and if
|
When sending mail, Postfix looks up the server hostname in a table,
|
||||||
a username/password is known, it will use that to authenticate
|
and if a username/password is found, it will use that username and
|
||||||
to the server.
|
password to authenticate to the server.
|
||||||
|
|
||||||
Building the SASL library
|
Building the SASL library
|
||||||
=========================
|
=========================
|
||||||
@@ -80,15 +83,13 @@ In order to allow mail relaying by authenticated clients:
|
|||||||
In /usr/local/lib/sasl/smtpd.conf you need to specify what authentication
|
In /usr/local/lib/sasl/smtpd.conf you need to specify what authentication
|
||||||
mechanism the server will support, for example:
|
mechanism the server will support, for example:
|
||||||
|
|
||||||
pwcheck_method: shadow
|
pwcheck_method: sasldb
|
||||||
|
|
||||||
This will use the Linux or Solaris shadow passwd file, which is
|
This will use the SASL password file (default: /etc/sasldb), which
|
||||||
the only way that I was able to test, but which is undesirable
|
is maintained with the saslpasswd command. On some systems the
|
||||||
because it uses plaintext passwords.
|
saslpasswd command needs to be run multiple times before it stops
|
||||||
|
complaining. The Postfix SMTP server needs read access to the
|
||||||
If you wish to use the system shadow password file, the Postfix
|
sasldb file - you have to play games with group access permissions.
|
||||||
SMTP server can't run chrooted (see master.cf), and the postfix
|
|
||||||
user or group needs read access to the shadow passwd file.
|
|
||||||
|
|
||||||
To run chrooted with SASL support is an interesting exercise.
|
To run chrooted with SASL support is an interesting exercise.
|
||||||
|
|
||||||
@@ -121,8 +122,8 @@ per-host username and password information.
|
|||||||
smtp_sasl_passwd_maps = hash:/etc/postfix/sasl_passwd
|
smtp_sasl_passwd_maps = hash:/etc/postfix/sasl_passwd
|
||||||
|
|
||||||
/etc/postfix/sasl_passwd:
|
/etc/postfix/sasl_passwd:
|
||||||
host.domain username:password
|
foo.com username:password
|
||||||
host.domain username
|
bar.com username
|
||||||
|
|
||||||
The SASL password file is opened before the SMTP server enters the
|
The SASL password file is opened before the SMTP server enters the
|
||||||
optional chroot jail, so there is no need to copy the sasl_passwd
|
optional chroot jail, so there is no need to copy the sasl_passwd
|
||||||
|
@@ -15,7 +15,7 @@
|
|||||||
* Version of this program.
|
* Version of this program.
|
||||||
*/
|
*/
|
||||||
#define VAR_MAIL_VERSION "mail_version"
|
#define VAR_MAIL_VERSION "mail_version"
|
||||||
#define DEF_MAIL_VERSION "Snapshot-20000417"
|
#define DEF_MAIL_VERSION "Snapshot-20000418"
|
||||||
extern char *var_mail_version;
|
extern char *var_mail_version;
|
||||||
|
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
|
@@ -14,7 +14,7 @@
|
|||||||
/* SMTP_STATE *state;
|
/* SMTP_STATE *state;
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* This module contains random chunks of code that implement
|
/* This module contains random chunks of code that implement
|
||||||
/* the SMTP protocol interface for SASL negotiation. The goal
|
/* the SMTP protocol interface for SASL negotiation. The goal
|
||||||
/* is to reduce clutter in the main SMTP client source code.
|
/* is to reduce clutter in the main SMTP client source code.
|
||||||
/*
|
/*
|
||||||
/* smtp_sasl_helo_auth() processes the AUTH option in the
|
/* smtp_sasl_helo_auth() processes the AUTH option in the
|
||||||
@@ -71,7 +71,7 @@
|
|||||||
|
|
||||||
/* smtp_sasl_helo_auth - handle AUTH option in EHLO reply */
|
/* smtp_sasl_helo_auth - handle AUTH option in EHLO reply */
|
||||||
|
|
||||||
void smtp_sasl_helo_auth(SMTP_STATE *state, const char *words)
|
void smtp_sasl_helo_auth(SMTP_STATE *state, const char *words)
|
||||||
{
|
{
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -88,20 +88,24 @@ void smtp_sasl_helo_auth(SMTP_STATE *state, const char *words)
|
|||||||
if (strlen(words) > 0) {
|
if (strlen(words) > 0) {
|
||||||
state->sasl_mechanism_list = mystrdup(words);
|
state->sasl_mechanism_list = mystrdup(words);
|
||||||
state->features |= SMTP_FEATURE_AUTH;
|
state->features |= SMTP_FEATURE_AUTH;
|
||||||
|
} else {
|
||||||
|
msg_warn("%s offered null AUTH mechanism list",
|
||||||
|
state->session->namaddr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* smtp_sasl_helo_login - perform SASL login */
|
/* smtp_sasl_helo_login - perform SASL login */
|
||||||
|
|
||||||
int smtp_sasl_helo_login(SMTP_STATE *state)
|
int smtp_sasl_helo_login(SMTP_STATE *state)
|
||||||
{
|
{
|
||||||
VSTRING *why = vstring_alloc(10);
|
VSTRING *why = vstring_alloc(10);
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip authentication when we have no authentication info for this
|
* Skip authentication when no authentication info exists for this
|
||||||
* server. In that case it should simply treat us like any stranger.
|
* server, so that we talk to each other like strangers. Otherwise, if
|
||||||
* Otherwise, if authentication fails assume the error is recoverable.
|
* authentication information exists, assume that authentication is
|
||||||
|
* required, and assume that an authentication error is recoverable.
|
||||||
*/
|
*/
|
||||||
if (smtp_sasl_passwd_lookup(state) != 0) {
|
if (smtp_sasl_passwd_lookup(state) != 0) {
|
||||||
smtp_sasl_start(state);
|
smtp_sasl_start(state);
|
||||||
|
@@ -47,7 +47,7 @@
|
|||||||
/* This member is a null pointer in the absence of successful
|
/* This member is a null pointer in the absence of successful
|
||||||
/* authentication.
|
/* authentication.
|
||||||
/* .PP
|
/* .PP
|
||||||
/* smtpd_sasl_logout() cleant up after smtpd_sasl_authenticate().
|
/* smtpd_sasl_logout() cleans up after smtpd_sasl_authenticate().
|
||||||
/* This routine exists for the sake of symmetry.
|
/* This routine exists for the sake of symmetry.
|
||||||
/*
|
/*
|
||||||
/* smtpd_sasl_disconnect() performs per-connection cleanup.
|
/* smtpd_sasl_disconnect() performs per-connection cleanup.
|
||||||
@@ -186,12 +186,10 @@ void smtpd_sasl_connect(SMTPD_STATE *state)
|
|||||||
msg_fatal("SASL per-connection server initialization");
|
msg_fatal("SASL per-connection server initialization");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Security options. XXX What exactly is this supposed to be doing? The
|
* Security options. Some information can be found in the sasl.h include
|
||||||
* cyrus-sasl-1.5.15 source code has no documentation at all about this
|
* file. Disallow anonymous authentication; this is because the
|
||||||
* routine.
|
* permit_sasl_authenticated feature is restricted to authenticated
|
||||||
*
|
* clients only.
|
||||||
* Disallow anonymous authentication. The permit_sasl_authenticated feature
|
|
||||||
* is restricted to authenticated clients only.
|
|
||||||
*/
|
*/
|
||||||
memset(&sec_props, 0, sizeof(sec_props));
|
memset(&sec_props, 0, sizeof(sec_props));
|
||||||
sec_props.min_ssf = 0;
|
sec_props.min_ssf = 0;
|
||||||
@@ -277,7 +275,7 @@ char *smtpd_sasl_authenticate(SMTPD_STATE *state,
|
|||||||
dec_buffer = STR(state->sasl_decoded);
|
dec_buffer = STR(state->sasl_decoded);
|
||||||
if (sasl_decode64(init_response, reply_len,
|
if (sasl_decode64(init_response, reply_len,
|
||||||
dec_buffer, &dec_length) != SASL_OK)
|
dec_buffer, &dec_length) != SASL_OK)
|
||||||
return ("501 AUTH failed: malformed initial response");
|
return ("501 Authentication failed: malformed initial response");
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: decoded initial response %s", myname, dec_buffer);
|
msg_info("%s: decoded initial response %s", myname, dec_buffer);
|
||||||
} else {
|
} else {
|
||||||
@@ -302,6 +300,9 @@ char *smtpd_sasl_authenticate(SMTPD_STATE *state,
|
|||||||
* comes in multiples of four bytes for each triple of input bytes,
|
* comes in multiples of four bytes for each triple of input bytes,
|
||||||
* plus four bytes for any incomplete last triple, plus one byte for
|
* plus four bytes for any incomplete last triple, plus one byte for
|
||||||
* the null terminator.
|
* the null terminator.
|
||||||
|
*
|
||||||
|
* XXX Replace the klunky sasl_encode64() interface by something that
|
||||||
|
* uses VSTRING buffers.
|
||||||
*/
|
*/
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info("%s: uncoded challenge: %.*s",
|
msg_info("%s: uncoded challenge: %.*s",
|
||||||
@@ -337,7 +338,7 @@ char *smtpd_sasl_authenticate(SMTPD_STATE *state,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Cleanup. What a horrible interface.
|
* Cleanup. What an awful interface.
|
||||||
*/
|
*/
|
||||||
if (serverout)
|
if (serverout)
|
||||||
free(serverout);
|
free(serverout);
|
||||||
|
@@ -2,9 +2,9 @@
|
|||||||
/* NAME
|
/* NAME
|
||||||
/* smtp-sink 8
|
/* smtp-sink 8
|
||||||
/* SUMMARY
|
/* SUMMARY
|
||||||
/* multi-threaded smtp test server
|
/* multi-threaded SMTP/LMTP test server
|
||||||
/* SYNOPSIS
|
/* SYNOPSIS
|
||||||
/* smtp-sink [-c] [-p] [-v] [-w delay] [host]:port backlog
|
/* smtp-sink [-cLpv] [-w delay] [host]:port backlog
|
||||||
/* DESCRIPTION
|
/* DESCRIPTION
|
||||||
/* \fIsmtp-sink\fR listens on the named host (or address) and port.
|
/* \fIsmtp-sink\fR listens on the named host (or address) and port.
|
||||||
/* It takes SMTP messages from the network and throws them away.
|
/* It takes SMTP messages from the network and throws them away.
|
||||||
@@ -14,6 +14,8 @@
|
|||||||
/* .IP -c
|
/* .IP -c
|
||||||
/* Display a running counter that is updated whenever an SMTP
|
/* Display a running counter that is updated whenever an SMTP
|
||||||
/* QUIT command is executed.
|
/* QUIT command is executed.
|
||||||
|
/* .IP -L
|
||||||
|
/* Speak LMTP rather than SMTP.
|
||||||
/* .IP -p
|
/* .IP -p
|
||||||
/* Disable ESMTP command pipelining.
|
/* Disable ESMTP command pipelining.
|
||||||
/* .IP -v
|
/* .IP -v
|
||||||
@@ -21,7 +23,7 @@
|
|||||||
/* .IP "-w delay"
|
/* .IP "-w delay"
|
||||||
/* Wait \fIdelay\fR seconds before responding to a DATA command.
|
/* Wait \fIdelay\fR seconds before responding to a DATA command.
|
||||||
/* SEE ALSO
|
/* SEE ALSO
|
||||||
/* smtp-source, SMTP test message generator
|
/* smtp-source, SMTP/LMTP test message generator
|
||||||
/* LICENSE
|
/* LICENSE
|
||||||
/* .ad
|
/* .ad
|
||||||
/* .fi
|
/* .fi
|
||||||
@@ -71,6 +73,7 @@ typedef struct SINK_STATE {
|
|||||||
VSTREAM *stream;
|
VSTREAM *stream;
|
||||||
int data_state;
|
int data_state;
|
||||||
int (*read) (struct SINK_STATE *);
|
int (*read) (struct SINK_STATE *);
|
||||||
|
int rcpts;
|
||||||
} SINK_STATE;
|
} SINK_STATE;
|
||||||
|
|
||||||
#define ST_ANY 0
|
#define ST_ANY 0
|
||||||
@@ -91,6 +94,7 @@ static int count;
|
|||||||
static int counter;
|
static int counter;
|
||||||
static int disable_pipelining;
|
static int disable_pipelining;
|
||||||
static int fixed_delay;
|
static int fixed_delay;
|
||||||
|
static int enable_lmtp;
|
||||||
|
|
||||||
/* ehlo_response - respond to EHLO command */
|
/* ehlo_response - respond to EHLO command */
|
||||||
|
|
||||||
@@ -109,6 +113,22 @@ static void ok_response(SINK_STATE *state)
|
|||||||
smtp_printf(state->stream, "250 Ok");
|
smtp_printf(state->stream, "250 Ok");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* mail_response - reset recipient count, send 250 OK */
|
||||||
|
|
||||||
|
static void mail_response(SINK_STATE *state)
|
||||||
|
{
|
||||||
|
state->rcpts = 0;
|
||||||
|
ok_response(state);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* rcpt_response - bump recipient count, send 250 OK */
|
||||||
|
|
||||||
|
static void rcpt_response(SINK_STATE *state)
|
||||||
|
{
|
||||||
|
state->rcpts++;
|
||||||
|
ok_response(state);
|
||||||
|
}
|
||||||
|
|
||||||
/* data_response - respond to DATA command */
|
/* data_response - respond to DATA command */
|
||||||
|
|
||||||
static void data_response(SINK_STATE *state)
|
static void data_response(SINK_STATE *state)
|
||||||
@@ -127,6 +147,18 @@ static void data_event(int unused_event, char *context)
|
|||||||
data_response(state);
|
data_response(state);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* dot_response - response to . command */
|
||||||
|
|
||||||
|
static void dot_response(SINK_STATE *state)
|
||||||
|
{
|
||||||
|
if (enable_lmtp) {
|
||||||
|
while (state->rcpts-- > 0) /* XXX this could block */
|
||||||
|
ok_response(state);
|
||||||
|
} else {
|
||||||
|
ok_response(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* quit_response - respond to QUIT command */
|
/* quit_response - respond to QUIT command */
|
||||||
|
|
||||||
static void quit_response(SINK_STATE *state)
|
static void quit_response(SINK_STATE *state)
|
||||||
@@ -184,7 +216,7 @@ static int data_read(SINK_STATE *state)
|
|||||||
if (state->data_state == ST_CR_LF_DOT_CR_LF) {
|
if (state->data_state == ST_CR_LF_DOT_CR_LF) {
|
||||||
if (msg_verbose)
|
if (msg_verbose)
|
||||||
msg_info(".");
|
msg_info(".");
|
||||||
ok_response(state);
|
dot_response(state);
|
||||||
state->read = command_read;
|
state->read = command_read;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -203,8 +235,9 @@ typedef struct SINK_COMMAND {
|
|||||||
static SINK_COMMAND command_table[] = {
|
static SINK_COMMAND command_table[] = {
|
||||||
"helo", ok_response,
|
"helo", ok_response,
|
||||||
"ehlo", ehlo_response,
|
"ehlo", ehlo_response,
|
||||||
"mail", ok_response,
|
"lhlo", ehlo_response,
|
||||||
"rcpt", ok_response,
|
"mail", mail_response,
|
||||||
|
"rcpt", rcpt_response,
|
||||||
"data", data_response,
|
"data", data_response,
|
||||||
"rset", ok_response,
|
"rset", ok_response,
|
||||||
"noop", ok_response,
|
"noop", ok_response,
|
||||||
@@ -311,7 +344,7 @@ static void connect_event(int unused_event, char *context)
|
|||||||
|
|
||||||
static void usage(char *myname)
|
static void usage(char *myname)
|
||||||
{
|
{
|
||||||
msg_fatal("usage: %s [-c] [-p] [-v] [host]:port backlog", myname);
|
msg_fatal("usage: %s [-cLpv] [host]:port backlog", myname);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
@@ -328,11 +361,14 @@ int main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Parse JCL.
|
* Parse JCL.
|
||||||
*/
|
*/
|
||||||
while ((ch = GETOPT(argc, argv, "cpvw:")) > 0) {
|
while ((ch = GETOPT(argc, argv, "cLpvw:")) > 0) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'c':
|
case 'c':
|
||||||
count++;
|
count++;
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
enable_lmtp = 1;
|
||||||
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
disable_pipelining = 1;
|
disable_pipelining = 1;
|
||||||
break;
|
break;
|
||||||
|
@@ -28,6 +28,8 @@
|
|||||||
/* Old mode: don't send HELO, and don't send message headers.
|
/* Old mode: don't send HELO, and don't send message headers.
|
||||||
/* .IP "-l length"
|
/* .IP "-l length"
|
||||||
/* Send \fIlength\fR bytes as message payload.
|
/* Send \fIlength\fR bytes as message payload.
|
||||||
|
/* .IP -L
|
||||||
|
/* Speak LMTP rather than SMTP.
|
||||||
/* .IP "-m message_count"
|
/* .IP "-m message_count"
|
||||||
/* Send the specified number of messages (default: 1).
|
/* Send the specified number of messages (default: 1).
|
||||||
/* .IP "-r recipient_count"
|
/* .IP "-r recipient_count"
|
||||||
@@ -104,6 +106,7 @@
|
|||||||
*/
|
*/
|
||||||
typedef struct SESSION {
|
typedef struct SESSION {
|
||||||
int xfer_count; /* # of xfers in session */
|
int xfer_count; /* # of xfers in session */
|
||||||
|
int rcpt_done; /* # of recipients done */
|
||||||
int rcpt_count; /* # of recipients to go */
|
int rcpt_count; /* # of recipients to go */
|
||||||
VSTREAM *stream; /* open connection */
|
VSTREAM *stream; /* open connection */
|
||||||
int connect_count; /* # of connect()s to retry */
|
int connect_count; /* # of connect()s to retry */
|
||||||
@@ -142,6 +145,7 @@ static int send_headers = 1;
|
|||||||
static int connect_count = 1;
|
static int connect_count = 1;
|
||||||
static int random_delay = 0;
|
static int random_delay = 0;
|
||||||
static int fixed_delay = 0;
|
static int fixed_delay = 0;
|
||||||
|
static int talk_lmtp = 0;
|
||||||
|
|
||||||
static void enqueue_connect(SESSION *);
|
static void enqueue_connect(SESSION *);
|
||||||
static void start_connect(SESSION *);
|
static void start_connect(SESSION *);
|
||||||
@@ -445,6 +449,7 @@ static void read_banner(int unused_event, char *context)
|
|||||||
static void send_helo(SESSION *session)
|
static void send_helo(SESSION *session)
|
||||||
{
|
{
|
||||||
int except;
|
int except;
|
||||||
|
char *protocol = (talk_lmtp ? "LHLO" : "EHLO");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Send the standard greeting with our hostname
|
* Send the standard greeting with our hostname
|
||||||
@@ -452,7 +457,7 @@ static void send_helo(SESSION *session)
|
|||||||
if ((except = setjmp(smtp_timeout_buf)) != 0)
|
if ((except = setjmp(smtp_timeout_buf)) != 0)
|
||||||
msg_fatal("%s while sending HELO", exception_text(except));
|
msg_fatal("%s while sending HELO", exception_text(except));
|
||||||
|
|
||||||
command(session->stream, "HELO %s", var_myhostname);
|
command(session->stream, "%s %s", protocol, var_myhostname);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare for the next event.
|
* Prepare for the next event.
|
||||||
@@ -520,6 +525,7 @@ static void mail_done(int unused, char *context)
|
|||||||
msg_fatal("sender rejected: %d %s", resp->code, resp->str);
|
msg_fatal("sender rejected: %d %s", resp->code, resp->str);
|
||||||
|
|
||||||
session->rcpt_count = recipients;
|
session->rcpt_count = recipients;
|
||||||
|
session->rcpt_done = 0;
|
||||||
send_rcpt(unused, context);
|
send_rcpt(unused, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -542,6 +548,7 @@ static void send_rcpt(int unused_event, char *context)
|
|||||||
else
|
else
|
||||||
command(session->stream, "RCPT TO:<%s>", recipient);
|
command(session->stream, "RCPT TO:<%s>", recipient);
|
||||||
session->rcpt_count--;
|
session->rcpt_count--;
|
||||||
|
session->rcpt_done++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Prepare for the next event.
|
* Prepare for the next event.
|
||||||
@@ -679,8 +686,10 @@ static void dot_done(int unused_event, char *context)
|
|||||||
*/
|
*/
|
||||||
if ((except = setjmp(smtp_timeout_buf)) != 0)
|
if ((except = setjmp(smtp_timeout_buf)) != 0)
|
||||||
msg_fatal("%s while sending message", exception_text(except));
|
msg_fatal("%s while sending message", exception_text(except));
|
||||||
if ((resp = response(session->stream, buffer))->code / 100 != 2)
|
do { /* XXX this could block */
|
||||||
msg_fatal("data %d %s", resp->code, resp->str);
|
if ((resp = response(session->stream, buffer))->code / 100 != 2)
|
||||||
|
msg_fatal("data %d %s", resp->code, resp->str);
|
||||||
|
} while (talk_lmtp && --session->rcpt_done > 0);
|
||||||
session->xfer_count++;
|
session->xfer_count++;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -740,7 +749,7 @@ int main(int argc, char **argv)
|
|||||||
/*
|
/*
|
||||||
* Parse JCL.
|
* Parse JCL.
|
||||||
*/
|
*/
|
||||||
while ((ch = GETOPT(argc, argv, "cC:df:l:m:or:R:s:t:vw:")) > 0) {
|
while ((ch = GETOPT(argc, argv, "cC:df:l:Lm:or:R:s:t:vw:")) > 0) {
|
||||||
switch (ch) {
|
switch (ch) {
|
||||||
case 'c':
|
case 'c':
|
||||||
count++;
|
count++;
|
||||||
@@ -765,6 +774,9 @@ int main(int argc, char **argv)
|
|||||||
message_data[i - 1] = '\n';
|
message_data[i - 1] = '\n';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 'L':
|
||||||
|
talk_lmtp = 1;
|
||||||
|
break;
|
||||||
case 'm':
|
case 'm':
|
||||||
if ((message_count = atoi(optarg)) <= 0)
|
if ((message_count = atoi(optarg)) <= 0)
|
||||||
usage(argv[0]);
|
usage(argv[0]);
|
||||||
|
Reference in New Issue
Block a user