Browse Source

add SASL2 support

Ralf S. Engelschall 24 years ago
parent
commit
9f7da5ec5a
2 changed files with 733 additions and 2 deletions
  1. 715 0
      postfix/postfix-sasl2.patch
  2. 18 2
      postfix/postfix.spec

+ 715 - 0
postfix/postfix-sasl2.patch

@@ -0,0 +1,715 @@
+diff -ru postfix-1.1.4-orig/README_FILES/SASL_README postfix-1.1.4/README_FILES/SASL_README
+--- postfix-1.1.4-orig/README_FILES/SASL_README	Sat May 26 11:32:47 2001
++++ postfix-1.1.4/README_FILES/SASL_README	Mon Mar 11 14:04:58 2002
+@@ -26,6 +26,14 @@
+ Note that this seems to be related to the auto_transition switch in
+ SASL. Note also that the Cyrus SASL documentation says that it is
+ pointless to enable that if you use "sasldb" for "pwcheck_method".
++Later versions of the SASL 1.5.x series should also work.
++
++Postfix+SASL 2.1.1 appears to work on Mandrake Linux 8.1 (pwcheck_method
++set to saslauthd or auxprop).  Note that the 'auxprop' pwcheck_method
++replaces the 'sasldb' method from SASL 1.5.x.  Postfix may need
++write access to /etc/sasldb2 if you are using the auto_transition
++feature, or if you are using an authentication mechanism such as OTP
++that needs to update secrets in the database.
+ 
+ Introduction
+ ============
+@@ -50,20 +58,22 @@
+ Building the SASL library
+ =========================
+ 
+-Postfix appears to work with cyrus-sasl-1.5.5, which is available
+-from:
++Postfix appears to work with cyrus-sasl-1.5.5 or cyrus-sasl-2.1.1, 
++which are available from:
+ 
+     ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/
+ 
+ IMPORTANT: if you install the Cyrus SASL libraries as per the default,
+-you will have to symlink /usr/lib/sasl -> /usr/local/lib/sasl.
++you will have to symlink /usr/lib/sasl -> /usr/local/lib/sasl for 
++version 1.5.5 or /usr/lib/sasl2 -> /usr/local/lib/sasl2 for version 2.1.1.
+ 
+ Reportedly, Microsoft Internet Explorer version 5 requires the
+ non-standard SASL LOGIN authentication method. To enable this
+ authentication method, specify ``./configure --enable-login''.
+ 
+ If you install the Cyrus SASL libraries as per the default, you
+-will have to symlink /usr/lib/sasl -> /usr/local/lib/sasl.
++will have to symlink /usr/lib/sasl -> /usr/local/lib/sasl for version 1.5.5
++or symlink /usr/lib/sasl2 -> /usr/local/lib/sasl2 for version 2.1.1.
+ 
+ Building Postfix with SASL authentication support
+ =================================================
+@@ -72,19 +82,33 @@
+ assumes that the Cyrus SASL include files are in /usr/local/include,
+ and that the Cyrus SASL libraries are in /usr/local/lib.
+ 
+-On some systems this generates the necessary Makefile definitions:
++On some systems this generates the necessary Makefile definitions for 
++Cyrus SASL 1.5.5:
+ 
+     % make tidy # if you have left-over files from a previous build
+     % make makefiles CCARGS="-DUSE_SASL_AUTH -I/usr/local/include" \
+ 	AUXLIBS="-L/usr/local/lib -lsasl"
+ 
++On some systems this generates the necessary Makefile definitions for 
++Cyrus SASL 2.1.1:
++
++    % make tidy # if you have left-over files from a previous build
++    % make makefiles CCARGS="-DUSE_SASL_AUTH -I/usr/local/include/sasl" \
++	AUXLIBS="-L/usr/local/lib -lsasl2"
++
+ On Solaris 2.x you need to specify run-time link information,
+ otherwise ld.so will not find the SASL shared library:
+ 
++(for version 1.5.5):
+     % make tidy # if you have left-over files from a previous build
+     % make makefiles CCARGS="-DUSE_SASL_AUTH -I/usr/local/include" \
+ 	AUXLIBS="-L/usr/local/lib -R/usr/local/lib -lsasl"
+ 
++(for version 2.1.1):
++    % make tidy # if you have left-over files from a previous build
++    % make makefiles CCARGS="-DUSE_SASL_AUTH -I/usr/local/include/sasl" \
++	AUXLIBS="-L/usr/local/lib -R/usr/local/lib -lsasl2"
++
+ Enabling SASL authentication in the Postfix SMTP server
+ =======================================================
+ 
+@@ -101,23 +125,41 @@
+ 	smtpd_recipient_restrictions = 
+ 	    permit_mynetworks permit_sasl_authenticated ...
+ 
+-In /usr/local/lib/sasl/smtpd.conf you need to specify how the server
+-should validate client passwords. 
++In /usr/local/lib/sasl/smtpd.conf (for version 1.5.5) or 
++/usr/local/lib/sasl2/smtpd.conf (for version 2.1.1) you need to 
++specify how the server should validate client passwords. 
+ 
+ In order to authenticate against the UNIX password database, try:
+ 
+     /usr/local/lib/sasl/smtpd.conf:
+ 	pwcheck_method: pwcheck
++   (use /usr/local/lib/sasl2/smtpd.conf with version 2.1.1)
+ 
+ The pwcheck daemon is contained in the cyrus-sasl source tarball.
+ 
+-In order to authenticate against SASL's own password database:
++Alternately, in SASL 1.5.27 and later (including 2.1.1), try:
++
++   /usr/local/lib/sasl/smtpd.conf:
++   	pwcheck_method: saslauthd
++   (use /usr/local/lib/sasl2/smtpd.conf with version 2.1.1)
++
++The saslauthd daemon is also contained in the cyrus-sasl source tarball.
++It is more flexible than the pwcheck daemon, in that it can authenticate
++against PAM and various other sources.
++
++In order to authenticate against SASL's own password database in version 1.5.5:
+ 
+     /usr/local/lib/sasl/smtpd.conf:
+ 	pwcheck_method:  sasldb
+ 
+-This will use the SASL password file (default: /etc/sasldb), which
+-is maintained with the saslpasswd command (part of the Cyrus SASL
++or in version 2.1.1:
++
++    /usr/local/lib/sasl2/smtpd.conf:
++    	pwcheck_method:  auxprop
++
++This will use the SASL password file (default: /etc/sasldb in 
++version 1.5.5, or /etc/sasldb2 in version 2.1.1), which is maintained
++with the saslpasswd or saslpasswd2 command (part of the Cyrus SASL 
+ software). On some poorly-supported 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 may
+diff -ru postfix-1.1.4-orig/conf/sample-auth.cf postfix-1.1.4/conf/sample-auth.cf
+--- postfix-1.1.4-orig/conf/sample-auth.cf	Mon Mar 11 00:44:43 2002
++++ postfix-1.1.4/conf/sample-auth.cf	Mon Mar 11 17:36:22 2002
+@@ -23,6 +23,7 @@
+ #
+ # In order to enable server-side authentication, build Postfix with
+ # SASL support, and install a configuration file /usr/lib/sasl/smtpd.conf
++# (for SASL version 1) or /usr/lib/sasl2/smtpd.conf (for SASL version 2)
+ # with as contents, for example,
+ #
+ #	pwcheck_method:  sasldb
+@@ -51,6 +52,10 @@
+ # nodictionary:	disallow methods subject to passive (dictionary) attack
+ # noanonymous:	disallow methods that allow anonymous authentication
+ # 
++# An additional options is available in SASL version 2:
++#
++# mutual_auth:	only allow methods that provide mutual authentication
++#
+ # By default, the Postfix SMTP server accepts plaintext passwords but
+ # not anonymous logins. 
+ #
+@@ -104,6 +109,10 @@
+ # nodictionary:	disallow methods subject to passive (dictionary) attack
+ # noanonymous:	disallow methods that allow anonymous authentication
+ # 
++# An additional options is available in SASL version 2:
++#
++# mutual_auth:	only allow methods that provide mutual authentication
++#
+ # By default, the Postfix SMTP client will not use plaintext passwords.
+ #
+ #smtp_sasl_security_options = 
+diff -ru postfix-1.1.4-orig/src/lmtp/lmtp_sasl_glue.c postfix-1.1.4/src/lmtp/lmtp_sasl_glue.c
+--- postfix-1.1.4-orig/src/lmtp/lmtp_sasl_glue.c	Fri Jan 19 15:46:44 2001
++++ postfix-1.1.4/src/lmtp/lmtp_sasl_glue.c	Mon Mar 11 17:35:33 2002
+@@ -116,6 +116,9 @@
+     "noactive", SASL_SEC_NOACTIVE,
+     "nodictionary", SASL_SEC_NODICTIONARY,
+     "noanonymous", SASL_SEC_NOANONYMOUS,
++#if SASL_VERSION_MAJOR >= 2
++    "mutual_auth", SASL_SEC_MUTUAL_AUTH,
++#endif
+     0,
+ };
+ 
+@@ -127,6 +130,44 @@
+ #define STR(x)	vstring_str(x)
+ 
+  /*
++  * Macros to handle API differences between SASLv1 and SASLv2.
++  * Specifics: 
++  *   The SASL_LOG_* constants were renamed in SASLv2.
++  *   SASLv2's sasl_client_new takes two new parameters to specify local
++  *     and remote IP addresses for auth mechs that use them.
++  *   SASLv2's sasl_client_start function no longer takes the secret parameter.
++  *   SASLv2's sasl_decode64 function takes an extra parameter for the 
++  *     length of the output buffer.
++  * 
++  * The other major change is that SASLv2 now takes more responsibility for
++  * deallocating memory that it allocates internally.  Thus, some of the
++  * function parameters are now 'const', to make sure we don't try to free
++  * them too.  This is dealt with in the code later on.
++  */
++
++#if SASL_VERSION_MAJOR < 2
++/* SASL version 1.x */
++#define SASL_LOG_WARN SASL_LOG_WARNING
++#define SASL_LOG_NOTE SASL_LOG_INFO
++#define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
++	sasl_client_new(srv, fqdn, prompt, secflags, pconn)
++#define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
++	sasl_client_start(conn, mechlst, secret, prompt, clout, cllen, mech)
++#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
++	sasl_decode64(in, inlen, out, outlen)
++#endif
++
++#if SASL_VERSION_MAJOR >= 2 
++/* SASL version > 2.x */
++#define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
++	sasl_client_new(srv, fqdn, lport, rport, prompt, secflags, pconn)
++#define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
++	sasl_client_start(conn, mechlst, prompt, clout, cllen, mech)
++#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
++	sasl_decode64(in, inlen, out, outmaxlen, outlen)
++#endif
++
++ /*
+   * Per-host login/password information.
+   */
+ static MAPS *lmtp_sasl_passwd_map;
+@@ -137,14 +178,18 @@
+ 			         const char *message)
+ {
+     switch (priority) {
+-	case SASL_LOG_ERR:
+-	case SASL_LOG_WARNING:
+-	msg_warn("%s", message);
++    case SASL_LOG_ERR:		/* unusual errors */
++    case SASL_LOG_WARN:		/* non-fatal warnings */
++	msg_warn("SASL authentication problem: %s", message);
+ 	break;
+-    case SASL_LOG_INFO:
++    case SASL_LOG_NOTE:		/* other info */
+ 	if (msg_verbose)
+-	    msg_info("%s", message);
++	    msg_info("SASL authentication info: %s", message);
+ 	break;
++#if SASL_VERSION_MAJOR >= 2
++    case SASL_LOG_FAIL:		/* authentication failures - SASLv2 only */
++	msg_warn("SASL authentication failure: %s", message);
++#endif
+     }
+     return (SASL_OK);
+ }
+@@ -317,7 +362,9 @@
+     memcpy((char *) state->sasl_callbacks, callbacks, sizeof(callbacks));
+     for (cp = state->sasl_callbacks; cp->id != SASL_CB_LIST_END; cp++)
+ 	cp->context = (void *) state;
+-    if (sasl_client_new("smtp", state->session->host,
++
++    if (SASL_CLIENT_NEW("smtp", state->session->host,
++			NULL, NULL,
+ 			state->sasl_callbacks, NULL_SECFLAGS,
+ 			(sasl_conn_t **) &state->sasl_conn) != SASL_OK)
+ 	msg_fatal("per-session SASL client initialization");
+@@ -354,7 +401,11 @@
+     char   *myname = "lmtp_sasl_authenticate";
+     unsigned enc_length;
+     unsigned enc_length_out;
++#if SASL_VERSION_MAJOR >= 2
++    const char *clientout;
++#else
+     char   *clientout;
++#endif
+     unsigned clientoutlen;
+     unsigned serverinlen;
+     LMTP_RESP *resp;
+@@ -374,7 +425,7 @@
+     /*
+      * Start the client side authentication protocol.
+      */
+-    result = sasl_client_start((sasl_conn_t *) state->sasl_conn,
++    result = SASL_CLIENT_START((sasl_conn_t *) state->sasl_conn,
+ 			       state->sasl_mechanism_list,
+ 			       NO_SASL_SECRET, NO_SASL_INTERACTION,
+ 			       &clientout, &clientoutlen, &mechanism);
+@@ -404,7 +455,10 @@
+ 			  STR(state->sasl_encoded), enc_length,
+ 			  &enc_length_out) != SASL_OK)
+ 	    msg_panic("%s: sasl_encode64 botch", myname);
++#if SASL_VERSION_MAJOR < 2
++	/* SASL version 1 doesn't free memory that it allocates. */
+ 	free(clientout);
++#endif
+ 	lmtp_chat_cmd(state, "AUTH %s %s", mechanism, STR(state->sasl_encoded));
+     } else {
+ 	lmtp_chat_cmd(state, "AUTH %s", mechanism);
+@@ -423,8 +477,8 @@
+ 	(void) mystrtok(&line, "- \t\n");	/* skip over result code */
+ 	serverinlen = strlen(line);
+ 	VSTRING_SPACE(state->sasl_decoded, serverinlen);
+-	if (sasl_decode64(line, serverinlen,
+-			STR(state->sasl_decoded), &enc_length) != SASL_OK) {
++	if (SASL_DECODE64(line, serverinlen, STR(state->sasl_decoded),
++			serverinlen, &enc_length) != SASL_OK) {
+ 	    vstring_sprintf(why, "malformed SASL challenge from server %s",
+ 			    state->session->namaddr);
+ 	    return (-1);
+@@ -456,7 +510,10 @@
+ 			      STR(state->sasl_encoded), enc_length,
+ 			      &enc_length_out) != SASL_OK)
+ 		msg_panic("%s: sasl_encode64 botch", myname);
++#if SASL_VERSION_MAJOR < 2
++	    /* SASL version 1 doesn't free memory that it allocates. */
+ 	    free(clientout);
++#endif
+ 	} else {
+ 	    vstring_strcat(state->sasl_encoded, "");
+ 	}
+@@ -487,7 +544,8 @@
+ 	state->sasl_passwd = 0;
+     }
+     if (state->sasl_mechanism_list) {
+-	myfree(state->sasl_mechanism_list);	/* allocated in lmtp_helo */
++	/* state->sasl_mechanism_list is allocated in lmtp_sasl_helo_auth */
++	myfree(state->sasl_mechanism_list); 
+ 	state->sasl_mechanism_list = 0;
+     }
+     if (state->sasl_conn) {
+diff -ru postfix-1.1.4-orig/src/smtp/smtp_sasl_glue.c postfix-1.1.4/src/smtp/smtp_sasl_glue.c
+--- postfix-1.1.4-orig/src/smtp/smtp_sasl_glue.c	Mon Jul  2 14:12:54 2001
++++ postfix-1.1.4/src/smtp/smtp_sasl_glue.c	Mon Mar 11 17:35:41 2002
+@@ -116,6 +116,9 @@
+     "noactive", SASL_SEC_NOACTIVE,
+     "nodictionary", SASL_SEC_NODICTIONARY,
+     "noanonymous", SASL_SEC_NOANONYMOUS,
++#if SASL_VERSION_MAJOR >= 2
++    "mutual_auth", SASL_SEC_MUTUAL_AUTH,
++#endif
+     0,
+ };
+ 
+@@ -127,6 +130,44 @@
+ #define STR(x)	vstring_str(x)
+ 
+  /*
++  * Macros to handle API differences between SASLv1 and SASLv2.
++  * Specifics: 
++  *   The SASL_LOG_* constants were renamed in SASLv2.
++  *   SASLv2's sasl_client_new takes two new parameters to specify local
++  *     and remote IP addresses for auth mechs that use them.
++  *   SASLv2's sasl_client_start function no longer takes the secret parameter.
++  *   SASLv2's sasl_decode64 function takes an extra parameter for the 
++  *     length of the output buffer.
++  * 
++  * The other major change is that SASLv2 now takes more responsibility for
++  * deallocating memory that it allocates internally.  Thus, some of the
++  * function parameters are now 'const', to make sure we don't try to free
++  * them too.  This is dealt with in the code later on.
++  */
++
++#if SASL_VERSION_MAJOR < 2
++/* SASL version 1.x */
++#define SASL_LOG_WARN SASL_LOG_WARNING
++#define SASL_LOG_NOTE SASL_LOG_INFO
++#define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
++	sasl_client_new(srv, fqdn, prompt, secflags, pconn)
++#define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
++	sasl_client_start(conn, mechlst, secret, prompt, clout, cllen, mech)
++#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
++	sasl_decode64(in, inlen, out, outlen)
++#endif
++
++#if SASL_VERSION_MAJOR >= 2 
++/* SASL version > 2.x */
++#define SASL_CLIENT_NEW(srv, fqdn, lport, rport, prompt, secflags, pconn) \
++	sasl_client_new(srv, fqdn, lport, rport, prompt, secflags, pconn)
++#define SASL_CLIENT_START(conn, mechlst, secret, prompt, clout, cllen, mech) \
++	sasl_client_start(conn, mechlst, prompt, clout, cllen, mech)
++#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
++	sasl_decode64(in, inlen, out, outmaxlen, outlen)
++#endif
++
++ /*
+   * Per-host login/password information.
+   */
+ static MAPS *smtp_sasl_passwd_map;
+@@ -137,14 +178,18 @@
+ 			         const char *message)
+ {
+     switch (priority) {
+-	case SASL_LOG_ERR:
+-	case SASL_LOG_WARNING:
++    case SASL_LOG_ERR:		/* unusual errors */
++    case SASL_LOG_WARN:		/* non-fatal warnings */
+ 	msg_warn("SASL authentication problem: %s", message);
+ 	break;
+-    case SASL_LOG_INFO:
++    case SASL_LOG_NOTE:		/* other info */
+ 	if (msg_verbose)
+ 	    msg_info("SASL authentication info: %s", message);
+ 	break;
++#if SASL_VERSION_MAJOR >= 2
++    case SASL_LOG_FAIL:		/* authentication failures - SASLv2 only */
++	msg_warn("SASL authentication failure: %s", message);
++#endif
+     }
+     return (SASL_OK);
+ }
+@@ -317,7 +362,9 @@
+     memcpy((char *) state->sasl_callbacks, callbacks, sizeof(callbacks));
+     for (cp = state->sasl_callbacks; cp->id != SASL_CB_LIST_END; cp++)
+ 	cp->context = (void *) state;
+-    if (sasl_client_new("smtp", state->session->host,
++
++    if (SASL_CLIENT_NEW("smtp", state->session->host,
++			NULL, NULL,
+ 			state->sasl_callbacks, NULL_SECFLAGS,
+ 			(sasl_conn_t **) &state->sasl_conn) != SASL_OK)
+ 	msg_fatal("per-session SASL client initialization");
+@@ -354,7 +401,11 @@
+     char   *myname = "smtp_sasl_authenticate";
+     unsigned enc_length;
+     unsigned enc_length_out;
++#if SASL_VERSION_MAJOR >= 2
++    const char *clientout;
++#else
+     char   *clientout;
++#endif
+     unsigned clientoutlen;
+     unsigned serverinlen;
+     SMTP_RESP *resp;
+@@ -374,7 +425,7 @@
+     /*
+      * Start the client side authentication protocol.
+      */
+-    result = sasl_client_start((sasl_conn_t *) state->sasl_conn,
++    result = SASL_CLIENT_START((sasl_conn_t *) state->sasl_conn,
+ 			       state->sasl_mechanism_list,
+ 			       NO_SASL_SECRET, NO_SASL_INTERACTION,
+ 			       &clientout, &clientoutlen, &mechanism);
+@@ -404,7 +455,10 @@
+ 			  STR(state->sasl_encoded), enc_length,
+ 			  &enc_length_out) != SASL_OK)
+ 	    msg_panic("%s: sasl_encode64 botch", myname);
++#if SASL_VERSION_MAJOR < 2
++	/* SASL version 1 doesn't free memory that it allocates. */
+ 	free(clientout);
++#endif
+ 	smtp_chat_cmd(state, "AUTH %s %s", mechanism, STR(state->sasl_encoded));
+     } else {
+ 	smtp_chat_cmd(state, "AUTH %s", mechanism);
+@@ -423,8 +477,8 @@
+ 	(void) mystrtok(&line, "- \t\n");	/* skip over result code */
+ 	serverinlen = strlen(line);
+ 	VSTRING_SPACE(state->sasl_decoded, serverinlen);
+-	if (sasl_decode64(line, serverinlen,
+-			STR(state->sasl_decoded), &enc_length) != SASL_OK) {
++	if (SASL_DECODE64(line, serverinlen, STR(state->sasl_decoded),
++			serverinlen, &enc_length) != SASL_OK) {
+ 	    vstring_sprintf(why, "malformed SASL challenge from server %s",
+ 			    state->session->namaddr);
+ 	    return (-1);
+@@ -456,7 +510,10 @@
+ 			      STR(state->sasl_encoded), enc_length,
+ 			      &enc_length_out) != SASL_OK)
+ 		msg_panic("%s: sasl_encode64 botch", myname);
++#if SASL_VERSION_MAJOR < 2
++	    /* SASL version 1 doesn't free memory that it allocates. */
+ 	    free(clientout);
++#endif
+ 	} else {
+ 	    vstring_strcat(state->sasl_encoded, "");
+ 	}
+@@ -487,7 +544,8 @@
+ 	state->sasl_passwd = 0;
+     }
+     if (state->sasl_mechanism_list) {
+-	myfree(state->sasl_mechanism_list);	/* allocated in smtp_helo */
++	/* state->sasl_mechanism_list is allocated in smtp_sasl_helo_auth */
++	myfree(state->sasl_mechanism_list); 
+ 	state->sasl_mechanism_list = 0;
+     }
+     if (state->sasl_conn) {
+diff -ru postfix-1.1.4-orig/src/smtpd/smtpd.h postfix-1.1.4/src/smtpd/smtpd.h
+--- postfix-1.1.4-orig/src/smtpd/smtpd.h	Mon Mar 11 00:44:45 2002
++++ postfix-1.1.4/src/smtpd/smtpd.h	Mon Mar 11 14:04:58 2002
+@@ -69,7 +69,11 @@
+     off_t   msg_size;
+     int     junk_cmds;
+ #ifdef USE_SASL_AUTH
++# if SASL_VERSION_MAJOR >= 2
++    const char *sasl_mechanism_list;
++# else
+     char   *sasl_mechanism_list;
++# endif
+     char   *sasl_method;
+     char   *sasl_username;
+     char   *sasl_sender;
+diff -ru postfix-1.1.4-orig/src/smtpd/smtpd_sasl_glue.c postfix-1.1.4/src/smtpd/smtpd_sasl_glue.c
+--- postfix-1.1.4-orig/src/smtpd/smtpd_sasl_glue.c	Sun Nov 25 18:14:01 2001
++++ postfix-1.1.4/src/smtpd/smtpd_sasl_glue.c	Mon Mar 11 17:35:37 2002
+@@ -110,20 +110,69 @@
+  */
+ #define STR(s)	vstring_str(s)
+ 
++ /*
++  * Macros to handle API differences between SASLv1 and SASLv2.
++  * Specifics: 
++  *   The SASL_LOG_* constants were renamed in SASLv2.
++  *   SASLv2's sasl_server_new takes two new parameters to specify local
++  *     and remote IP addresses for auth mechs that use them.
++  *   SASLv2's sasl_server_start and sasl_server_step no longer have the 
++  *     errstr parameter.
++  *   SASLv2's sasl_decode64 function takes an extra parameter for the 
++  *     length of the output buffer.
++  * 
++  * The other major change is that SASLv2 now takes more responsibility for
++  * deallocating memory that it allocates internally.  Thus, some of the
++  * function parameters are now 'const', to make sure we don't try to free
++  * them too.  This is dealt with in the code later on.
++  */
++
++#if SASL_VERSION_MAJOR < 2
++/* SASL version 1.x */
++#define SASL_LOG_WARN SASL_LOG_WARNING
++#define SASL_LOG_NOTE SASL_LOG_INFO
++#define SASL_SERVER_NEW(srv, fqdn, rlm, lport, rport, cb, secflags, pconn) \
++	sasl_server_new(srv, fqdn, rlm, cb, secflags, pconn)
++#define SASL_SERVER_START(conn, mech, clin, clinlen, srvout, srvoutlen, err) \
++	sasl_server_start(conn, mech, clin, clinlen, srvout, srvoutlen, err)
++#define SASL_SERVER_STEP(conn, clin, clinlen, srvout, srvoutlen, err) \
++	sasl_server_step(conn, clin, clinlen, srvout, srvoutlen, err)
++#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
++	sasl_decode64(in, inlen, out, outlen)
++#endif
++
++#if SASL_VERSION_MAJOR >= 2 
++/* SASL version > 2.x */
++#define SASL_SERVER_NEW(srv, fqdn, rlm, lport, rport, cb, secflags, pconn) \
++	sasl_server_new(srv, fqdn, rlm, lport, rport, cb, secflags, pconn)
++#define SASL_SERVER_START(conn, mech, clin, clinlen, srvout, srvoutlen, err) \
++	sasl_server_start(conn, mech, clin, clinlen, srvout, srvoutlen)
++#define SASL_SERVER_STEP(conn, clin, clinlen, srvout, srvoutlen, err) \
++	sasl_server_step(conn, clin, clinlen, srvout, srvoutlen)
++#define SASL_DECODE64(in, inlen, out, outmaxlen, outlen) \
++	sasl_decode64(in, inlen, out, outmaxlen, outlen)
++#endif
++
+ /* smtpd_sasl_log - SASL logging callback */
+ 
+ static int smtpd_sasl_log(void *unused_context, int priority,
+ 			          const char *message)
+ {
+     switch (priority) {
+-	case SASL_LOG_ERR:
+-	case SASL_LOG_WARNING:
++    case SASL_LOG_ERR:
++    case SASL_LOG_WARN:
+ 	msg_warn("SASL authentication problem: %s", message);
+ 	break;
+-    case SASL_LOG_INFO:
++    case SASL_LOG_NOTE:
+ 	if (msg_verbose)
+ 	    msg_info("SASL authentication info: %s", message);
+ 	break;
++#if SASL_VERSION_MAJOR >= 2
++    case SASL_LOG_FAIL:
++	if (msg_verbose)
++	    msg_info("SASL authentication failure: %s", message);
++	break;
++#endif
+     }
+     return SASL_OK;
+ }
+@@ -144,6 +193,9 @@
+     "noactive", SASL_SEC_NOACTIVE,
+     "nodictionary", SASL_SEC_NODICTIONARY,
+     "noanonymous", SASL_SEC_NOANONYMOUS,
++#if SASL_VERSION_MAJOR >= 2
++    "mutual_auth", SASL_SEC_MUTUAL_AUTH,
++#endif
+     0,
+ };
+ 
+@@ -174,6 +226,9 @@
+ {
+     unsigned sasl_mechanism_count;
+     sasl_security_properties_t sec_props;
++    char    *iplocal;
++    char    *ipremote;
++
+ 
+     /*
+      * Initialize SASL-specific state variables. Use long-lived storage for
+@@ -195,11 +250,24 @@
+ #define NO_SECURITY_LAYERS	(0)
+ #define NO_SESSION_CALLBACKS	((sasl_callback_t *) 0)
+ 
+-    if (sasl_server_new("smtp", var_myhostname, var_smtpd_sasl_realm,
++
++#if SASL_VERSION_MAJOR >= 2 && defined(USE_SASL_IP_AUTH)
++    /* Get IP addresses of local and remote hosts to pass to SASL. */
++
++#else
++    /* Don't give any IP information to SASL.  SASLv1 doesn't use it, and
++     * in SASLv2 this will disable any mechs that do.
++     */
++    iplocal = NULL;
++    ipremote = NULL;
++#endif
++
++    if (SASL_SERVER_NEW("smtp", var_myhostname, var_smtpd_sasl_realm,
++			iplocal, ipremote,
+ 			NO_SESSION_CALLBACKS, NO_SECURITY_LAYERS,
+ 			&state->sasl_conn) != SASL_OK)
+ 	msg_fatal("SASL per-connection server initialization");
+-
++    
+     /*
+      * Security options. Some information can be found in the sasl.h include
+      * file. Disallow anonymous authentication; this is because the
+@@ -239,7 +307,10 @@
+ void    smtpd_sasl_disconnect(SMTPD_STATE *state)
+ {
+     if (state->sasl_mechanism_list) {
++#if SASL_VERSION_MAJOR < 2
++	/* SASL version 1 doesn't free memory that it allocates. */
+ 	free(state->sasl_mechanism_list);
++#endif
+ 	state->sasl_mechanism_list = 0;
+     }
+     if (state->sasl_conn) {
+@@ -262,10 +333,18 @@
+     unsigned enc_length;
+     unsigned enc_length_out;
+     unsigned reply_len;
+-    char   *serverout = 0;
+     unsigned serveroutlen;
+     int     result;
++    
++#if SASL_VERSION_MAJOR < 2
++    char   *serverout = 0;
++#else
++    const char *serverout = 0;
++#endif
++
++#if SASL_VERSION_MAJOR < 2
+     const char *errstr = 0;
++#endif
+ 
+ #define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
+ 
+@@ -288,8 +367,8 @@
+ 	reply_len = strlen(init_response);
+ 	VSTRING_SPACE(state->sasl_decoded, reply_len);
+ 	dec_buffer = STR(state->sasl_decoded);
+-	if (sasl_decode64(init_response, reply_len,
+-			  dec_buffer, &dec_length) != SASL_OK)
++	if (SASL_DECODE64(init_response, reply_len,
++			  dec_buffer, reply_len, &dec_length) != SASL_OK)
+ 	    return ("501 Authentication failed: malformed initial response");
+ 	if (msg_verbose)
+ 	    msg_info("%s: decoded initial response %s", myname, dec_buffer);
+@@ -297,7 +376,7 @@
+ 	dec_buffer = 0;
+ 	dec_length = 0;
+     }
+-    result = sasl_server_start(state->sasl_conn, sasl_method, dec_buffer,
++    result = SASL_SERVER_START(state->sasl_conn, sasl_method, dec_buffer,
+ 			    dec_length, &serverout, &serveroutlen, &errstr);
+ 
+     /*
+@@ -327,7 +406,10 @@
+ 	if (sasl_encode64(serverout, serveroutlen, STR(state->sasl_encoded),
+ 			  enc_length, &enc_length_out) != SASL_OK)
+ 	    msg_panic("%s: sasl_encode64 botch", myname);
++#if SASL_VERSION_MAJOR < 2
++	/* SASL version 1 doesn't free memory that it allocates. */
+ 	free(serverout);
++#endif
+ 	serverout = 0;
+ 	smtpd_chat_reply(state, "334 %s", STR(state->sasl_encoded));
+ 
+@@ -342,21 +424,24 @@
+ 	    return ("501 Authentication aborted");	/* XXX */
+ 	reply_len = VSTRING_LEN(state->buffer);
+ 	VSTRING_SPACE(state->sasl_decoded, reply_len);
+-	if (sasl_decode64(vstring_str(state->buffer), reply_len,
+-			  STR(state->sasl_decoded), &dec_length) != SASL_OK)
++	if (SASL_DECODE64(vstring_str(state->buffer), reply_len,
++			  STR(state->sasl_decoded), reply_len, 
++			  &dec_length) != SASL_OK)
+ 	    return ("501 Error: malformed authentication response");
+ 	if (msg_verbose)
+ 	    msg_info("%s: decoded response: %.*s",
+ 		     myname, (int) dec_length, STR(state->sasl_decoded));
+-	result = sasl_server_step(state->sasl_conn, STR(state->sasl_decoded),
++	result = SASL_SERVER_STEP(state->sasl_conn, STR(state->sasl_decoded),
+ 			    dec_length, &serverout, &serveroutlen, &errstr);
+     }
+ 
++#if SASL_VERSION_MAJOR < 2
+     /*
+      * Cleanup. What an awful interface.
+      */
+     if (serverout)
+ 	free(serverout);
++#endif
+ 
+     /*
+      * The authentication protocol was completed.
+@@ -369,8 +454,13 @@
+      * accounting purposes. For the sake of completeness we also record the
+      * authentication method that was used. XXX Do not free(serverout).
+      */
++#if SASL_VERSION_MAJOR >= 2
++    result = sasl_getprop(state->sasl_conn, SASL_USERNAME,
++			  (const void **) &serverout);
++#else
+     result = sasl_getprop(state->sasl_conn, SASL_USERNAME,
+ 			  (void **) &serverout);
++#endif
+     if (result != SASL_OK || serverout == 0)
+ 	msg_panic("%s: sasl_getprop SASL_USERNAME botch", myname);
+     state->sasl_username = mystrdup(serverout);
+

+ 18 - 2
postfix/postfix.spec

@@ -32,6 +32,9 @@
 %ifndef       with_tls
 %define       with_tls    no
 %endif
+%ifndef       with_sasl
+%define       with_sasl   no
+%endif
 
 #   package information
 Name:         postfix
@@ -43,7 +46,7 @@ Distribution: OpenPKG [REL]
 Group:        Mail
 License:      IPL
 Version:      %{V_postfix}
-Release:      20020615
+Release:      20020705
 
 #   list of sources
 Source0:      ftp://ftp.porcupine.org/mirrors/postfix-release/official/postfix-%{V_postfix}.tar.gz
@@ -52,6 +55,7 @@ Source2:      fakesyslog.tar.gz
 Source3:      etc.tar
 Source4:      http://jimsun.linxnet.com/downloads/pflogsumm-%{V_pflogsumm}.pl
 Source5:      rc.postfix
+Source6:      postfix-sasl2.patch
 
 #   build information
 Prefix:       %{l_prefix}
@@ -62,6 +66,10 @@ BuildPreReq:  db, pcre
 %if "%{with_tls}" == "yes"
 BuildPreReq:  openssl, patch
 %endif
+%if "%{with_sasl}" == "yes"
+BuildPreReq:  sasl
+PreReq:       sasl
+%endif
 AutoReq:      no
 AutoReqProv:  no
 Provides:     MTA
@@ -77,8 +85,9 @@ Provides:     MTA
     o Optional STARTTLS support
     o Optional Berkeley-DB lookup table support
     o Optional PCRE matching support
+    o Optional SASL2 authentication support
 
-    Options: with_tls=%{with_tls}
+    Options: with_tls=%{with_tls} with_sasl=%{with_sasl}
 
 %prep
     %setup0 -q -c -a 0
@@ -90,6 +99,9 @@ Provides:     MTA
     cd postfix-%{V_postfix}
 %if "%{with_tls}" == "yes"
     %{l_patch} -p1 < ../pfixtls-%{V_tls}/pfixtls.diff
+%endif
+%if "%{with_sasl}" == "yes"
+    %{l_patch} -p1 < %{SOURCE postfix-sasl2.patch}
 %endif
     %{l_shtool} subst \
         -e 's/var_config_dir, /var_command_dir, /' \
@@ -134,6 +146,10 @@ Provides:     MTA
 %if "%{with_tls}" == "yes"
     CCARGS="$CCARGS -DHAS_SSL"
     AUXLIBS="$AUXLIBS -lssl -lcrypto"
+%endif
+%if "%{with_sasl}" == "yes"
+    CCARGS="$CCARGS -DUSE_SASL_AUTH -I%{l_prefix}/include/sasl"
+    AUXLIBS="$AUXLIBS -lsasl2"
 %endif
     AUXLIBS="$AUXLIBS -L$fakesyslogdir -lfakesyslog"
     %{l_make} %{l_mflags} makefiles \