2
0
mirror of https://github.com/vdukhovni/postfix synced 2025-08-30 21:55:20 +00:00

snapshot-20000418

This commit is contained in:
Wietse Venema
2000-04-18 00:00:00 +00:00
parent 1656957b3c
commit 17d46ec1c0
7 changed files with 116 additions and 55 deletions

View File

@@ -3819,4 +3819,11 @@ Apologies for any names omitted.
20000417
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.

View File

@@ -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
Cyrus SASL library, which is light years away from production
quality. There is not enough documentation to figure out how the
software is supposed to work.
Cyrus SASL library, which has not enough documentation about how
the software is supposed to work.
The SASL library code works only on LINUX and Solaris. If you
build Postfix+SASL on other systems, the software builds without
trouble but fails at runtime due to no available authentication
mechanisms. It can be made to work with considerable tweaking.
Postfix+SASL 1.5.5 appears to work on RedHat 6.1 (pwcheck_method
of shadow or sasldb), Solaris 2.7 (pwcheck_method of shadow or
sasldb), and FreeBSD 3.4 (pwcheck_method of sasldb). On RedHat
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
============
@@ -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
version with only the bare necessities.
When receiving mail, Postfix logs the client-provided username and
sender address to the maillog file, and optionally grants mail
relay access to authenticated clients. SASL authentication information
is not passed on via message headers or via SMTP. It is no-one's
business what username and authentication method the poster was
using in order to access the mail server.
When receiving mail, Postfix logs the client-provided username,
authentication method, and sender address to the maillog file, and
optionally grants mail access via the permit_sasl_authenticated
UCE restriction. SASL authentication information is not passed on
via message headers or via SMTP. It is no-one's business what
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
a username/password is known, it will use that to authenticate
to the server.
When sending mail, Postfix looks up the server hostname in a table,
and if a username/password is found, it will use that username and
password to authenticate to the server.
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
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
the only way that I was able to test, but which is undesirable
because it uses plaintext passwords.
If you wish to use the system shadow password file, the Postfix
SMTP server can't run chrooted (see master.cf), and the postfix
user or group needs read access to the shadow passwd file.
This will use the SASL password file (default: /etc/sasldb), which
is maintained with the saslpasswd command. On some systems the
saslpasswd command needs to be run multiple times before it stops
complaining. The Postfix SMTP server needs read access to the
sasldb file - you have to play games with group access permissions.
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
/etc/postfix/sasl_passwd:
host.domain username:password
host.domain username
foo.com username:password
bar.com username
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

View File

