From: Wietse Venema Date: Tue, 18 Apr 2000 00:00:00 +0000 (+0000) Subject: snapshot-20000418 X-Git-Tag: v20010228~63 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=17d46ec1c0df1598d1e9996a4e7ab060e6e96645;p=thirdparty%2Fpostfix.git snapshot-20000418 --- diff --git a/postfix/HISTORY b/postfix/HISTORY index bab37d87a..5f17ecb36 100644 --- a/postfix/HISTORY +++ b/postfix/HISTORY @@ -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. diff --git a/postfix/SASL_README b/postfix/SASL_README index 7a9926c99..767a13cfe 100644 --- a/postfix/SASL_README +++ b/postfix/SASL_README @@ -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 - -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. + pwcheck_method: sasldb -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 diff --git a/postfix/global/mail_version.h b/postfix/global/mail_version.h index 3be0516b4..4999f7b1c 100644 --- a/postfix/global/mail_version.h +++ b/postfix/global/mail_version.h @@ -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 diff --git a/postfix/smtp/smtp_sasl_proto.c b/postfix/smtp/smtp_sasl_proto.c index 2b17e47fc..f38182365 100644 --- a/postfix/smtp/smtp_sasl_proto.c +++ b/postfix/smtp/smtp_sasl_proto.c @@ -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); diff --git a/postfix/smtpd/smtpd_sasl_glue.c b/postfix/smtpd/smtpd_sasl_glue.c index 2c8ed540f..5372e5c31 100644 --- a/postfix/smtpd/smtpd_sasl_glue.c +++ b/postfix/smtpd/smtpd_sasl_glue.c @@ -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); diff --git a/postfix/smtpstone/smtp-sink.c b/postfix/smtpstone/smtp-sink.c index 5619f0b10..7cd5e65e5 100644 --- a/postfix/smtpstone/smtp-sink.c +++ b/postfix/smtpstone/smtp-sink.c @@ -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; diff --git a/postfix/smtpstone/smtp-source.c b/postfix/smtpstone/smtp-source.c index 5968acf5e..1181ffaff 100644 --- a/postfix/smtpstone/smtp-source.c +++ b/postfix/smtpstone/smtp-source.c @@ -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]);