@@ -15,7 +15,7 @@
* Version of this program.
*/
#define VAR_MAIL_VERSION "mail_version"
#define DEF_MAIL_VERSION "Snapshot-20000417"
#define DEF_MAIL_VERSION "Snapshot-20000418"
extern char *var_mail_version;
/* LICENSE

View File

@@ -14,7 +14,7 @@
/* SMTP_STATE *state;
/* DESCRIPTION
/* 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.
/*
/* smtp_sasl_helo_auth() processes the AUTH option in the
@@ -71,7 +71,7 @@
/* 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) {
state->sasl_mechanism_list = mystrdup(words);
state->features |= SMTP_FEATURE_AUTH;
} else {
msg_warn("%s offered null AUTH mechanism list",
state->session->namaddr);
}
}
/* 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);
int ret = 0;
/*
* Skip authentication when we have no authentication info for this
* server. In that case it should simply treat us like any stranger.
* Otherwise, if authentication fails assume the error is recoverable.
* Skip authentication when no authentication info exists for this
* server, so that we talk to each other like strangers. Otherwise, if
* authentication information exists, assume that authentication is
* required, and assume that an authentication error is recoverable.
*/
if (smtp_sasl_passwd_lookup(state) != 0) {
smtp_sasl_start(state);

View File

@@ -47,7 +47,7 @@
/* This member is a null pointer in the absence of successful
/* authentication.
/* .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.
/*
/* 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");
/*
* Security options. XXX What exactly is this supposed to be doing? The
* cyrus-sasl-1.5.15 source code has no documentation at all about this
* routine.
*
* Disallow anonymous authentication. The permit_sasl_authenticated feature
* is restricted to authenticated clients only.
* Security options. Some information can be found in the sasl.h include
* file. Disallow anonymous authentication; this is because the
* permit_sasl_authenticated feature is restricted to authenticated
* clients only.
*/
memset(&sec_props, 0, sizeof(sec_props));
sec_props.min_ssf = 0;
@@ -277,7 +275,7 @@ char *smtpd_sasl_authenticate(SMTPD_STATE *state,
dec_buffer = STR(state->sasl_decoded);
if (sasl_decode64(init_response, reply_len,
dec_buffer, &dec_length) != SASL_OK)
return ("501 AUTH failed: malformed initial response");
return ("501 Authentication failed: malformed initial response");
if (msg_verbose)
msg_info("%s: decoded initial response %s", myname, dec_buffer);
} else {
@@ -302,6 +300,9 @@ char *smtpd_sasl_authenticate(SMTPD_STATE *state,
* comes in multiples of four bytes for each triple of input bytes,
* plus four bytes for any incomplete last triple, plus one byte for
* the null terminator.
*
* XXX Replace the klunky sasl_encode64() interface by something that
* uses VSTRING buffers.
*/
if (msg_verbose)
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)
free(serverout);

View File

@@ -2,9 +2,9 @@
/* NAME
/* smtp-sink 8
/* SUMMARY
/* multi-threaded smtp test server
/* multi-threaded SMTP/LMTP test server
/* SYNOPSIS
/* smtp-sink [-c] [-p] [-v] [-w delay] [host]:port backlog
/* smtp-sink [-cLpv] [-w delay] [host]:port backlog
/* DESCRIPTION
/* \fIsmtp-sink\fR listens on the named host (or address) and port.
/* It takes SMTP messages from the network and throws them away.
@@ -14,6 +14,8 @@
/* .IP -c
/* Display a running counter that is updated whenever an SMTP
/* QUIT command is executed.
/* .IP -L
/* Speak LMTP rather than SMTP.
/* .IP -p
/* Disable ESMTP command pipelining.
/* .IP -v
@@ -21,7 +23,7 @@
/* .IP "-w delay"
/* Wait \fIdelay\fR seconds before responding to a DATA command.
/* SEE ALSO
/* smtp-source, SMTP test message generator
/* smtp-source, SMTP/LMTP test message generator
/* LICENSE
/* .ad
/* .fi
@@ -71,6 +73,7 @@ typedef struct SINK_STATE {
VSTREAM *stream;
int data_state;
int (*read) (struct SINK_STATE *);
int rcpts;
} SINK_STATE;
#define ST_ANY 0
@@ -91,6 +94,7 @@ static int count;
static int counter;
static int disable_pipelining;
static int fixed_delay;
static int enable_lmtp;
/* ehlo_response - respond to EHLO command */
@@ -109,6 +113,22 @@ static void ok_response(SINK_STATE *state)
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 */
static void data_response(SINK_STATE *state)
@@ -127,6 +147,18 @@ static void data_event(int unused_event, char *context)
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 */
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 (msg_verbose)
msg_info(".");
ok_response(state);
dot_response(state);
state->read = command_read;
break;
}
@@ -203,8 +235,9 @@ typedef struct SINK_COMMAND {
static SINK_COMMAND command_table[] = {
"helo", ok_response,
"ehlo", ehlo_response,
"mail", ok_response,
"rcpt", ok_response,
"lhlo", ehlo_response,
"mail", mail_response,
"rcpt", rcpt_response,
"data", data_response,
"rset", ok_response,
"noop", ok_response,
@@ -311,7 +344,7 @@ static void connect_event(int unused_event, char *context)
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)
@@ -328,11 +361,14 @@ int main(int argc, char **argv)
/*
* Parse JCL.
*/
while ((ch = GETOPT(argc, argv, "cpvw:")) > 0) {
while ((ch = GETOPT(argc, argv, "cLpvw:")) > 0) {
switch (ch) {
case 'c':
count++;
break;
case 'L':
enable_lmtp = 1;
break;
case 'p':
disable_pipelining = 1;
break;

View File

@@ -28,6 +28,8 @@
/* Old mode: don't send HELO, and don't send message headers.
/* .IP "-l length"
/* Send \fIlength\fR bytes as message payload.
/* .IP -L
/* Speak LMTP rather than SMTP.
/* .IP "-m message_count"
/* Send the specified number of messages (default: 1).
/* .IP "-r recipient_count"
@@ -104,6 +106,7 @@
*/
typedef struct SESSION {
int xfer_count; /* # of xfers in session */
int rcpt_done; /* # of recipients done */
int rcpt_count; /* # of recipients to go */
VSTREAM *stream; /* open connection */
int connect_count; /* # of connect()s to retry */
@@ -142,6 +145,7 @@ static int send_headers = 1;
static int connect_count = 1;
static int random_delay = 0;
static int fixed_delay = 0;
static int talk_lmtp = 0;
static void enqueue_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)
{
int except;
char *protocol = (talk_lmtp ? "LHLO" : "EHLO");
/*
* Send the standard greeting with our hostname
@@ -452,7 +457,7 @@ static void send_helo(SESSION *session)
if ((except = setjmp(smtp_timeout_buf)) != 0)
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.
@@ -520,6 +525,7 @@ static void mail_done(int unused, char *context)
msg_fatal("sender rejected: %d %s", resp->code, resp->str);
session->rcpt_count = recipients;
session->rcpt_done = 0;
send_rcpt(unused, context);
}
@@ -542,6 +548,7 @@ static void send_rcpt(int unused_event, char *context)
else
command(session->stream, "RCPT TO:<%s>", recipient);
session->rcpt_count--;
session->rcpt_done++;
/*
* 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)
msg_fatal("%s while sending message", exception_text(except));
if ((resp = response(session->stream, buffer))->code / 100 != 2)
msg_fatal("data %d %s", resp->code, resp->str);
do { /* XXX this could block */
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++;
/*
@@ -740,7 +749,7 @@ int main(int argc, char **argv)
/*
* 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) {
case 'c':
count++;
@@ -765,6 +774,9 @@ int main(int argc, char **argv)
message_data[i - 1] = '\n';
}
break;
case 'L':
talk_lmtp = 1;
break;
case 'm':
if ((message_count = atoi(optarg)) <= 0)
usage(argv[0]);