-TCRYPTO_EX_DATA
-TCTABLE
-TCTABLE_ENTRY
+-TXSASL_CYRUS_CLIENT
+-TXSASL_CYRUS_ERROR_INFO
+-TXSASL_CYRUS_SERVER
-TDELIVER_ATTR
-TDELIVER_REQUEST
-TDELTA_TIME
-TX509
-TX509_NAME
-TX509_STORE_CTX
+-TXSASL_CLIENT
+-TXSASL_CLIENT_IMPL
+-TXSASL_CLIENT_IMPL_INFO
+-TXSASL_SERVER
+-TXSASL_SERVER_IMPL
+-TXSASL_SERVER_IMPL_INFO
-Tregex_t
-Tregmatch_t
-Tsasl_conn_t
logic for address list and fallback relay processing.
Still need to simplify deferred recipient handling.
-20051210
+20051212
Bugfix: after a failed TLS session, the 20051210 SMTP client
code cleanup broke sessions with backup servers, causing the
was Ralf Hildebrandt, detectives Victor Duchovni and Wietse.
File: smtp/smtp_proto.c.
+20051213
+
+ Bugfix: *SQL, proxy and LDAP map types were not defined in
+ user-land commands such as postqueue. Leandro Santi. File:
+ postqueue/postqueue.c.
+
+20051212-14
+
+ Server-side plug-in interface for SASL authentication. This
+ uses Cyrus SASL by default, so nothing has changed except
+ error messages may be more informative. Files:
+ smtpd/smtpd_sasl_proto.c smtpd/smtpd_sasl_glue.c,
+ xsasl/xsasl_server.[hc], xsasl/cyrus_server.[hc]
+ xsasl/cyrus_strerror.c, xsasl/cyrus_log.c, xsasl/cyrus_security.c.
+
+20051215
+
+ Portability: IRIX 6.5.28 defines sa_len as a macro, so it
+ can't be used as a variable identifier. Zach McDanel. Files:
+ dns/dns_rr_to_sa.c, smtpd/smtpd_peer.c, qmqpd/qmqpd_peer.c.
+
+20051216
+
+ Cleanup: removed some scar tissue that was introduced with
+ server-side SASL plug-in support. Files: smtpd_sasl_proto.c,
+ smtpd_sasl_glue.c.
+
+ Client-side plug-in interface for SASL authentication. This
+ uses Cyrus SASL by default, so nothing has changed except
+ error messages may be more informative. Files: smtp_sasl_glue.c,
+ xsasl/xsasl_client.[hc], xsasl/cyrus_client.[hc].
+
+20051217
+
+ Bugfix: when a SASL client password is required by a specific
+ server, defer delivery when no server-announced mechanism
+ survives the smtp_sasl_mechanism_filter, instead of ignoring
+ the SASL announcement and trying to deliver the mail over
+ an unauthenticated connection and risking that mail will
+ be rejected. File: smtp/smtp_sasl_proto.c, smtp/smtp_proto.c.
+
+ Portability: zero the "struct msg" just in case. Both purify
+ (Linux) and valgrind (FreeBSD) complain about uninitialized
+ bits. Files: util/unix_{send,recv}_fd.c.
+
+20051219
+
+ Cleanup: generic smtpd_sasl_path, smtp_sasl_path and
+ lmtp_sasl_path configuration parameters; simplified the
+ SASL plug-in API, and made initial provisions for SASL
+ session encryption. Files: xsasl/*.[hc].
+
+ Feature: "postconf -a" lists the available SASL server
+ plug-in types, and "postconf -A" does the same for the
+ client. Files: postconf.c, xsasl_{client,server}.c.
+
+ Feature: new SMTPD policy attributes "encryption_protocol",
+ "encryption_cypher" and "encryption_keysize", to distinguish
+ plaintext from encrypted connections.
+
Open problems:
+ Reject numeric domains only when strict envelope syntax is
+ turned on.
+
"postsuper -r" no longer resets the message arrival time,
because pickup(8) no longer overrides queue file time stamp
information. This can be a problem when mail "on hold" is
SHELL = /bin/sh
WARN = -Wmissing-prototypes -Wformat
OPTS = 'CC=$(CC)'
-DIRS = src/util src/global src/dns src/tls src/master src/postfix src/smtpstone \
+DIRS = src/util src/global src/dns src/tls src/xsasl src/master src/postfix src/smtpstone \
src/sendmail src/error src/pickup src/cleanup src/smtpd src/local \
src/trivial-rewrite src/qmgr src/oqmgr src/smtp src/bounce \
src/pipe src/showq src/postalias src/postcat src/postconf src/postdrop \
People who go to the trouble of installing Postfix may have the expectation
that Postfix is more secure than some other mailers. The Cyrus SASL library is
-a lot of code. With SASL authentication enabled in the Postfix SMTP client and
-SMTP server, Postfix becomes as secure as other mail systems that use the Cyrus
-SASL library.
+a lot of code. With this, Postfix becomes as secure as other mail systems that
+use the Cyrus SASL library.
H\bHo\bow\bw P\bPo\bos\bst\btf\bfi\bix\bx u\bus\bse\bes\bs S\bSA\bAS\bSL\bL a\bau\but\bth\bhe\ben\bnt\bti\bic\bca\bat\bti\bio\bon\bn i\bin\bnf\bfo\bor\brm\bma\bat\bti\bio\bon\bn
access via the permit_sasl_authenticated UCE restriction.
When sending mail, Postfix can look up the server hostname or destination
-domain (the address right-hand part) in a table, and if a username/password is
-found, it will use that username and password to authenticate to the server.
+domain (the address right-hand part) in a Postfix SASL password table, and if a
+username/password is found, it will use that username and password to
+authenticate to the server. And as of version 2.3, Postfix can be configured to
+search its SASL password table by the sender email address.
This document covers the following topics:
* What SASL versions are supported
- * Building the SASL library
- * Building Postfix with SASL authentication support
+ * Building the Cyrus SASL library
+ * Building Postfix with Cyrus SASL support
* Enabling SASL authentication in the Postfix SMTP server
* Testing SASL authentication in the Postfix SMTP server
* Trouble shooting the SASL internals
W\bWh\bha\bat\bt S\bSA\bAS\bSL\bL v\bve\ber\brs\bsi\bio\bon\bns\bs a\bar\bre\be s\bsu\bup\bpp\bpo\bor\brt\bte\bed\bd
-Postfix+SASL 1.5.5 was seen working on RedHat 6.1 (pwcheck_method set to shadow
-or sasldb), Solaris 2.7 (pwcheck_method set to shadow or sasldb), and FreeBSD
-3.4 (pwcheck_method set to sasldb). On RedHat 6.1, SASL 1.5.5 insisted on write
-access to /etc/sasldb. 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.
+This document describes Postfix with Cyrus SASL version 1 and Cyrus SASL
+version 2. Postfix version 2.3 introduces has a plug-in mechanism for other
+SASL implementations. Support for other implementations is currently not part
+of the Postfix distribution and will be described elsewhere.
-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 use the auto_transition feature, or if you use an authentication
-mechanism such as OTP (one-time passwords) that needs to update secrets in the
-database.
-
-B\bBu\bui\bil\bld\bdi\bin\bng\bg t\bth\bhe\be S\bSA\bAS\bSL\bL l\bli\bib\bbr\bra\bar\bry\by
+B\bBu\bui\bil\bld\bdi\bin\bng\bg t\bth\bhe\be C\bCy\byr\bru\bus\bs S\bSA\bAS\bSL\bL l\bli\bib\bbr\bra\bar\bry\by
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/.
+ 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 for version 1.5.5 or /usr/
SASL LOGIN authentication method. To enable this authentication method, specify
``./configure --enable-login''.
-B\bBu\bui\bil\bld\bdi\bin\bng\bg P\bPo\bos\bst\btf\bfi\bix\bx w\bwi\bit\bth\bh S\bSA\bAS\bSL\bL a\bau\but\bth\bhe\ben\bnt\bti\bic\bca\bat\bti\bio\bon\bn s\bsu\bup\bpp\bpo\bor\brt\bt
+B\bBu\bui\bil\bld\bdi\bin\bng\bg P\bPo\bos\bst\btf\bfi\bix\bx w\bwi\bit\bth\bh C\bCy\byr\bru\bus\bs S\bSA\bAS\bSL\bL s\bsu\bup\bpp\bpo\bor\brt\bt
To build Postfix with SASL authentication support, the following assumes that
the Cyrus SASL include files are in /usr/local/include, and that the Cyrus SASL
On some systems this generates the necessary Makefile definitions:
-(for SASL version 1.5.5):
+(for Cyrus SASL 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 -lsasl"
+ % make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include" AUXLIBS="-L/usr/local/lib -lsasl"
-(for SASL version 2.1.1):
+(for Cyrus SASL 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 -lsasl2"
+ % make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -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 SASL version 1.5.5):
+(for Cyrus SASL 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"
+ % make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include" AUXLIBS="-L/usr/local/lib \
+ -R/usr/local/lib -lsasl"
-(for SASL version 2.1.1):
+(for Cyrus SASL 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"
+ % make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include/sasl" AUXLIBS="-L/usr/local/lib \
+ -R/usr/local/lib -lsasl2"
E\bEn\bna\bab\bbl\bli\bin\bng\bg S\bSA\bAS\bSL\bL a\bau\but\bth\bhe\ben\bnt\bti\bic\bca\bat\bti\bio\bon\bn i\bin\bn t\bth\bhe\be P\bPo\bos\bst\btf\bfi\bix\bx S\bSM\bMT\bTP\bP s\bse\ber\brv\bve\ber\br
Note: the SASL login names will be shared with the entire world.
-In /usr/local/lib/sasl/smtpd.conf (SASL version 1.5.5) or /usr/local/lib/sasl2/
-smtpd.conf (SASL version 2.1.1) you need to specify how the server should
-validate client passwords.
+In /usr/local/lib/sasl/smtpd.conf (Cyrus SASL version 1.5.5) or /usr/local/lib/
+sasl2/smtpd.conf (Cyrus SASL version 2.1.1) you need to specify how the server
+should validate client passwords.
Note: some Postfix distributions are modified and look for the smtpd.conf file
in /etc/postfix.
-Note: some Cyrus SASL distributions are modified and look for the smtpd.conf
-file in /etc/sasl2.
+Note: some Cyrus SASL distributions look for the smtpd.conf file in /etc/sasl2.
-In order to authenticate against the UNIX password database, try:
+ * To authenticate against the UNIX password database, try:
-(SASL version 1.5.5)
+ (Cyrus SASL version 1.5.5)
- /usr/local/lib/sasl/smtpd.conf:
- pwcheck_method: pwcheck
+ /usr/local/lib/sasl/smtpd.conf:
+ pwcheck_method: pwcheck
-(SASL version 2.1.1)
+ (Cyrus SASL version 2.1.1)
- /usr/local/lib/sasl2/smtpd.conf:
- pwcheck_method: pwcheck
+ /usr/local/lib/sasl2/smtpd.conf:
+ pwcheck_method: pwcheck
-The name of the file in /usr/local/lib/sasl (SASL version 1.5.5) or /usr/local/
-lib/sasl2 (SASL version 2.1.1) used by the SASL library for configuration can
-be set with:
+ The name of the file in /usr/local/lib/sasl (Cyrus SASL version 1.5.5) or /
+ usr/local/lib/sasl2 (Cyrus SASL version 2.1.1) used by the SASL library for
+ configuration can be set with:
- /etc/postfix/main.cf:
- smtpd_sasl_application_name = smtpd
+ /etc/postfix/main.cf:
+ smtpd_sasl_application_name = smtpd
+
+ The pwcheck daemon is contained in the cyrus-sasl source tarball.
+
+ IMPORTANT: postfix processes need to have group read+execute permission for
+ the /var/pwcheck directory, otherwise authentication attempts will fail.
+
+ * Alternately, in Cyrus SASL 1.5.26 and later (including 2.1.1), try:
+
+ (Cyrus SASL version 1.5.26)
+
+ /usr/local/lib/sasl/smtpd.conf:
+ pwcheck_method: saslauthd
+
+ (Cyrus SASL version 2.1.1)
-The pwcheck daemon is contained in the cyrus-sasl source tarball.
+ /usr/local/lib/sasl2/smtpd.conf:
+ pwcheck_method: saslauthd
-IMPORTANT: postfix processes need to have group read+execute permission for the
-/var/pwcheck directory, otherwise authentication attempts will fail.
+ 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. To use PAM, start saslauthd with "-
+ a pam".
-Alternately, in SASL 1.5.26 and later (including 2.1.1), try:
+ * To authenticate against Cyrus SASL's own password database:
-(SASL version 1.5.26)
+ (Cyrus SASL version 1.5.5)
- /usr/local/lib/sasl/smtpd.conf:
- pwcheck_method: saslauthd
+ /usr/local/lib/sasl/smtpd.conf:
+ pwcheck_method: sasldb
-(SASL version 2.1.1)
+ (Cyrus SASL version 2.1.1)
- /usr/local/lib/sasl2/smtpd.conf:
- pwcheck_method: saslauthd
+ /usr/local/lib/sasl2/smtpd.conf:
+ pwcheck_method: auxprop
-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. To use PAM, start saslauthd with "-a pam".
+ This will use the Cyrus 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 have to play games with group
+ access permissions. With the OTP authentication mechanism, the SMTP server
+ also needs WRITE access to /etc/sasldb2 or /etc/sasldb (or the back end SQL
+ database, if used).
-In order to authenticate against SASL's own password database:
+ IMPORTANT: To get sasldb running, make sure that you set the SASL domain
+ (realm) to a fully qualified domain name.
-(SASL version 1.5.5)
+ EXAMPLE:
- /usr/local/lib/sasl/smtpd.conf:
- pwcheck_method: sasldb
+ (Cyrus SASL version 1.5.5)
-(SASL version 2.1.1)
+ % saslpasswd -c -u `postconf -h myhostname` exampleuser
- /usr/local/lib/sasl2/smtpd.conf:
- pwcheck_method: auxprop
+ (Cyrus SASL version 2.1.1)
-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 have to play games with group access permissions. With the OTP
-authentication mechanism, the SMTP server also needs write access to /etc/
-sasldb2 or /etc/sasldb (or the back end SQL database, if used).
+ % saslpasswd2 -c -u `postconf -h myhostname` exampleuser
+
+ You can find out SASL's idea about the realms of the users in sasldb with
+ sasldblistusers (Cyrus SASL version 1.5.5) or sasldblistusers2 (Cyrus SASL
+ version 2.1.1).
+
+ On the Postfix side, you can have only one realm per smtpd instance, and
+ only the users belonging to that realm would be able to authenticate. The
+ Postfix variable smtpd_sasl_local_domain controls the realm used by smtpd:
+
+ /etc/postfix/main.cf:
+ smtpd_sasl_local_domain = $myhostname
IMPORTANT: all users must be able to authenticate using ALL authentication
mechanisms advertised by Postfix, otherwise the negotiation might end up with
mechanisms, such as DIGEST-MD5. This happens because those mechanisms are made
available by other plugins, and the SASL library have no way to know that your
only valid authentication source is PAM. Thus you might need to limit the list
-of mechanisms advertised by Postfix. This is only possible with SASL version
-2.1.1 or later:
-
- /usr/local/lib/sasl2/smtpd.conf:
- mech_list: plain login
-
-For the same reasons you might want to limit the list of plugins used for
-authentication. With SASL version 1.5.5 your only choice is to delete the
-corresponding libraries from /usr/local/lib/sasl. With SASL version 2.1.1:
-
- /usr/local/lib/sasl2/smtpd.conf:
- pwcheck_method: auxprop
- auxprop_plugin: sql
-
-IMPORTANT: To get sasldb running, make sure that you set the SASL domain
-(realm) to a fully qualified domain name.
+of mechanisms advertised by Postfix.
-EXAMPLE:
+ * With older Cyrus SASL versions you remove the corresponding library files
+ from the SASL plug-in directory (and again whenever the system is updated).
-(SASL version 1.5.5)
+ * With Cyrus SASL version 2.1.1 or later:
- % saslpasswd -c -u `postconf -h myhostname` exampleuser
+ /usr/local/lib/sasl2/smtpd.conf:
+ mech_list: plain login
-(SASL version 2.1.1)
-
- % saslpasswd2 -c -u `postconf -h myhostname` exampleuser
+For the same reasons you might want to limit the list of plugins used for
+authentication.
-You can find out SASL's idea about the realms of the users in sasldb with
-sasldblistusers (SASL version 1.5.5) or sasldblistusers2 (SASL version 2.1.1).
+ * With Cyrus SASL version 1.5.5 your only choice is to delete the
+ corresponding library files from the SASL plug-in directory.
-On the Postfix side, you can have only one realm per smtpd instance, and only
-the users belonging to that realm would be able to authenticate. The Postfix
-variable smtpd_sasl_local_domain controls the realm used by smtpd:
+ * With SASL version 2.1.1:
- /etc/postfix/main.cf:
- smtpd_sasl_local_domain = $myhostname
+ /usr/local/lib/sasl2/smtpd.conf:
+ pwcheck_method: auxprop
+ auxprop_plugin: sql
To run software chrooted with SASL support is an interesting exercise. It
probably is not worth the trouble.
[mail.myisp.net] username:password
[mail.myisp.net]:submission username:password
+Postfix version 2.3 supports-per-sender SASL password information. To search
+the Postfix SASL password by sender before it searches by destination, specify:
+
+ /etc/postfix/main.cf:
+ smtp_sender_dependent_authentication = yes
+ smtp_sasl_auth_enable = yes
+ smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
+
+ /etc/postfix/sasl_passwd:
+ user@example.com username:password
+ bar.com username
+ [mail.myisp.net] username:password
+ [mail.myisp.net]:submission username:password
+
Note: some SMTP servers support PLAIN or LOGIN authentication only. By default,
the Postfix SMTP client does not use authentication methods that send plaintext
passwords, and defers delivery with the following error message:
plaintext authentication specify, for example:
/etc/postfix/main.cf:
- smtp_sasl_security_options =
+ smtp_sasl_security_options = noanonymous
-The SASL client password file is opened before the SMTP server enters the
-optional chroot jail, so you can keep the file in /etc/postfix.
+The Postfix SASL client password file is opened before the SMTP server enters
+the optional chroot jail, so you can keep the file in /etc/postfix.
Note: Some SMTP servers support authentication mechanisms that, although
available on the client system, may not in practice work or possess the
appropriate credentials to authenticate to the server. It is possible via the
smtp_sasl_mechanism_filter parameter to further restrict the list of server
-mechanisms that the smtp(8) client will take into consideration.
+mechanisms that the smtp(8) client will take into consideration:
+
+ /etc/postfix/main.cf:
+ smtp_sasl_mechanism_filter = !gssapi, !external, static:all
+
+In the above example, Postfix will decline to use mechanisms that require
+special infrastructure such as Kerberos.
The Postfix SMTP client is backwards compatible with SMTP servers that use the
non-standard "AUTH=method..." syntax in response to the EHLO command; there is
* Postfix SASL support was originally implemented by Till Franke of SuSE
Rhein/Main AG.
* Wietse trimmed down the code to only the bare necessities.
- * Support for SASL version 2 was contributed by Jason Hoos.
+ * Support for Cyrus SASL version 2 was contributed by Jason Hoos.
* Liviu Daia added smtpd_sasl_application_name, split
reject_sender_login_mismatch into
reject_authenticated_sender_login_mismatch and
reject_unauthenticated_sender_login_mismatch, and revised the docs.
+ * Wietse made another iteration through the code to add plug-in support for
+ multiple implementations.
client_name=another.domain.tld
reverse_client_name=another.domain.tld
instance=123.456.7
+ P\bPo\bos\bst\btf\bfi\bix\bx v\bve\ber\brs\bsi\bio\bon\bn 2\b2.\b.2\b2 a\ban\bnd\bd l\bla\bat\bte\ber\br:\b:
sasl_method=plain
sasl_username=you
sasl_sender=
+ size=12345
ccert_subject=solaris9.porcupine.org
ccert_issuer=Wietse Venema
ccert_fingerprint=C2:9D:F4:87:71:73:73:D9:18:E7:C2:F3:C1:DA:6E:04
- size=12345
+ P\bPo\bos\bst\btf\bfi\bix\bx v\bve\ber\brs\bsi\bio\bon\bn 2\b2.\b.3\b3 a\ban\bnd\bd l\bla\bat\bte\ber\br:\b:
+ encryption_protocol=TLSv1/SSLv3
+ encryption_cipher=DHE-RSA-AES256-SHA
+ encryption_keysize=256
[empty line]
Notes:
sends the END-OF-DATA command.
* The "sasl_*" attributes (Postfix 2.2 and later) specify information about
- how the client was authenticated via SASL.
+ how the client was authenticated via SASL. These attributes are empty in
+ case of no SASL authentication.
* The "ccert_*" attributes (Postfix 2.2 and later) specify information about
- how the client was authenticated via TLS.
+ how the client was authenticated via TLS. These attributes are empty in
+ case of no certificate authentication.
+
+ * The "encryption_*" attributes (Postfix 2.3 and later) specify information
+ about how the connection is encrypted. With plaintext connections the
+ protocol and cypher attributes are empty and the keysize is zero.
The following is specific to SMTPD delegated policy requests:
If you upgrade from Postfix 2.1 or earlier, read RELEASE_NOTES-2.2
before proceeding.
+Incompatibility with snapshot 20051220
+======================================
+
+The Postfix-with-Cyrus-SASL build procedure has changed. You now
+need to specify -DUSE_CYRUS_SASL in addition to -DUSE_SASL_AUTH or
+else you end up without any Cyrus SASL support. The error messages
+are:
+
+ unsupported SASL server implementation: cyrus
+ unsupported SASL client implementation: cyrus
+
+Major changes with snapshot 20051220
+====================================
+
+Plug-in support for SASL authentication in the SMTP server and in
+the SMTP+LMTP client. With this, Postfix can support multiple SASL
+implementations without source code patches. Some distributors may
+even make SASL support a run-time linking option, just like they
+do with Postfix lookup tables.
+
+Hints and tips for plug-in developers are in the xsasl/README file.
+
+For backwards compatibility the default plug-in type is Cyrus SASL,
+so everything should behave like it did before. Some error messages
+are slightly different, but these are generally improvements.
+
+The "postconf -a" command shows what plug-in implementations are
+available for the SMTP server, and "postconf -A" does the same for
+the SMTP+LMTP client. Plug-in implementations are selected with
+the smtpd_sasl_type, smtp_sasl_type and lmtp_sasl_type configuration
+parameters.
+
+Other new configuration parameters are smtpd_sasl_path, smtp_sasl_path
+and lmtp_sasl_path. These are better left alone; they are introduced
+for the convenience of other SASL implementations.
+
Incompatibility with snapshot 20051208
======================================
<h2>WARNING</h2>
-<p> People who go to the trouble of installing Postfix may have
-the expectation that Postfix is more secure than some other mailers.
-The Cyrus SASL library is a lot of code. With SASL authentication
-enabled in the Postfix SMTP client and SMTP server, Postfix becomes
+<p> People who go to the trouble of installing Postfix may have the
+expectation that Postfix is more secure than some other mailers.
+The Cyrus SASL library is a lot of code. With this, Postfix becomes
as secure as other mail systems that use the Cyrus SASL library.
</p>
UCE restriction. </p>
<p> When sending mail, Postfix can look up the server hostname or
-destination domain (the address right-hand part) in a table, and if a
-username/password is found, it will use that username and password
-to authenticate to the server. </p>
+destination domain (the address right-hand part) in a Postfix SASL password
+table, and if a username/password is found, it will use that username
+and password to authenticate to the server. And as of version 2.3,
+Postfix can be configured to search its SASL password table by the
+sender email address. </p>
<p>This document covers the following topics: </p>
<li><a href="#versions">What SASL versions are supported</a>
-<li><a href="#build_sasl">Building the SASL library</a>
+<li><a href="#build_sasl">Building the Cyrus SASL library</a>
-<li><a href="#build_postfix">Building Postfix with SASL authentication
+<li><a href="#build_postfix">Building Postfix with Cyrus SASL
support</a></li>
<li><a href="#server_sasl">Enabling SASL authentication in the
<h2><a name="versions">What SASL versions are supported</a></h2>
-<p> Postfix+SASL 1.5.5 was seen working on RedHat 6.1 (pwcheck_method
-set to shadow or sasldb), Solaris 2.7 (pwcheck_method set to shadow
-or sasldb), and FreeBSD 3.4 (pwcheck_method set to sasldb). On
-RedHat 6.1, SASL 1.5.5 insisted on write access to /etc/sasldb.
-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. </p>
-
-<p> 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 use
-the auto_transition feature, or if you use an authentication
-mechanism such as OTP (one-time passwords) that needs to update
-secrets in the database. </p>
-
-<h2><a name="build_sasl">Building the SASL library</a></h2>
+<p> This document describes Postfix with Cyrus SASL version 1 and
+Cyrus SASL version 2. Postfix version 2.3 introduces has a plug-in
+mechanism for other SASL implementations. Support for other
+implementations is currently not part of the Postfix distribution
+and will be described elsewhere. </p>
+
+<h2><a name="build_sasl">Building the Cyrus SASL library</a></h2>
<p> Postfix appears to work with cyrus-sasl-1.5.5 or cyrus-sasl-2.1.1,
which are available from: </p>
<blockquote>
<pre>
-<a href="ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/">ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/</a>.
+<a href="ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/">ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/</a>
</pre>
</blockquote>
non-standard SASL LOGIN authentication method. To enable this
authentication method, specify ``./configure --enable-login''. </p>
-<h2><a name="build_postfix">Building Postfix with SASL authentication
-support</a></h2>
+<h2><a name="build_postfix">Building Postfix with Cyrus SASL support</a></h2>
<p> To build Postfix with SASL authentication support, the following
assumes that the Cyrus SASL include files are in /usr/local/include,
<dl>
-<dt> (for SASL version 1.5.5):
+<dt> (for Cyrus SASL version 1.5.5):
<dd>
<pre>
% 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"
+% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include" AUXLIBS="-L/usr/local/lib -lsasl"
</pre>
-<dt> (for SASL version 2.1.1):
+<dt> (for Cyrus SASL version 2.1.1):
<dd>
<pre>
% 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"
+% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include/sasl" AUXLIBS="-L/usr/local/lib -lsasl2"
</pre>
</dl>
<dl>
-<dt> (for SASL version 1.5.5):
+<dt> (for Cyrus SASL version 1.5.5):
<dd>
<pre>
% 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"
+% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include" AUXLIBS="-L/usr/local/lib \
+ -R/usr/local/lib -lsasl"
</pre>
-<dt> (for SASL version 2.1.1):
+<dt> (for Cyrus SASL version 2.1.1):
<dd>
<pre>
% 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"
+% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include/sasl" AUXLIBS="-L/usr/local/lib \
+ -R/usr/local/lib -lsasl2"
</pre>
</dl>
<p> Note: the SASL login names will be shared with the entire world.
</p>
-<p> In /usr/local/lib/sasl/smtpd.conf (SASL version 1.5.5) or
-/usr/local/lib/sasl2/smtpd.conf (SASL version 2.1.1) you need to
+<p> In /usr/local/lib/sasl/smtpd.conf (Cyrus SASL version 1.5.5) or
+/usr/local/lib/sasl2/smtpd.conf (Cyrus SASL version 2.1.1) you need to
specify how the server should validate client passwords. </p>
<p> Note: some Postfix distributions are modified and look for
the smtpd.conf file in /etc/postfix. </p>
-<p> Note: some Cyrus SASL distributions are modified and look for
-the smtpd.conf file in /etc/sasl2. </p>
+<p> Note: some Cyrus SASL distributions look for the smtpd.conf
+file in /etc/sasl2. </p>
+
+<ul>
-<p> In order to authenticate against the UNIX password database, try: </p>
+<li> <p> To authenticate against the UNIX password database, try: </p>
<dl>
-<dt> (SASL version 1.5.5)
+<dt> (Cyrus SASL version 1.5.5)
<dd>
<pre>
/usr/local/lib/sasl/smtpd.conf:
</pre>
-<dt> (SASL version 2.1.1)
+<dt> (Cyrus SASL version 2.1.1)
<dd>
<pre>
/usr/local/lib/sasl2/smtpd.conf:
</dl>
-<p> The name of the file in /usr/local/lib/sasl (SASL version 1.5.5)
-or /usr/local/lib/sasl2 (SASL version 2.1.1) used by the SASL
+<p> The name of the file in /usr/local/lib/sasl (Cyrus SASL version
+1.5.5) or /usr/local/lib/sasl2 (Cyrus SASL version 2.1.1) used by
+the SASL
library for configuration can be set with: </p>
<blockquote>
<pre>
/etc/postfix/main.cf:
- <a href="postconf.5.html#smtpd_sasl_application_name">smtpd_sasl_application_name</a> = smtpd
+ smtpd_sasl_application_name = smtpd
</pre>
</blockquote>
permission for the /var/pwcheck directory, otherwise authentication
attempts will fail. </p>
-<p> Alternately, in SASL 1.5.26 and later (including 2.1.1), try: </p>
+<li> <p> Alternately, in Cyrus SASL 1.5.26 and later (including
+2.1.1), try: </p>
<dl>
-<dt> (SASL version 1.5.26)
+<dt> (Cyrus SASL version 1.5.26)
<dd>
<pre>
/usr/local/lib/sasl/smtpd.conf:
pwcheck_method: saslauthd
</pre>
-<dt> (SASL version 2.1.1)
+<dt> (Cyrus SASL version 2.1.1)
<dd>
<pre>
/usr/local/lib/sasl2/smtpd.conf:
can authenticate against PAM and various other sources. To use PAM,
start saslauthd with "-a pam". </p>
-<p> In order to authenticate against SASL's own password database: </p>
+<li> <p> To authenticate against Cyrus SASL's own password database: </p>
<dl>
-<dt> (SASL version 1.5.5)
+<dt> (Cyrus SASL version 1.5.5)
<dd>
<pre>
/usr/local/lib/sasl/smtpd.conf:
pwcheck_method: sasldb
</pre>
-<dt> (SASL version 2.1.1)
+<dt> (Cyrus SASL version 2.1.1)
<dd>
<pre>
/usr/local/lib/sasl2/smtpd.conf:
</dl>
-<p> This will use the SASL password file (default: /etc/sasldb in
+<p> This will use the Cyrus 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 have to play games
with group access permissions. With the OTP authentication mechanism,
-the SMTP server also needs write access to /etc/sasldb2 or /etc/sasldb
+the SMTP server also needs WRITE access to /etc/sasldb2 or /etc/sasldb
(or the back end SQL database, if used). </p>
-<p> IMPORTANT: all users must be able to authenticate using ALL
-authentication mechanisms advertised by Postfix, otherwise the
-negotiation might end up with an unsupported mechanism, and
-authentication would fail. For example if you configure SASL to
-use <i>saslauthd</i> for authentication against PAM (pluggable
-authentication modules), only the PLAIN and LOGIN mechanisms are
-supported and stand a chance to succeed, yet the SASL library would also
-advertise other mechanisms, such as DIGEST-MD5. This happens because
-those mechanisms are made available by other plugins, and the SASL
-library have no way to know that your only valid authentication source
-is PAM. Thus you might need to limit the list of mechanisms advertised
-by Postfix. This is only possible with SASL version 2.1.1 or later:
-</p>
-
-<blockquote>
-<pre>
-/usr/local/lib/sasl2/smtpd.conf:
- mech_list: plain login
-</pre>
-</blockquote>
-
-<p> For the same reasons you might want to limit the list of plugins
-used for authentication. With SASL version 1.5.5 your only choice is to
-delete the corresponding libraries from /usr/local/lib/sasl. With SASL
-version 2.1.1: </p>
-
-<blockquote>
-<pre>
-/usr/local/lib/sasl2/smtpd.conf:
- pwcheck_method: auxprop
- auxprop_plugin: sql
-</pre>
-</blockquote>
-
<p> IMPORTANT: To get sasldb running, make sure that you set the SASL
domain (realm) to a fully qualified domain name. </p>
<p> EXAMPLE: </p>
<dl>
-<dt> (SASL version 1.5.5)
+<dt> (Cyrus SASL version 1.5.5)
<dd>
<pre>
% saslpasswd -c -u `postconf -h <a href="postconf.5.html#myhostname">myhostname</a>` exampleuser
</pre>
-<dt> (SASL version 2.1.1)
+<dt> (Cyrus SASL version 2.1.1)
<dd>
<pre>
% saslpasswd2 -c -u `postconf -h <a href="postconf.5.html#myhostname">myhostname</a>` exampleuser
</dl>
<p> You can find out SASL's idea about the realms of the users
-in sasldb with <i>sasldblistusers</i> (SASL version 1.5.5) or
-<i>sasldblistusers2</i> (SASL version 2.1.1). </p>
+in sasldb with <i>sasldblistusers</i> (Cyrus SASL version 1.5.5) or
+<i>sasldblistusers2</i> (Cyrus SASL version 2.1.1). </p>
<p> On the Postfix side, you can have only one realm per smtpd
instance, and only the users belonging to that realm would be able to
</pre>
</blockquote>
+</ul>
+
+<p> IMPORTANT: all users must be able to authenticate using ALL
+authentication mechanisms advertised by Postfix, otherwise the
+negotiation might end up with an unsupported mechanism, and
+authentication would fail. For example if you configure SASL to
+use <i>saslauthd</i> for authentication against PAM (pluggable
+authentication modules), only the PLAIN and LOGIN mechanisms are
+supported and stand a chance to succeed, yet the SASL library would also
+advertise other mechanisms, such as DIGEST-MD5. This happens because
+those mechanisms are made available by other plugins, and the SASL
+library have no way to know that your only valid authentication source
+is PAM. Thus you might need to limit the list of mechanisms advertised
+by Postfix. </p>
+
+<ul>
+
+<li> <p> With older Cyrus SASL versions you remove the corresponding
+library files from the SASL plug-in directory (and again whenever
+the system is updated). </p>
+
+<li> <p> With Cyrus SASL version 2.1.1 or later: </p>
+
+<blockquote>
+<pre>
+/usr/local/lib/sasl2/smtpd.conf:
+ mech_list: plain login
+</pre>
+</blockquote>
+
+</ul>
+
+<p> For the same reasons you might want to limit the list of plugins
+used for authentication. </p>
+
+<ul>
+
+<li> <p> With Cyrus SASL version 1.5.5 your only choice is to
+delete the corresponding library files from the SASL plug-in
+directory. </p>
+
+<li> <p> With SASL version 2.1.1: </p>
+
+<blockquote>
+<pre>
+/usr/local/lib/sasl2/smtpd.conf:
+ pwcheck_method: auxprop
+ auxprop_plugin: sql
+</pre>
+</blockquote>
+
+</ul>
+
<p> To run software chrooted with SASL support is an interesting
exercise. It probably is not worth the trouble. </p>
</pre>
</blockquote>
+<p> Postfix version 2.3 supports-per-sender SASL password
+information. To search the Postfix SASL password by sender
+before it searches by destination, specify: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ <a href="postconf.5.html#smtp_sender_dependent_authentication">smtp_sender_dependent_authentication</a> = yes
+ <a href="postconf.5.html#smtp_sasl_auth_enable">smtp_sasl_auth_enable</a> = yes
+ <a href="postconf.5.html#smtp_sasl_password_maps">smtp_sasl_password_maps</a> = hash:/etc/postfix/sasl_passwd
+
+/etc/postfix/sasl_passwd:
+ user@example.com username:password
+ bar.com username
+ [mail.myisp.net] username:password
+ [mail.myisp.net]:submission username:password
+</pre>
+</blockquote>
+
<p> Note: some SMTP servers support PLAIN or LOGIN authentication only.
By default, the Postfix SMTP client does not use authentication
methods that send plaintext passwords, and defers delivery with
<blockquote>
<pre>
/etc/postfix/main.cf:
- <a href="postconf.5.html#smtp_sasl_security_options">smtp_sasl_security_options</a> =
+ <a href="postconf.5.html#smtp_sasl_security_options">smtp_sasl_security_options</a> = noanonymous
</pre>
</blockquote>
-<p> The SASL client password file is opened before the SMTP server
+<p> The Postfix SASL client password file is opened before the SMTP server
enters the optional chroot jail, so you can keep the file in
/etc/postfix. </p>
possess the appropriate credentials to authenticate to the server. It
is possible via the <a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a> parameter to further
restrict the list of server mechanisms that the <a href="smtp.8.html">smtp(8)</a> client will take
-into consideration. </p>
+into consideration: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ <a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a> = !gssapi, !external, static:all
+</pre>
+</blockquote>
+
+<p> In the above example, Postfix will decline to use mechanisms
+that require special infrastructure such as Kerberos. </p>
<p> The Postfix SMTP client is backwards compatible with SMTP
servers that use the non-standard "AUTH=method..." syntax in response
<li> Wietse trimmed down the code to only the bare necessities.
-<li> Support for SASL version 2 was contributed by Jason Hoos.
+<li> Support for Cyrus SASL version 2 was contributed by Jason Hoos.
-<li> Liviu Daia added <a href="postconf.5.html#smtpd_sasl_application_name">smtpd_sasl_application_name</a>, split
+<li> Liviu Daia added smtpd_sasl_application_name, split
<a href="postconf.5.html#reject_sender_login_mismatch">reject_sender_login_mismatch</a> into
<a href="postconf.5.html#reject_authenticated_sender_login_mismatch">reject_authenticated_sender_login_mismatch</a> and
<a href="postconf.5.html#reject_unauthenticated_sender_login_mismatch">reject_unauthenticated_sender_login_mismatch</a>, and revised the docs.
+<li> Wietse made another iteration through the code to add
+plug-in support for multiple implementations.
+
</ul>
</body>
client_name=another.domain.tld
reverse_client_name=another.domain.tld
instance=123.456.7
+<b>Postfix version 2.2 and later:</b>
sasl_method=plain
sasl_username=you
sasl_sender=
+size=12345
ccert_subject=solaris9.porcupine.org
ccert_issuer=Wietse Venema
ccert_fingerprint=C2:9D:F4:87:71:73:73:D9:18:E7:C2:F3:C1:DA:6E:04
-size=12345
+<b>Postfix version 2.3 and later:</b>
+encryption_protocol=TLSv1/SSLv3
+encryption_cipher=DHE-RSA-AES256-SHA
+encryption_keysize=256
[empty line]
</pre>
</blockquote>
<li> <p> The "sasl_*" attributes (Postfix 2.2 and later) specify
information about how the client was authenticated via SASL.
+ These attributes are empty in case of no SASL authentication.
</p>
<li> <p> The "ccert_*" attributes (Postfix 2.2 and later) specify
information about how the client was authenticated via TLS.
+ These attributes are empty in case of no certificate authentication.
</p>
+ <li> <p> The "encryption_*" attributes (Postfix 2.3 and later)
+ specify information about how the connection is encrypted. With
+ plaintext connections the protocol and cypher attributes are
+ empty and the keysize is zero. </p>
+
</ul>
<p> The following is specific to SMTPD delegated policy requests:
postconf - Postfix configuration utility
<b>SYNOPSIS</b>
- <b>postconf</b> [<b>-dhmlnv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>parameter ...</i>]
+ <b>postconf</b> [<b>-dhnv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>parameter ...</i>]
+
+ <b>postconf</b> [<b>-aAmlv</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>]
<b>postconf</b> [<b>-ev</b>] [<b>-c</b> <i>config</i><b>_</b><i>dir</i>] [<i>parameter=value ...</i>]
Options:
+ <b>-a</b> List the available SASL server plug-in types. The
+ SASL plug-in type is selected with the
+ <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b> configuration parameter.
+
+ This feature is available with Postfix 2.3 and
+ later.
+
+ <b>-A</b> List the available SASL client plug-in types. The
+ SASL plug-in type is selected with the
+ <b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a></b> or <b><a href="postconf.5.html#lmtp_sasl_type">lmtp_sasl_type</a></b> configuration
+ parameters.
+
+ This feature is available with Postfix 2.3 and
+ later.
+
<b>-b</b> [<i>template</i><b>_</b><i>file</i>]
Display the message text that appears at the begin-
- ning of delivery status notification (DSN) mes-
- sages, with $<b>name</b> expressions replaced by actual
- values. To override the built-in message text,
- specify a template file at the end of the command
- line, or specify a template file in main.cf with
- the <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a></b> parameter. To force
- selection of the built-in message text templates,
- specify an empty template file name (in shell lan-
+ ning of delivery status notification (DSN) mes-
+ sages, with $<b>name</b> expressions replaced by actual
+ values. To override the built-in message text,
+ specify a template file at the end of the command
+ line, or specify a template file in main.cf with
+ the <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a></b> parameter. To force
+ selection of the built-in message text templates,
+ specify an empty template file name (in shell lan-
guage: "").
- This feature is available with Postfix 2.3 and
+ This feature is available with Postfix 2.3 and
later.
<b>-c</b> <i>config</i><b>_</b><i>dir</i>
- The <b>main.cf</b> configuration file is in the named
+ The <b>main.cf</b> configuration file is in the named
directory instead of the default configuration
directory.
- <b>-d</b> Print default parameter settings instead of actual
+ <b>-d</b> Print default parameter settings instead of actual
settings.
- <b>-e</b> Edit the <b>main.cf</b> configuration file. The file is
+ <b>-e</b> Edit the <b>main.cf</b> configuration file. The file is
copied to a temporary file then renamed into place.
- Parameters and values are specified on the command
- line. Use quotes in order to protect shell
+ Parameters and values are specified on the command
+ line. Use quotes in order to protect shell
metacharacters and whitespace.
- <b>-h</b> Show parameter values only, not the ``name = ''
+ <b>-h</b> Show parameter values only, not the ``name = ''
label that normally precedes the value.
- <b>-l</b> List the names of all supported mailbox locking
+ <b>-l</b> List the names of all supported mailbox locking
methods. Postfix supports the following methods:
- <b>flock</b> A kernel-based advisory locking method for
- local files only. This locking method is
- available on systems with a BSD compatible
+ <b>flock</b> A kernel-based advisory locking method for
+ local files only. This locking method is
+ available on systems with a BSD compatible
library.
- <b>fcntl</b> A kernel-based advisory locking method for
+ <b>fcntl</b> A kernel-based advisory locking method for
local and remote files.
<b>dotlock</b>
- An application-level locking method. An
- application locks a file named <i>filename</i> by
- creating a file named <i>filename</i><b>.lock</b>. The
- application is expected to remove its own
- lock file, as well as stale lock files that
+ An application-level locking method. An
+ application locks a file named <i>filename</i> by
+ creating a file named <i>filename</i><b>.lock</b>. The
+ application is expected to remove its own
+ lock file, as well as stale lock files that
were left behind after abnormal termination.
<b>-m</b> List the names of all supported lookup table types.
- In Postfix configuration files, lookup tables are
- specified as <i>type</i><b>:</b><i>name</i>, where <i>type</i> is one of the
- types listed below. The table <i>name</i> syntax depends
- on the lookup table type as described in the <a href="DATABASE_README.html">DATA</a>-
+ In Postfix configuration files, lookup tables are
+ specified as <i>type</i><b>:</b><i>name</i>, where <i>type</i> is one of the
+ types listed below. The table <i>name</i> syntax depends
+ on the lookup table type as described in the <a href="DATABASE_README.html">DATA</a>-
<a href="DATABASE_README.html">BASE_README</a> document.
- <b>btree</b> A sorted, balanced tree structure. This is
+ <b>btree</b> A sorted, balanced tree structure. This is
available on systems with support for Berke-
ley DB databases.
- <b>cdb</b> A read-optimized structure with no support
- for incremental updates. This is available
+ <b>cdb</b> A read-optimized structure with no support
+ for incremental updates. This is available
on systems with support for CDB databases.
- <b>cidr</b> A table that associates values with Class-
- less Inter-Domain Routing (CIDR) patterns.
+ <b>cidr</b> A table that associates values with Class-
+ less Inter-Domain Routing (CIDR) patterns.
This is described in <a href="cidr_table.5.html"><b>cidr_table</b>(5)</a>.
<b>dbm</b> An indexed file type based on hashing. This
<b>environ</b>
The UNIX process environment array. The
- lookup key is the variable name. Originally
- implemented for testing, someone may find
+ lookup key is the variable name. Originally
+ implemented for testing, someone may find
this useful someday.
<b>hash</b> An indexed file type based on hashing. This
- is available on systems with support for
+ is available on systems with support for
Berkeley DB databases.
<b>ldap</b> (read-only)
- Perform lookups using the LDAP protocol.
+ Perform lookups using the LDAP protocol.
This is described in <a href="ldap_table.5.html"><b>ldap_table</b>(5)</a>.
<b>mysql</b> (read-only)
- Perform lookups using the MYSQL protocol.
+ Perform lookups using the MYSQL protocol.
This is described in <a href="mysql_table.5.html"><b>mysql_table</b>(5)</a>.
<b>pcre</b> (read-only)
A lookup table based on Perl Compatible Reg-
- ular Expressions. The file format is
+ ular Expressions. The file format is
described in <a href="pcre_table.5.html"><b>pcre_table</b>(5)</a>.
<b>pgsql</b> (read-only)
- Perform lookups using the PostgreSQL proto-
+ Perform lookups using the PostgreSQL proto-
col. This is described in <a href="pgsql_table.5.html"><b>pgsql_table</b>(5)</a>.
<b>proxy</b> (read-only)
- A lookup table that is implemented via the
- Postfix <a href="proxymap.8.html"><b>proxymap</b>(8)</a> service. The table name
+ A lookup table that is implemented via the
+ Postfix <a href="proxymap.8.html"><b>proxymap</b>(8)</a> service. The table name
syntax is <i>type</i><b>:</b><i>name</i>.
<b>regexp</b> (read-only)
A lookup table based on regular expressions.
- The file format is described in <a href="regexp_table.5.html"><b>regexp_ta-</b></a>
+ The file format is described in <a href="regexp_table.5.html"><b>regexp_ta-</b></a>
<a href="regexp_table.5.html"><b>ble</b>(5)</a>.
<b>sdbm</b> An indexed file type based on hashing. This
- is available on systems with support for
+ is available on systems with support for
SDBM databases.
<b>static</b> (read-only)
- A table that always returns its name as
- lookup result. For example, <b>static:foobar</b>
- always returns the string <b>foobar</b> as lookup
+ A table that always returns its name as
+ lookup result. For example, <b>static:foobar</b>
+ always returns the string <b>foobar</b> as lookup
result.
<b>tcp</b> (read-only)
Perform lookups using a simple request-reply
- protocol that is described in <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.
- This feature is not included with Postfix
+ protocol that is described in <a href="tcp_table.5.html"><b>tcp_table</b>(5)</a>.
+ This feature is not included with Postfix
2.2.
<b>unix</b> (read-only)
- A limited way to query the UNIX authentica-
+ A limited way to query the UNIX authentica-
tion database. The following tables are
implemented:
<b>unix:passwd.byname</b>
- The table is the UNIX password data-
- base. The key is a login name. The
- result is a password file entry in
+ The table is the UNIX password data-
+ base. The key is a login name. The
+ result is a password file entry in
<b>passwd</b>(5) format.
<b>unix:group.byname</b>
The table is the UNIX group database.
- The key is a group name. The result
- is a group file entry in <b>group</b>(5)
+ The key is a group name. The result
+ is a group file entry in <b>group</b>(5)
format.
- Other table types may exist depending on how Post-
+ Other table types may exist depending on how Post-
fix was built.
<b>-n</b> Print parameter settings that are not left at their
<b>-t</b> [<i>template</i><b>_</b><i>file</i>]
Display the templates for delivery status notifica-
- tion (DSN) messages. To override the built-in tem-
- plates, specify a template file at the end of the
+ tion (DSN) messages. To override the built-in tem-
+ plates, specify a template file at the end of the
command line, or specify a template file in main.cf
- with the <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a></b> parameter. To force
- selection of the built-in templates, specify an
+ with the <b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a></b> parameter. To force
+ selection of the built-in templates, specify an
empty template file name (in shell language: "").
- This feature is available with Postfix 2.3 and
+ This feature is available with Postfix 2.3 and
later.
<b>-v</b> Enable verbose logging for debugging purposes. Mul-
- tiple <b>-v</b> options make the software increasingly
+ tiple <b>-v</b> options make the software increasingly
verbose.
<b>DIAGNOSTICS</b>
Directory with Postfix configuration files.
<b>CONFIGURATION PARAMETERS</b>
- The following <b>main.cf</b> parameters are especially relevant
+ The following <b>main.cf</b> parameters are especially relevant
to this program.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
<b><a href="postconf.5.html#bounce_template_file">bounce_template_file</a> (empty)</b>
- Pathname of a configuration file with bounce mes-
+ Pathname of a configuration file with bounce mes-
sage templates.
<b>FILES</b>
<a href="DATABASE_README.html">DATABASE_README</a>, Postfix lookup table overview
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
<p>
Optional list of relay hosts for SMTP destinations that can't be
found or that are unreachable. With Postfix 2.3 this parameter
-is renamed to smtp_fallback_relay. </p>
+is renamed to <a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a>. </p>
<p>
By default, mail is returned to the sender when a destination is
<p> Lookup tables, indexed by the remote LMTP server address, with
case insensitive lists of LHLO keywords (pipelining, starttls,
auth, etc.) that the LMTP client will ignore in the LHLO response
-from a remote LMTP server. See lmtp_discard_lhlo_keywords for
+from a remote LMTP server. See <a href="postconf.5.html#lmtp_discard_lhlo_keywords">lmtp_discard_lhlo_keywords</a> for
details. </p>
<p> This feature is available in Postfix 2.3 and later. </p>
<li> <p> Specify the <b>silent-discard</b> pseudo keyword to prevent
this action from being logged. </p>
-<li> <p> Use the lmtp_discard_lhlo_keyword_address_maps feature to
+<li> <p> Use the <a href="postconf.5.html#lmtp_discard_lhlo_keyword_address_maps">lmtp_discard_lhlo_keyword_address_maps</a> feature to
discard LHLO keywords selectively. </p>
</ul>
<pre>
/etc/postfix/master.cf:
- mylmtp ... lmtp -o lmtp_lhlo_name=foo.bar.com
+ mylmtp ... lmtp -o <a href="postconf.5.html#lmtp_lhloname">lmtp_lhlo_name</a>=foo.bar.com
</pre>
<p>
</p>
+</DD>
+
+<DT><b><a name="lmtp_sasl_path">lmtp_sasl_path</a>
+(default: empty)</b></DT><DD>
+
+<p> Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+<b><a href="postconf.5.html#lmtp_sasl_type">lmtp_sasl_type</a></b>. Typically this specifies the name of a
+configuration file or rendez-vous point. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_sasl_security_options">lmtp_sasl_security_options</a>
(default: noplaintext, noanonymous)</b></DT><DD>
-<p>
-What authentication mechanisms the Postfix LMTP client is allowed
-to use. The list of available authentication mechanisms is system
-dependent.
-</p>
+<p> SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL client implementation that is selected
+with <b><a href="postconf.5.html#lmtp_sasl_type">lmtp_sasl_type</a></b>. </p>
+
+<p> The following security features are defined for the <b>cyrus</b>
+client SASL implementation: </p>
<dl>
<p> This feature is available in Postfix 2.3 and later. </p>
+</DD>
+
+<DT><b><a name="lmtp_sasl_type">lmtp_sasl_type</a>
+(default: cyrus)</b></DT><DD>
+
+<p> The SASL plug-in type that the Postfix LMTP client should use
+for authentication. The available types are listed with the
+"<b>postconf -A</b>" command. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="lmtp_send_xforward_command">lmtp_send_xforward_command</a>
</p>
+</DD>
+
+<DT><b><a name="plaintext_session_reject_code">plaintext_session_reject_code</a>
+(default: 450)</b></DT><DD>
+
+<p>
+The numerical Postfix SMTP server response code when a request
+is rejected by the <b><a href="postconf.5.html#reject_plaintext_session">reject_plaintext_session</a></b> restriction.
+</p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="prepend_delivered_header">prepend_delivered_header</a>
destinations, Postfix will try them in the specified order. </p>
<p> To prevent mailer loops between MX hosts and fall-back hosts,
-Postfix version 2.3 and later will not use the smtp_fallback_relay
+Postfix version 2.3 and later will not use the <a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a>
feature for destinations that it is MX host for. </p>
</p>
+</DD>
+
+<DT><b><a name="smtp_sasl_path">smtp_sasl_path</a>
+(default: empty)</b></DT><DD>
+
+<p> Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+<b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a></b>. Typically this specifies the name of a
+configuration file or rendez-vous point. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="smtp_sasl_security_options">smtp_sasl_security_options</a>
(default: noplaintext, noanonymous)</b></DT><DD>
-<p>
-What authentication mechanisms the Postfix SMTP client is allowed
-to use. The list of available authentication mechanisms is system
-dependent.
-</p>
+<p> SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL client implementation that is selected
+with <b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a></b>. </p>
+
+<p> The following security features are defined for the <b>cyrus</b>
+client SASL implementation: </p>
<p>
Specify zero or more of the following:
client uses for TLS encrypted SMTP sessions. </p>
+</DD>
+
+<DT><b><a name="smtp_sasl_type">smtp_sasl_type</a>
+(default: cyrus)</b></DT><DD>
+
+<p> The SASL plug-in type that the Postfix SMTP client should use
+for authentication. The available types are listed with the
+"<b>postconf -A</b>" command. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="smtp_send_xforward_command">smtp_send_xforward_command</a>
response code for rejected requests (default: 550). This feature
is available in Postfix 2.1 and later. </dd>
+<dt><b><a name="reject_plaintext_session">reject_plaintext_session</a></b></dt>
+
+<dd>Reject the request when the connection is not encrypted. This
+restriction should not be used before the client has had a chance
+to negotiate encryption with the AUTH or STARTTLS commands.
+<br>
+The <a href="postconf.5.html#plaintext_session_reject_code">plaintext_session_reject_code</a> parameter specifies the response
+code for rejected requests (default: 450). This feature is available
+in Postfix 2.3 and later. </dd>
+
<dt><b><a name="reject_unauth_pipelining">reject_unauth_pipelining</a></b></dt>
<dd>Reject the request when the client sends SMTP commands ahead
</pre>
+</DD>
+
+<DT><b><a name="smtpd_sasl_path">smtpd_sasl_path</a>
+(default: smtpd)</b></DT><DD>
+
+<p> Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+<b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b>. Typically this specifies the name of a
+configuration file or rendez-vous point. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="smtpd_sasl_security_options">smtpd_sasl_security_options</a>
(default: noanonymous)</b></DT><DD>
+<p> SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL server implementation that is selected
+with <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b>. </p>
+
+<p> The following security features are defined for the <b>cyrus</b>
+server SASL implementation: </p>
+
<p>
Restrict what authentication mechanisms the Postfix SMTP server
will offer to the client. The list of available authentication
server uses for TLS encrypted SMTP sessions. </p>
+</DD>
+
+<DT><b><a name="smtpd_sasl_type">smtpd_sasl_type</a>
+(default: cyrus)</b></DT><DD>
+
+<p> The SASL plug-in type that the Postfix SMTP server should use
+for authentication. The available types are listed with the
+"<b>postconf -a</b>" command. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
</DD>
<DT><b><a name="smtpd_sender_login_maps">smtpd_sender_login_maps</a>
<b>SMTP DESTINATION SYNTAX</b>
SMTP destinations have the following form:
- <i>domainname</i>, <i>domainname</i>:<i>port</i>
+ <i>domainname</i>
+
+ <i>domainname</i>:<i>port</i>
Look up the mail exchangers for the specified
- domain.
+ domain, and connect to the specified port (default:
+ <b>smtp</b>).
- [<i>hostname</i>], [<i>hostname</i>]:<i>port</i>
- Look up the address of the specified host.
+ [<i>hostname</i>]
- [<i>address</i>], [<i>address</i>]:<i>port</i>
- Connect to the host at the specified address. An
- IPv6 address must be formatted as [<b>ipv6</b>:<i>address</i>].
+ [<i>hostname</i>]:<i>port</i>
+ Look up the address(es) of the specified host, and
+ connect to the specified port (default: <b>smtp</b>).
- In all the above cases, when no port is specified, look up
- the port defined as <b>smtp</b> in <b>services</b>(4).
+ [<i>address</i>]
+
+ [<i>address</i>]:<i>port</i>
+ Connect to the host at the specified address, and
+ connect to the specified port (default: <b>smtp</b>). An
+ IPv6 address must be formatted as [<b>ipv6</b>:<i>address</i>].
<b>LMTP DESTINATION SYNTAX</b>
LMTP destinations have the following form:
runs chrooted, an absolute pathname is interpreted
relative to the Postfix queue directory.
- <b>inet</b>:<i>hostname</i>, <b>inet:</b><i>hostname</i>:<i>port</i>
+ <b>inet</b>:<i>hostname</i>
- <b>inet</b>:[<i>address</i>], <b>inet</b>:[<i>address</i>]:<i>port</i>
+ <b>inet:</b><i>hostname</i>:<i>port</i>
+
+ <b>inet</b>:[<i>address</i>]
+
+ <b>inet</b>:[<i>address</i>]:<i>port</i>
Connect to the specified TCP port on the specified
local or remote host. If no port is specified, con-
nect to the port defined as <b>lmtp</b> in <b>services</b>(4).
If no such service is found, the <b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a></b> con-
figuration parameter (default value of 24) will be
- used.
+ used. An IPv6 address must be formatted as
+ [<b>ipv6</b>:<i>address</i>].
<b>SECURITY</b>
- The SMTP+LMTP client is moderately security-sensitive. It
- talks to SMTP or LMTP servers and to DNS servers on the
+ The SMTP+LMTP client is moderately security-sensitive. It
+ talks to SMTP or LMTP servers and to DNS servers on the
network. The SMTP+LMTP client can be run chrooted at fixed
low privilege.
<a href="http://www.faqs.org/rfcs/rfc3463.html">RFC 3463</a> (Enhanced Status Codes)
<b>DIAGNOSTICS</b>
- Problems and transactions are logged to <b>syslogd</b>(8). Cor-
- rupted message files are marked so that the queue manager
+ Problems and transactions are logged to <b>syslogd</b>(8). Cor-
+ rupted message files are marked so that the queue manager
can move them to the <b>corrupt</b> queue for further inspection.
- Depending on the setting of the <b><a href="postconf.5.html#notify_classes">notify_classes</a></b> parameter,
- the postmaster is notified of bounces, protocol problems,
+ Depending on the setting of the <b><a href="postconf.5.html#notify_classes">notify_classes</a></b> parameter,
+ the postmaster is notified of bounces, protocol problems,
and of other trouble.
<b>BUGS</b>
- SMTP and LMTP connection caching does not work with TLS.
- The necessary support for TLS object passivation and re-
- activation does not exist without closing the session,
+ SMTP and LMTP connection caching does not work with TLS.
+ The necessary support for TLS object passivation and re-
+ activation does not exist without closing the session,
which defeats the purpose.
SMTP and LMTP connection caching assumes that SASL creden-
- tials are valid for all destinations that map onto the
+ tials are valid for all destinations that map onto the
same IP address and TCP port.
<b>CONFIGURATION PARAMETERS</b>
- Most smtp_<i>xxx</i> configuration parameters have an lmtp_<i>xxx</i>
- "ghost" parameter for the equivalent LMTP feature. This
+ Before Postfix version 2.3, the LMTP client is a separate
+ program that implements only a subset of the functionality
+ available with SMTP: there is no support for TLS, and con-
+ nections are cached in-process, making it ineffective when
+ the client is used for multiple domains.
+
+ Most smtp_<i>xxx</i> configuration parameters have an lmtp_<i>xxx</i>
+ "ghost" parameter for the equivalent LMTP feature. This
document describes only those LMTP-related parameters that
aren't simply "ghost" parameters.
Changes to <b>main.cf</b> are picked up automatically, as <a href="smtp.8.html"><b>smtp</b>(8)</a>
- processes run for only a limited amount of time. Use the
+ processes run for only a limited amount of time. Use the
command "<b>postfix reload</b>" to speed up a change.
- The text below provides only a parameter summary. See
+ The text below provides only a parameter summary. See
<a href="postconf.5.html"><b>postconf</b>(5)</a> for more details including examples.
<b>COMPATIBILITY CONTROLS</b>
Never send EHLO at the start of an SMTP session.
<b><a href="postconf.5.html#smtp_defer_if_no_mx_address_found">smtp_defer_if_no_mx_address_found</a> (no)</b>
- Defer mail delivery when no MX record resolves to
+ Defer mail delivery when no MX record resolves to
an IP address.
<b><a href="postconf.5.html#smtp_line_length_limit">smtp_line_length_limit</a> (990)</b>
that Postfix will send via SMTP.
<b><a href="postconf.5.html#smtp_pix_workaround_delay_time">smtp_pix_workaround_delay_time</a> (10s)</b>
- How long the Postfix SMTP client pauses before
+ How long the Postfix SMTP client pauses before
sending ".<CR><LF>" in order to work around the PIX
firewall "<CR><LF>.<CR><LF>" bug.
<b><a href="postconf.5.html#smtp_pix_workaround_threshold_time">smtp_pix_workaround_threshold_time</a> (500s)</b>
- How long a message must be queued before the PIX
- firewall "<CR><LF>.<CR><LF>" bug workaround is
+ How long a message must be queued before the PIX
+ firewall "<CR><LF>.<CR><LF>" bug workaround is
turned on.
<b><a href="postconf.5.html#smtp_quote_rfc821_envelope">smtp_quote_rfc821_envelope</a> (yes)</b>
- Quote addresses in SMTP MAIL FROM and RCPT TO com-
+ Quote addresses in SMTP MAIL FROM and RCPT TO com-
mands as required by <a href="http://www.faqs.org/rfcs/rfc821.html">RFC 821</a>.
<b><a href="postconf.5.html#smtp_skip_5xx_greeting">smtp_skip_5xx_greeting</a> (yes)</b>
(go away, do not try again later).
<b><a href="postconf.5.html#smtp_skip_quit_response">smtp_skip_quit_response</a> (yes)</b>
- Do not wait for the response to the SMTP QUIT com-
+ Do not wait for the response to the SMTP QUIT com-
mand.
Available in Postfix version 2.0 and earlier:
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtp_discard_ehlo_keyword_address_maps">smtp_discard_ehlo_keyword_address_maps</a> (empty)</b>
- Lookup tables, indexed by the remote SMTP server
- address, with case insensitive lists of EHLO key-
- words (pipelining, starttls, auth, etc.) that the
+ Lookup tables, indexed by the remote SMTP server
+ address, with case insensitive lists of EHLO key-
+ words (pipelining, starttls, auth, etc.) that the
SMTP client will ignore in the EHLO response from a
remote SMTP server.
<b><a href="postconf.5.html#smtp_discard_ehlo_keywords">smtp_discard_ehlo_keywords</a> (empty)</b>
- A case insensitive list of EHLO keywords (pipelin-
- ing, starttls, auth, etc.) that the SMTP client
+ A case insensitive list of EHLO keywords (pipelin-
+ ing, starttls, auth, etc.) that the SMTP client
will ignore in the EHLO response from a remote SMTP
server.
<b><a href="postconf.5.html#smtp_generic_maps">smtp_generic_maps</a> (empty)</b>
Optional lookup tables that perform address rewrit-
- ing in the SMTP client, typically to transform a
+ ing in the SMTP client, typically to transform a
locally valid address into a globally valid address
when sending mail across the Internet.
Available in Postfix version 2.3 and later:
- <b>lmtp_discard_lhlo_keyword_address_maps (empty)</b>
- Lookup tables, indexed by the remote LMTP server
- address, with case insensitive lists of LHLO key-
- words (pipelining, starttls, auth, etc.) that the
+ <b><a href="postconf.5.html#lmtp_discard_lhlo_keyword_address_maps">lmtp_discard_lhlo_keyword_address_maps</a> (empty)</b>
+ Lookup tables, indexed by the remote LMTP server
+ address, with case insensitive lists of LHLO key-
+ words (pipelining, starttls, auth, etc.) that the
LMTP client will ignore in the LHLO response from a
remote LMTP server.
- <b>lmtp_discard_lhlo_keywords ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
- A case insensitive list of LHLO keywords (pipelin-
- ing, starttls, auth, etc.) that the LMTP client
+ <b><a href="postconf.5.html#lmtp_discard_lhlo_keywords">lmtp_discard_lhlo_keywords</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
+ A case insensitive list of LHLO keywords (pipelin-
+ ing, starttls, auth, etc.) that the LMTP client
will ignore in the LHLO response from a remote LMTP
server.
Available in Postfix version 2.0 and later:
<b><a href="postconf.5.html#disable_mime_output_conversion">disable_mime_output_conversion</a> (no)</b>
- Disable the conversion of 8BITMIME format to 7BIT
+ Disable the conversion of 8BITMIME format to 7BIT
format.
<b><a href="postconf.5.html#mime_boundary_length_limit">mime_boundary_length_limit</a> (2048)</b>
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#smtp_send_xforward_command">smtp_send_xforward_command</a> (no)</b>
- Send the non-standard XFORWARD command when the
- Postfix SMTP server EHLO response announces XFOR-
+ Send the non-standard XFORWARD command when the
+ Postfix SMTP server EHLO response announces XFOR-
WARD support.
<b>SASL AUTHENTICATION CONTROLS</b>
<b><a href="postconf.5.html#smtp_sasl_auth_enable">smtp_sasl_auth_enable</a> (no)</b>
- Enable SASL authentication in the Postfix SMTP
+ Enable SASL authentication in the Postfix SMTP
client.
<b><a href="postconf.5.html#smtp_sasl_password_maps">smtp_sasl_password_maps</a> (empty)</b>
- Optional SMTP client lookup tables with one user-
- name:password entry per remote hostname or domain,
+ Optional SMTP client lookup tables with one user-
+ name:password entry per remote hostname or domain,
or sender address when sender-dependent authentica-
tion is enabled.
<b><a href="postconf.5.html#smtp_sasl_security_options">smtp_sasl_security_options</a> (noplaintext, noanonymous)</b>
- What authentication mechanisms the Postfix SMTP
- client is allowed to use.
+ SASL security options; as of Postfix 2.3 the list
+ of available features depends on the SASL client
+ implementation that is selected with
+ <b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a></b>.
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtp_sasl_mechanism_filter">smtp_sasl_mechanism_filter</a> (empty)</b>
- If non-empty, a Postfix SMTP client filter for the
- remote SMTP server's list of offered SASL mecha-
+ If non-empty, a Postfix SMTP client filter for the
+ remote SMTP server's list of offered SASL mecha-
nisms.
Available in Postfix version 2.3 and later:
<b><a href="postconf.5.html#smtp_sender_dependent_authentication">smtp_sender_dependent_authentication</a> (no)</b>
- Enable sender-dependent authentication in the SMTP
- client; this is available only with SASL authenti-
- cation, and disables SMTP connection caching to
- ensure that mail from different senders will use
+ Enable sender-dependent authentication in the SMTP
+ client; this is available only with SASL authenti-
+ cation, and disables SMTP connection caching to
+ ensure that mail from different senders will use
the appropriate credentials.
+ <b><a href="postconf.5.html#smtp_sasl_path">smtp_sasl_path</a> (empty)</b>
+ Implementation-specific information that is passed
+ through to the SASL plug-in implementation that is
+ selected with <b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a></b>.
+
+ <b><a href="postconf.5.html#smtp_sasl_type">smtp_sasl_type</a> (cyrus)</b>
+ The SASL plug-in type that the Postfix SMTP client
+ should use for authentication.
+
<b>STARTTLS SUPPORT CONTROLS</b>
Detailed information about STARTTLS configuration may be
found in the <a href="TLS_README.html">TLS_README</a> document.
The SMTP client time limit for sending the RSET
command, and for receiving the server response.
+ Available in Postfix version 2.2 and earlier:
+
+ <b><a href="postconf.5.html#lmtp_cache_connection">lmtp_cache_connection</a> (yes)</b>
+ Keep Postfix LMTP client connections open for up to
+ $<a href="postconf.5.html#max_idle">max_idle</a> seconds.
+
Available in Postfix version 2.2 and later:
<b><a href="postconf.5.html#smtp_connection_cache_destinations">smtp_connection_cache_destinations</a> (empty)</b>
- Permanently enable SMTP connection caching for the
+ Permanently enable SMTP connection caching for the
specified destinations.
<b><a href="postconf.5.html#smtp_connection_cache_on_demand">smtp_connection_cache_on_demand</a> (yes)</b>
- Temporarily enable SMTP connection caching while a
+ Temporarily enable SMTP connection caching while a
destination has a high volume of mail in the active
queue.
<b><a href="postconf.5.html#smtp_connection_cache_time_limit">smtp_connection_cache_time_limit</a> (2s)</b>
When SMTP connection caching is enabled, the amount
- of time that an unused SMTP client socket is kept
+ of time that an unused SMTP client socket is kept
open before it is closed.
Available in Postfix version 2.3 and later:
<b><a href="postconf.5.html#connection_cache_protocol_timeout">connection_cache_protocol_timeout</a> (5s)</b>
- Time limit for connection cache connect, send or
+ Time limit for connection cache connect, send or
receive operations.
<b>TROUBLE SHOOTING CONTROLS</b>
<b><a href="postconf.5.html#debug_peer_level">debug_peer_level</a> (2)</b>
- The increment in verbose logging level when a
- remote client or server matches a pattern in the
+ The increment in verbose logging level when a
+ remote client or server matches a pattern in the
<a href="postconf.5.html#debug_peer_list">debug_peer_list</a> parameter.
<b><a href="postconf.5.html#debug_peer_list">debug_peer_list</a> (empty)</b>
- Optional list of remote client or server hostname
- or network address patterns that cause the verbose
- logging level to increase by the amount specified
+ Optional list of remote client or server hostname
+ or network address patterns that cause the verbose
+ logging level to increase by the amount specified
in $<a href="postconf.5.html#debug_peer_level">debug_peer_level</a>.
<b><a href="postconf.5.html#error_notice_recipient">error_notice_recipient</a> (postmaster)</b>
- The recipient of postmaster notifications about
- mail delivery problems that are caused by policy,
+ The recipient of postmaster notifications about
+ mail delivery problems that are caused by policy,
resource, software or protocol errors.
<b><a href="postconf.5.html#notify_classes">notify_classes</a> (resource, software)</b>
- The list of error classes that are reported to the
+ The list of error classes that are reported to the
postmaster.
<b>MISCELLANEOUS CONTROLS</b>
<b><a href="postconf.5.html#best_mx_transport">best_mx_transport</a> (empty)</b>
- Where the Postfix SMTP client should deliver mail
+ Where the Postfix SMTP client should deliver mail
when it detects a "mail loops back to myself" error
condition.
<b><a href="postconf.5.html#config_directory">config_directory</a> (see 'postconf -d' output)</b>
- The default location of the Postfix main.cf and
+ The default location of the Postfix main.cf and
master.cf configuration files.
<b><a href="postconf.5.html#daemon_timeout">daemon_timeout</a> (18000s)</b>
- How much time a Postfix daemon process may take to
- handle a request before it is terminated by a
+ How much time a Postfix daemon process may take to
+ handle a request before it is terminated by a
built-in watchdog timer.
<b><a href="postconf.5.html#delay_logging_resolution_limit">delay_logging_resolution_limit</a> (2)</b>
- The maximal number of digits after the decimal
+ The maximal number of digits after the decimal
point when logging sub-second delay values.
<b><a href="postconf.5.html#disable_dns_lookups">disable_dns_lookups</a> (no)</b>
- Disable DNS lookups in the Postfix SMTP and LMTP
+ Disable DNS lookups in the Postfix SMTP and LMTP
clients.
<b><a href="postconf.5.html#inet_interfaces">inet_interfaces</a> (all)</b>
tem receives mail on.
<b><a href="postconf.5.html#inet_protocols">inet_protocols</a> (ipv4)</b>
- The Internet protocols Postfix will attempt to use
+ The Internet protocols Postfix will attempt to use
when making or accepting connections.
<b><a href="postconf.5.html#ipc_timeout">ipc_timeout</a> (3600s)</b>
over an internal communication channel.
<b><a href="postconf.5.html#lmtp_tcp_port">lmtp_tcp_port</a> (24)</b>
- The default TCP port that the Postfix LMTP client
+ The default TCP port that the Postfix LMTP client
connects to.
<b><a href="postconf.5.html#max_idle">max_idle</a> (100s)</b>
- The maximum amount of time that an idle Postfix
- daemon process waits for the next service request
+ The maximum amount of time that an idle Postfix
+ daemon process waits for the next service request
before exiting.
<b><a href="postconf.5.html#max_use">max_use</a> (100)</b>
- The maximal number of connection requests before a
+ The maximal number of connection requests before a
Postfix daemon process terminates.
<b><a href="postconf.5.html#process_id">process_id</a> (read-only)</b>
- The process ID of a Postfix command or daemon
+ The process ID of a Postfix command or daemon
process.
<b><a href="postconf.5.html#process_name">process_name</a> (read-only)</b>
- The process name of a Postfix command or daemon
+ The process name of a Postfix command or daemon
process.
<b><a href="postconf.5.html#proxy_interfaces">proxy_interfaces</a> (empty)</b>
The network interface addresses that this mail sys-
- tem receives mail on by way of a proxy or network
+ tem receives mail on by way of a proxy or network
address translation unit.
<b><a href="postconf.5.html#smtp_bind_address">smtp_bind_address</a> (empty)</b>
An optional numerical network address that the SMTP
- client should bind to when making an IPv4 connec-
+ client should bind to when making an IPv4 connec-
tion.
<b><a href="postconf.5.html#smtp_bind_address6">smtp_bind_address6</a> (empty)</b>
An optional numerical network address that the SMTP
- client should bind to when making an IPv6 connec-
+ client should bind to when making an IPv6 connec-
tion.
<b><a href="postconf.5.html#smtp_helo_name">smtp_helo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
- The hostname to send in the SMTP EHLO or HELO com-
+ The hostname to send in the SMTP EHLO or HELO com-
mand.
- <b>lmtp_lhlo_name ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
+ <b><a href="postconf.5.html#lmtp_lhloname">lmtp_lhlo_name</a> ($<a href="postconf.5.html#myhostname">myhostname</a>)</b>
The hostname to send in the LMTP LHLO command.
<b><a href="postconf.5.html#smtp_host_lookup">smtp_host_lookup</a> (dns)</b>
- What mechanisms when the SMTP client uses to look
+ What mechanisms when the SMTP client uses to look
up a host's IP address.
<b><a href="postconf.5.html#smtp_randomize_addresses">smtp_randomize_addresses</a> (yes)</b>
- Randomize the order of equal-preference MX host
+ Randomize the order of equal-preference MX host
addresses.
<b><a href="postconf.5.html#syslog_facility">syslog_facility</a> (mail)</b>
The syslog facility of Postfix logging.
<b><a href="postconf.5.html#syslog_name">syslog_name</a> (postfix)</b>
- The mail system name that is prepended to the
- process name in syslog records, so that "smtpd"
+ The mail system name that is prepended to the
+ process name in syslog records, so that "smtpd"
becomes, for example, "postfix/smtpd".
Available with Postfix 2.2 and earlier:
<b><a href="postconf.5.html#fallback_relay">fallback_relay</a> (empty)</b>
- Optional list of relay hosts for SMTP destinations
+ Optional list of relay hosts for SMTP destinations
that can't be found or that are unreachable.
Available with Postfix 2.3 and later:
- <b>smtp_fallback_relay ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
- Optional list of relay hosts for SMTP destinations
+ <b><a href="postconf.5.html#smtp_fallback_relay">smtp_fallback_relay</a> ($<a href="postconf.5.html#fallback_relay">fallback_relay</a>)</b>
+ Optional list of relay hosts for SMTP destinations
that can't be found or that are unreachable.
<b>SEE ALSO</b>
<a href="TLS_README.html">TLS_README</a>, Postfix STARTTLS howto
<b>LICENSE</b>
- The Secure Mailer license must be distributed with this
+ The Secure Mailer license must be distributed with this
software.
<b>AUTHOR(S)</b>
Enable SASL authentication in the Postfix SMTP
server.
- <b><a href="postconf.5.html#smtpd_sasl_application_name">smtpd_sasl_application_name</a> (smtpd)</b>
- The application name used for SASL server initial-
- ization.
-
<b><a href="postconf.5.html#smtpd_sasl_local_domain">smtpd_sasl_local_domain</a> (empty)</b>
The name of the local SASL authentication realm.
<b><a href="postconf.5.html#smtpd_sasl_security_options">smtpd_sasl_security_options</a> (noanonymous)</b>
- Restrict what authentication mechanisms the Postfix
- SMTP server will offer to the client.
+ SASL security options; as of Postfix 2.3 the list
+ of available features depends on the SASL server
+ implementation that is selected with
+ <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b>.
<b><a href="postconf.5.html#smtpd_sender_login_maps">smtpd_sender_login_maps</a> (empty)</b>
- Optional lookup table with the SASL login names
+ Optional lookup table with the SASL login names
that own sender (MAIL FROM) addresses.
Available in Postfix version 2.1 and later:
<b><a href="postconf.5.html#smtpd_sasl_exceptions_networks">smtpd_sasl_exceptions_networks</a> (empty)</b>
- What SMTP clients Postfix will not offer AUTH sup-
+ What SMTP clients Postfix will not offer AUTH sup-
port to.
Available in Postfix version 2.3 and later:
<b><a href="postconf.5.html#smtpd_sasl_authenticated_header">smtpd_sasl_authenticated_header</a> (no)</b>
- Report the SASL authenticated user name in the
+ Report the SASL authenticated user name in the
<a href="smtpd.8.html"><b>smtpd</b>(8)</a> Received message header.
+ <b>smtpd_sasl_path (smtpd)</b>
+ Implementation-specific information that is passed
+ through to the SASL plug-in implementation that is
+ selected with <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a></b>.
+
+ <b><a href="postconf.5.html#smtpd_sasl_type">smtpd_sasl_type</a> (cyrus)</b>
+ The SASL plug-in type that the Postfix SMTP server
+ should use for authentication.
+
<b>STARTTLS SUPPORT CONTROLS</b>
Detailed information about STARTTLS configuration may be
found in the <a href="TLS_README.html">TLS_README</a> document.
<a href="postconf.5.html#reject_non_fqdn_sender">reject_non_fqdn_sender</a> or <a href="postconf.5.html#reject_non_fqdn_recipient">reject_non_fqdn_recipient</a>
restriction.
+ <b>plaintext_reject_code (450)</b>
+ The numerical Postfix SMTP server response code
+ when a request is rejected by the <b>reject_plain-</b>
+ <b>text_session</b> restriction.
+
<b><a href="postconf.5.html#reject_code">reject_code</a> (554)</b>
The numerical Postfix SMTP server response code
when a remote SMTP client request is rejected by
.na
.nf
.fi
-\fBpostconf\fR [\fB-dhmlnv\fR] [\fB-c \fIconfig_dir\fR]
+\fBpostconf\fR [\fB-dhnv\fR] [\fB-c \fIconfig_dir\fR]
[\fIparameter ...\fR]
+\fBpostconf\fR [\fB-aAmlv\fR] [\fB-c \fIconfig_dir\fR]
+
\fBpostconf\fR [\fB-ev\fR] [\fB-c \fIconfig_dir\fR]
[\fIparameter=value ...\fR]
the Postfix mail system.
Options:
+.IP \fB-a\fR
+List the available SASL server plug-in types. The SASL
+plug-in type is selected with the \fBsmtpd_sasl_type\fR
+configuration parameter.
+
+This feature is available with Postfix 2.3 and later.
+.IP \fB-A\fR
+List the available SASL client plug-in types. The SASL
+plug-in type is selected with the \fBsmtp_sasl_type\fR or
+\fBlmtp_sasl_type\fR configuration parameters.
+
+This feature is available with Postfix 2.3 and later.
.IP "\fB-b\fR [\fItemplate_file\fR]"
Display the message text that appears at the beginning of
delivery status notification (DSN) messages, with $\fBname\fR
per host or domain. If a remote host or domain has no username:password
entry, then the Postfix LMTP client will not attempt to authenticate
to the remote host.
+.SH lmtp_sasl_path (default: empty)
+Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+\fBlmtp_sasl_type\fR. Typically this specifies the name of a
+configuration file or rendez-vous point.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_sasl_security_options (default: noplaintext, noanonymous)
-What authentication mechanisms the Postfix LMTP client is allowed
-to use. The list of available authentication mechanisms is system
-dependent.
+SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL client implementation that is selected
+with \fBlmtp_sasl_type\fR.
+.PP
+The following security features are defined for the \fBcyrus\fR
+client SASL implementation:
.IP "\fBnoplaintext\fR"
Disallow authentication methods that use plaintext passwords.
.IP "\fBnoactive\fR"
configuration parameter. See there for details.
.PP
This feature is available in Postfix 2.3 and later.
+.SH lmtp_sasl_type (default: cyrus)
+The SASL plug-in type that the Postfix LMTP client should use
+for authentication. The available types are listed with the
+"\fBpostconf -A\fR" command.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH lmtp_send_xforward_command (default: no)
Send an XFORWARD command to the LMTP server when the LMTP LHLO
server response announces XFORWARD support. This allows an \fBlmtp\fR(8)
submissions from the Postfix maildrop queue.
.PP
This feature is available in Postfix 2.0 and later.
+.SH plaintext_session_reject_code (default: 450)
+The numerical Postfix SMTP server response code when a request
+is rejected by the \fBreject_plaintext_session\fR restriction.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH prepend_delivered_header (default: command, file, forward)
The message delivery contexts where the Postfix \fBlocal\fR(8) delivery
agent prepends a Delivered-To: message header with the address
.PP
The Postfix SMTP client opens the lookup table before going to
chroot jail, so you can leave the password file in /etc/postfix.
+.SH smtp_sasl_path (default: empty)
+Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+\fBsmtp_sasl_type\fR. Typically this specifies the name of a
+configuration file or rendez-vous point.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH smtp_sasl_security_options (default: noplaintext, noanonymous)
-What authentication mechanisms the Postfix SMTP client is allowed
-to use. The list of available authentication mechanisms is system
-dependent.
+SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL client implementation that is selected
+with \fBsmtp_sasl_type\fR.
+.PP
+The following security features are defined for the \fBcyrus\fR
+client SASL implementation:
.PP
Specify zero or more of the following:
.IP "\fBnoplaintext\fR"
.SH smtp_sasl_tls_security_options (default: $smtp_sasl_security_options)
The SASL authentication security options that the Postfix SMTP
client uses for TLS encrypted SMTP sessions.
+.SH smtp_sasl_type (default: cyrus)
+The SASL plug-in type that the Postfix SMTP client should use
+for authentication. The available types are listed with the
+"\fBpostconf -A\fR" command.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH smtp_send_xforward_command (default: no)
Send the non-standard XFORWARD command when the Postfix SMTP server EHLO
response announces XFORWARD support.
The multi_recipient_bounce_reject_code parameter specifies the
response code for rejected requests (default: 550). This feature
is available in Postfix 2.1 and later.
+.IP "\fBreject_plaintext_session\fR"
+Reject the request when the connection is not encrypted. This
+restriction should not be used before the client has had a chance
+to negotiate encryption with the AUTH or STARTTLS commands.
+.br
+The plaintext_session_reject_code parameter specifies the response
+code for rejected requests (default: 450). This feature is available
+in Postfix 2.3 and later.
.IP "\fBreject_unauth_pipelining\fR"
Reject the request when the client sends SMTP commands ahead
of time where it is not allowed, or when the client sends SMTP
.fi
.ad
.ft R
+.SH smtpd_sasl_path (default: smtpd)
+Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+\fBsmtpd_sasl_type\fR. Typically this specifies the name of a
+configuration file or rendez-vous point.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH smtpd_sasl_security_options (default: noanonymous)
+SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL server implementation that is selected
+with \fBsmtpd_sasl_type\fR.
+.PP
+The following security features are defined for the \fBcyrus\fR
+server SASL implementation:
+.PP
Restrict what authentication mechanisms the Postfix SMTP server
will offer to the client. The list of available authentication
mechanisms is system dependent.
.SH smtpd_sasl_tls_security_options (default: $smtpd_sasl_security_options)
The SASL authentication security options that the Postfix SMTP
server uses for TLS encrypted SMTP sessions.
+.SH smtpd_sasl_type (default: cyrus)
+The SASL plug-in type that the Postfix SMTP server should use
+for authentication. The available types are listed with the
+"\fBpostconf -a\fR" command.
+.PP
+This feature is available in Postfix 2.3 and later.
.SH smtpd_sender_login_maps (default: empty)
Optional lookup table with the SASL login names that own sender
(MAIL FROM) addresses.
.ad
.fi
SMTP destinations have the following form:
-.IP "\fIdomainname\fR, \fIdomainname\fR:\fIport\fR"
-Look up the mail exchangers for the specified domain.
-.IP "[\fIhostname\fR], [\fIhostname\fR]:\fIport\fR"
-Look up the address of the specified host.
-.IP "[\fIaddress\fR], [\fIaddress\fR]:\fIport\fR"
-Connect to the host at the specified address. An IPv6
-address must be formatted as [\fBipv6\fR:\fIaddress\fR].
-.PP
-In all the above cases, when no port is specified, look up
-the port defined as \fBsmtp\fR in \fBservices\fR(4).
+.IP \fIdomainname\fR
+.IP \fIdomainname\fR:\fIport\fR
+Look up the mail exchangers for the specified domain, and
+connect to the specified port (default: \fBsmtp\fR).
+.IP [\fIhostname\fR]
+.IP [\fIhostname\fR]:\fIport\fR
+Look up the address(es) of the specified host, and connect to
+the specified port (default: \fBsmtp\fR).
+.IP [\fIaddress\fR]
+.IP [\fIaddress\fR]:\fIport\fR
+Connect to the host at the specified address, and connect
+to the specified port (default: \fBsmtp\fR). An IPv6 address
+must be formatted as [\fBipv6\fR:\fIaddress\fR].
.SH "LMTP DESTINATION SYNTAX"
.na
.nf
Connect to the local UNIX-domain server that is bound to the specified
\fIpathname\fR. If the process runs chrooted, an absolute pathname
is interpreted relative to the Postfix queue directory.
-.IP "\fBinet\fR:\fIhostname\fR, \fBinet\fB:\fIhostname\fR:\fIport\fR"
-.IP "\fBinet\fR:[\fIaddress\fR], \fBinet\fR:[\fIaddress\fR]:\fIport\fR"
+.IP \fBinet\fR:\fIhostname\fR
+.IP \fBinet\fB:\fIhostname\fR:\fIport\fR
+.IP \fBinet\fR:[\fIaddress\fR]
+.IP \fBinet\fR:[\fIaddress\fR]:\fIport\fR
Connect to the specified TCP port on the specified local or
remote host. If no port is specified, connect to the 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.
+An IPv6 address must be formatted as [\fBipv6\fR:\fIaddress\fR].
.PP
.SH "SECURITY"
.na
.nf
.ad
.fi
+Before Postfix version 2.3, the LMTP client is a separate
+program that implements only a subset of the functionality
+available with SMTP: there is no support for TLS, and
+connections are cached in-process, making it ineffective
+when the client is used for multiple domains.
+
Most smtp_\fIxxx\fR configuration parameters have an
lmtp_\fIxxx\fR "ghost" parameter for the equivalent LMTP
feature. This document describes only those LMTP-related
per remote hostname or domain, or sender address when sender-dependent
authentication is enabled.
.IP "\fBsmtp_sasl_security_options (noplaintext, noanonymous)\fR"
-What authentication mechanisms the Postfix SMTP client is allowed
-to use.
+SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL client implementation that is selected
+with \fBsmtp_sasl_type\fR.
.PP
Available in Postfix version 2.2 and later:
.IP "\fBsmtp_sasl_mechanism_filter (empty)\fR"
available only with SASL authentication, and disables SMTP connection
caching to ensure that mail from different senders will use the
appropriate credentials.
+.IP "\fBsmtp_sasl_path (empty)\fR"
+Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+\fBsmtp_sasl_type\fR.
+.IP "\fBsmtp_sasl_type (cyrus)\fR"
+The SASL plug-in type that the Postfix SMTP client should use
+for authentication.
.SH "STARTTLS SUPPORT CONTROLS"
.na
.nf
The SMTP client time limit for sending the RSET command, and
for receiving the server response.
.PP
+Available in Postfix version 2.2 and earlier:
+.IP "\fBlmtp_cache_connection (yes)\fR"
+Keep Postfix LMTP client connections open for up to $max_idle
+seconds.
+.PP
Available in Postfix version 2.2 and later:
.IP "\fBsmtp_connection_cache_destinations (empty)\fR"
Permanently enable SMTP connection caching for the specified
version of the AUTH command (RFC 2554).
.IP "\fBsmtpd_sasl_auth_enable (no)\fR"
Enable SASL authentication in the Postfix SMTP server.
-.IP "\fBsmtpd_sasl_application_name (smtpd)\fR"
-The application name used for SASL server initialization.
.IP "\fBsmtpd_sasl_local_domain (empty)\fR"
The name of the local SASL authentication realm.
.IP "\fBsmtpd_sasl_security_options (noanonymous)\fR"
-Restrict what authentication mechanisms the Postfix SMTP server
-will offer to the client.
+SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL server implementation that is selected
+with \fBsmtpd_sasl_type\fR.
.IP "\fBsmtpd_sender_login_maps (empty)\fR"
Optional lookup table with the SASL login names that own sender
(MAIL FROM) addresses.
.IP "\fBsmtpd_sasl_authenticated_header (no)\fR"
Report the SASL authenticated user name in the \fBsmtpd\fR(8) Received
message header.
+.IP "\fBsmtpd_sasl_path (smtpd)\fR"
+Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+\fBsmtpd_sasl_type\fR.
+.IP "\fBsmtpd_sasl_type (cyrus)\fR"
+The SASL plug-in type that the Postfix SMTP server should use
+for authentication.
.SH "STARTTLS SUPPORT CONTROLS"
.na
.nf
The numerical Postfix SMTP server reply code when a client request
is rejected by the reject_non_fqdn_helo_hostname, reject_non_fqdn_sender
or reject_non_fqdn_recipient restriction.
+.IP "\fBplaintext_reject_code (450)\fR"
+The numerical Postfix SMTP server response code when a request
+is rejected by the \fBreject_plaintext_session\fR restriction.
.IP "\fBreject_code (554)\fR"
The numerical Postfix SMTP server response code when a remote SMTP
client request is rejected by the "reject" restriction.
s;\bipc_timeout\b;<a href="postconf.5.html#ipc_timeout">$&</a>;g;
s;\bipc_ttl\b;<a href="postconf.5.html#ipc_ttl">$&</a>;g;
s;\bline_length_limit\b;<a href="postconf.5.html#line_length_limit">$&</a>;g;
+ s;\blmtp_bind_address\b;<a href="postconf.5.html#lmtp_bind_address">$&</a>;g;
+ s;\blmtp_bind_address6\b;<a href="postconf.5.html#lmtp_bind_address6">$&</a>;g;
s;\blmtp_cache_connection\b;<a href="postconf.5.html#lmtp_cache_connection">$&</a>;g;
+ s;\blmtp_discard_lhlo_keyword_address_maps\b;<a href="postconf.5.html#lmtp_discard_lhlo_keyword_address_maps">$&</a>;g;
+ s;\blmtp_discard_lhlo_keywords\b;<a href="postconf.5.html#lmtp_discard_lhlo_keywords">$&</a>;g;
+ s;\blmtp_sasl_tls_security_options\b;<a href="postconf.5.html#lmtp_sasl_tls_security_options">$&</a>;g;
+ s;\blmtp_sasl_mechanism_filter\b;<a href="postconf.5.html#lmtp_sasl_mechanism_filter">$&</a>;g;
+ s;\blmtp_host_lookup\b;<a href="postconf.5.html#lmtp_host_lookup">$&</a>;g;
+ s;\blmtp_connection_cache_destinations\b;<a href="postconf.5.html#lmtp_connection_cache_destinations">$&</a>;g;
+ s;\blmtp_tls_per_site\b;<a href="postconf.5.html#lmtp_tls_per_site">$&</a>;g;
+ s;\blmtp_generic_maps\b;<a href="postconf.5.html#lmtp_generic_maps">$&</a>;g;
+ s;\blmtp_pix_workaround_threshold_time\b;<a href="postconf.5.html#lmtp_pix_workaround_threshold_time">$&</a>;g;
+ s;\blmtp_pix_workaround_delay_time\b;<a href="postconf.5.html#lmtp_pix_workaround_delay_time">$&</a>;g;
+ s;\blmtp_connection_reuse_time_limit\b;<a href="postconf.5.html#lmtp_connection_reuse_time_limit">$&</a>;g;
+ s;\blmtp_starttls_timeout\b;<a href="postconf.5.html#lmtp_starttls_timeout">$&</a>;g;
+ s;\blmtp_line_length_limit\b;<a href="postconf.5.html#lmtp_line_length_limit">$&</a>;g;
+ s;\blmtp_mx_address_limit\b;<a href="postconf.5.html#lmtp_mx_address_limit">$&</a>;g;
+ s;\blmtp_mx_session_limit\b;<a href="postconf.5.html#lmtp_mx_session_limit">$&</a>;g;
+ s;\blmtp_tls_scert_verifydepth\b;<a href="postconf.5.html#lmtp_tls_scert_verifydepth">$&</a>;g;
+ s;\blmtp_skip_5xx_greeting\b;<a href="postconf.5.html#lmtp_skip_5xx_greeting">$&</a>;g;
+ s;\blmtp_randomize_addresses\b;<a href="postconf.5.html#lmtp_randomize_addresses">$&</a>;g;
+ s;\blmtp_quote_rfc821_envelope\b;<a href="postconf.5.html#lmtp_quote_rfc821_envelope">$&</a>;g;
+ s;\blmtp_defer_if_no_mx_address_found\b;<a href="postconf.5.html#lmtp_defer_if_no_mx_address_found">$&</a>;g;
+ s;\blmtp_connection_cache_on_demand\b;<a href="postconf.5.html#lmtp_connection_cache_on_demand">$&</a>;g;
+ s;\blmtp_use_tls\b;<a href="postconf.5.html#lmtp_use_tls">$&</a>;g;
+ s;\blmtp_enforce_tls\b;<a href="postconf.5.html#lmtp_enforce_tls">$&</a>;g;
+ s;\blmtp_tls_enforce_peername\b;<a href="postconf.5.html#lmtp_tls_enforce_peername">$&</a>;g;
+ s;\blmtp_tls_note_starttls_offer\b;<a href="postconf.5.html#lmtp_tls_note_starttls_offer">$&</a>;g;
+ s;\blmtp_sender_dependent_authentication\b;<a href="postconf.5.html#lmtp_sender_dependent_authentication">$&</a>;g;
+ s;\blmtp_sasl_path\b;<a href="postconf.5.html#lmtp_sasl_path">$&</a>;g;
+ s;\blmtp_lhlo_name\b;<a href="postconf.5.html#lmtp_lhloname">$&</a>;g;
s;\blmtp_connect_timeout\b;<a href="postconf.5.html#lmtp_connect_timeout">$&</a>;g;
s;\blmtp_data_done_timeout\b;<a href="postconf.5.html#lmtp_data_done_timeout">$&</a>;g;
s;\blmtp_data_init_timeout\b;<a href="postconf.5.html#lmtp_data_init_timeout">$&</a>;g;
s;\blmtp_sasl_auth_enable\b;<a href="postconf.5.html#lmtp_sasl_auth_enable">$&</a>;g;
s;\blmtp_sasl_password_maps\b;<a href="postconf.5.html#lmtp_sasl_password_maps">$&</a>;g;
s;\blmtp_sasl_security_options\b;<a href="postconf.5.html#lmtp_sasl_security_options">$&</a>;g;
+ s;\blmtp_sasl_type\b;<a href="postconf.5.html#lmtp_sasl_type">$&</a>;g;
s;\blmtp_send_xforward_command\b;<a href="postconf.5.html#lmtp_send_xforward_command">$&</a>;g;
s;\blmtp_skip_quit_response\b;<a href="postconf.5.html#lmtp_skip_quit_response">$&</a>;g;
s;\blmtp_tcp_port\b;<a href="postconf.5.html#lmtp_tcp_port">$&</a>;g;
s;\bpar[-</bB>]*\n* *[<bB>]*ent_domain_matches_subdomains\b;<a href="postconf.5.html#parent_domain_matches_subdomains">$&</a>;g;
s;\bpermit_mx_backup_networks\b;<a href="postconf.5.html#permit_mx_backup_networks">$&</a>;g;
s;\bpickup_service_name\b;<a href="postconf.5.html#pickup_service_name">$&</a>;g;
+ s;\bplaintext_session_reject_code\b;<a href="postconf.5.html#plaintext_session_reject_code">$&</a>;g;
s;\bprepend_delivered_header\b;<a href="postconf.5.html#prepend_delivered_header">$&</a>;g;
s;\bprocess_id\b;<a href="postconf.5.html#process_id">$&</a>;g;
s;\bprocess_id_directory\b;<a href="postconf.5.html#process_id_directory">$&</a>;g;
s;\bsmtp_sasl_auth_enable\b;<a href="postconf.5.html#smtp_sasl_auth_enable">$&</a>;g;
s;\bsmtp_sasl_mechanism_filter\b;<a href="postconf.5.html#smtp_sasl_mechanism_filter">$&</a>;g;
s;\bsmtp_sasl_password_maps\b;<a href="postconf.5.html#smtp_sasl_password_maps">$&</a>;g;
+ s;\bsmtp_sasl_path\b;<a href="postconf.5.html#smtp_sasl_path">$&</a>;g;
s;\bsmtp_sasl_secu[-</Bb>]*\n* *[<Bb>]*rity_options\b;<a href="postconf.5.html#smtp_sasl_security_options">$&</a>;g;
s;\bsmtp_send_xforward_command\b;<a href="postconf.5.html#smtp_send_xforward_command">$&</a>;g;
s;\bsmtp_skip_4xx_greeting\b;<a href="postconf.5.html#smtp_skip_4xx_greeting">$&</a>;g;
s;\bsmtpd_reject_unlisted_recip[-</bB>]*\n* *[<bB>]*ient\b;<a href="postconf.5.html#smtpd_reject_unlisted_recipient">$&</a>;g;
s;\bsmtpd_reject_unlisted_sender\b;<a href="postconf.5.html#smtpd_reject_unlisted_sender">$&</a>;g;
s;\bsmtpd_restriction_classes\b;<a href="postconf.5.html#smtpd_restriction_classes">$&</a>;g;
- s;\bsmtpd_sasl_application_name\b;<a href="postconf.5.html#smtpd_sasl_application_name">$&</a>;g;
+ s;\bsmtpd_sasl_path\b;<a href="postconf.5.html#smtpd_sasl_path">$&</a>;g;
s;\bsmtpd_sasl_auth_enable\b;<a href="postconf.5.html#smtpd_sasl_auth_enable">$&</a>;g;
s;\bsmtpd_sasl_authenticated_header\b;<a href="postconf.5.html#smtpd_sasl_authenticated_header">$&</a>;g;
s;\bsmtpd_sasl_exceptions_networks\b;<a href="postconf.5.html#smtpd_sasl_exceptions_networks">$&</a>;g;
s;\bvir[-</bB>]*\n*[ <bB>]*tual_uid_maps\b;<a href="postconf.5.html#virtual_uid_maps">$&</a>;g;
s;\bsmtp_enforce_tls\b;<a href="postconf.5.html#smtp_enforce_tls">$&</a>;g;
+ s;\bsmtp_fallback_relay\b;<a href="postconf.5.html#smtp_fallback_relay">$&</a>;g;
s;\bsmtp_sasl_tls_security_options\b;<a href="postconf.5.html#smtp_sasl_tls_security_options">$&</a>;g;
s;\bsmtp_sasl_tls_verified_security_options\b;<a href="postconf.5.html#smtp_sasl_tls_verified_security_options">$&</a>;g;
+ s;\bsmtp_sasl_type\b;<a href="postconf.5.html#smtp_sasl_type">$&</a>;g;
s;\bsmtp_starttls_timeout\b;<a href="postconf.5.html#smtp_starttls_timeout">$&</a>;g;
s;\bsmtp_tls_CAfile\b;<a href="postconf.5.html#smtp_tls_CAfile">$&</a>;g;
s;\bsmtp_tls_CApath\b;<a href="postconf.5.html#smtp_tls_CApath">$&</a>;g;
s;\bsmtp_use_tls\b;<a href="postconf.5.html#smtp_use_tls">$&</a>;g;
s;\bsmtpd_enforce_tls\b;<a href="postconf.5.html#smtpd_enforce_tls">$&</a>;g;
s;\bsmtpd_sasl_tls_security_options\b;<a href="postconf.5.html#smtpd_sasl_tls_security_options">$&</a>;g;
+ s;\bsmtpd_sasl_type\b;<a href="postconf.5.html#smtpd_sasl_type">$&</a>;g;
s;\bsmtpd_starttls_timeout\b;<a href="postconf.5.html#smtpd_starttls_timeout">$&</a>;g;
s;\bsmtpd_tls_CAfile\b;<a href="postconf.5.html#smtpd_tls_CAfile">$&</a>;g;
s;\bsmtpd_tls_CApath\b;<a href="postconf.5.html#smtpd_tls_CApath">$&</a>;g;
s;\bdefer_if_permit\b;<a href="postconf.5.html#defer_if_permit">$&</a>;g;
s;\bdefer_if_reject\b;<a href="postconf.5.html#defer_if_reject">$&</a>;g;
s;\breject_multi_recip[-</bB>]*\n* *[<bB>]*ient_bounce\b;<a href="postconf.5.html#reject_multi_recipient_bounce">$&</a>;g;
+ s;\breject_plaintext_session\b;<a href="postconf.5.html#reject_plaintext_session">$&</a>;g;
s;\breject_unauth_pipelining\b;<a href="postconf.5.html#reject_unauth_pipelining">$&</a>;g;
s;\bwarn_if_reject\b;<a href="postconf.5.html#warn_if_reject">$&</a>;g;
<h2>WARNING</h2>
-<p> People who go to the trouble of installing Postfix may have
-the expectation that Postfix is more secure than some other mailers.
-The Cyrus SASL library is a lot of code. With SASL authentication
-enabled in the Postfix SMTP client and SMTP server, Postfix becomes
+<p> People who go to the trouble of installing Postfix may have the
+expectation that Postfix is more secure than some other mailers.
+The Cyrus SASL library is a lot of code. With this, Postfix becomes
as secure as other mail systems that use the Cyrus SASL library.
</p>
UCE restriction. </p>
<p> When sending mail, Postfix can look up the server hostname or
-destination domain (the address right-hand part) in a table, and if a
-username/password is found, it will use that username and password
-to authenticate to the server. </p>
+destination domain (the address right-hand part) in a Postfix SASL password
+table, and if a username/password is found, it will use that username
+and password to authenticate to the server. And as of version 2.3,
+Postfix can be configured to search its SASL password table by the
+sender email address. </p>
<p>This document covers the following topics: </p>
<li><a href="#versions">What SASL versions are supported</a>
-<li><a href="#build_sasl">Building the SASL library</a>
+<li><a href="#build_sasl">Building the Cyrus SASL library</a>
-<li><a href="#build_postfix">Building Postfix with SASL authentication
+<li><a href="#build_postfix">Building Postfix with Cyrus SASL
support</a></li>
<li><a href="#server_sasl">Enabling SASL authentication in the
<h2><a name="versions">What SASL versions are supported</a></h2>
-<p> Postfix+SASL 1.5.5 was seen working on RedHat 6.1 (pwcheck_method
-set to shadow or sasldb), Solaris 2.7 (pwcheck_method set to shadow
-or sasldb), and FreeBSD 3.4 (pwcheck_method set to sasldb). On
-RedHat 6.1, SASL 1.5.5 insisted on write access to /etc/sasldb.
-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. </p>
-
-<p> 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 use
-the auto_transition feature, or if you use an authentication
-mechanism such as OTP (one-time passwords) that needs to update
-secrets in the database. </p>
-
-<h2><a name="build_sasl">Building the SASL library</a></h2>
+<p> This document describes Postfix with Cyrus SASL version 1 and
+Cyrus SASL version 2. Postfix version 2.3 introduces has a plug-in
+mechanism for other SASL implementations. Support for other
+implementations is currently not part of the Postfix distribution
+and will be described elsewhere. </p>
+
+<h2><a name="build_sasl">Building the Cyrus SASL library</a></h2>
<p> Postfix appears to work with cyrus-sasl-1.5.5 or cyrus-sasl-2.1.1,
which are available from: </p>
<blockquote>
<pre>
-ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/.
+ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/
</pre>
</blockquote>
non-standard SASL LOGIN authentication method. To enable this
authentication method, specify ``./configure --enable-login''. </p>
-<h2><a name="build_postfix">Building Postfix with SASL authentication
-support</a></h2>
+<h2><a name="build_postfix">Building Postfix with Cyrus SASL support</a></h2>
<p> To build Postfix with SASL authentication support, the following
assumes that the Cyrus SASL include files are in /usr/local/include,
<dl>
-<dt> (for SASL version 1.5.5):
+<dt> (for Cyrus SASL version 1.5.5):
<dd>
<pre>
% 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"
+% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include" AUXLIBS="-L/usr/local/lib -lsasl"
</pre>
-<dt> (for SASL version 2.1.1):
+<dt> (for Cyrus SASL version 2.1.1):
<dd>
<pre>
% 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"
+% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include/sasl" AUXLIBS="-L/usr/local/lib -lsasl2"
</pre>
</dl>
<dl>
-<dt> (for SASL version 1.5.5):
+<dt> (for Cyrus SASL version 1.5.5):
<dd>
<pre>
% 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"
+% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include" AUXLIBS="-L/usr/local/lib \
+ -R/usr/local/lib -lsasl"
</pre>
-<dt> (for SASL version 2.1.1):
+<dt> (for Cyrus SASL version 2.1.1):
<dd>
<pre>
% 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"
+% make makefiles CCARGS="-DUSE_SASL_AUTH -DUSE_CYRUS_SASL \
+ -I/usr/local/include/sasl" AUXLIBS="-L/usr/local/lib \
+ -R/usr/local/lib -lsasl2"
</pre>
</dl>
<p> Note: the SASL login names will be shared with the entire world.
</p>
-<p> In /usr/local/lib/sasl/smtpd.conf (SASL version 1.5.5) or
-/usr/local/lib/sasl2/smtpd.conf (SASL version 2.1.1) you need to
+<p> In /usr/local/lib/sasl/smtpd.conf (Cyrus SASL version 1.5.5) or
+/usr/local/lib/sasl2/smtpd.conf (Cyrus SASL version 2.1.1) you need to
specify how the server should validate client passwords. </p>
<p> Note: some Postfix distributions are modified and look for
the smtpd.conf file in /etc/postfix. </p>
-<p> Note: some Cyrus SASL distributions are modified and look for
-the smtpd.conf file in /etc/sasl2. </p>
+<p> Note: some Cyrus SASL distributions look for the smtpd.conf
+file in /etc/sasl2. </p>
+
+<ul>
-<p> In order to authenticate against the UNIX password database, try: </p>
+<li> <p> To authenticate against the UNIX password database, try: </p>
<dl>
-<dt> (SASL version 1.5.5)
+<dt> (Cyrus SASL version 1.5.5)
<dd>
<pre>
/usr/local/lib/sasl/smtpd.conf:
</pre>
-<dt> (SASL version 2.1.1)
+<dt> (Cyrus SASL version 2.1.1)
<dd>
<pre>
/usr/local/lib/sasl2/smtpd.conf:
</dl>
-<p> The name of the file in /usr/local/lib/sasl (SASL version 1.5.5)
-or /usr/local/lib/sasl2 (SASL version 2.1.1) used by the SASL
+<p> The name of the file in /usr/local/lib/sasl (Cyrus SASL version
+1.5.5) or /usr/local/lib/sasl2 (Cyrus SASL version 2.1.1) used by
+the SASL
library for configuration can be set with: </p>
<blockquote>
permission for the /var/pwcheck directory, otherwise authentication
attempts will fail. </p>
-<p> Alternately, in SASL 1.5.26 and later (including 2.1.1), try: </p>
+<li> <p> Alternately, in Cyrus SASL 1.5.26 and later (including
+2.1.1), try: </p>
<dl>
-<dt> (SASL version 1.5.26)
+<dt> (Cyrus SASL version 1.5.26)
<dd>
<pre>
/usr/local/lib/sasl/smtpd.conf:
pwcheck_method: saslauthd
</pre>
-<dt> (SASL version 2.1.1)
+<dt> (Cyrus SASL version 2.1.1)
<dd>
<pre>
/usr/local/lib/sasl2/smtpd.conf:
can authenticate against PAM and various other sources. To use PAM,
start saslauthd with "-a pam". </p>
-<p> In order to authenticate against SASL's own password database: </p>
+<li> <p> To authenticate against Cyrus SASL's own password database: </p>
<dl>
-<dt> (SASL version 1.5.5)
+<dt> (Cyrus SASL version 1.5.5)
<dd>
<pre>
/usr/local/lib/sasl/smtpd.conf:
pwcheck_method: sasldb
</pre>
-<dt> (SASL version 2.1.1)
+<dt> (Cyrus SASL version 2.1.1)
<dd>
<pre>
/usr/local/lib/sasl2/smtpd.conf:
</dl>
-<p> This will use the SASL password file (default: /etc/sasldb in
+<p> This will use the Cyrus 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 have to play games
with group access permissions. With the OTP authentication mechanism,
-the SMTP server also needs write access to /etc/sasldb2 or /etc/sasldb
+the SMTP server also needs WRITE access to /etc/sasldb2 or /etc/sasldb
(or the back end SQL database, if used). </p>
-<p> IMPORTANT: all users must be able to authenticate using ALL
-authentication mechanisms advertised by Postfix, otherwise the
-negotiation might end up with an unsupported mechanism, and
-authentication would fail. For example if you configure SASL to
-use <i>saslauthd</i> for authentication against PAM (pluggable
-authentication modules), only the PLAIN and LOGIN mechanisms are
-supported and stand a chance to succeed, yet the SASL library would also
-advertise other mechanisms, such as DIGEST-MD5. This happens because
-those mechanisms are made available by other plugins, and the SASL
-library have no way to know that your only valid authentication source
-is PAM. Thus you might need to limit the list of mechanisms advertised
-by Postfix. This is only possible with SASL version 2.1.1 or later:
-</p>
-
-<blockquote>
-<pre>
-/usr/local/lib/sasl2/smtpd.conf:
- mech_list: plain login
-</pre>
-</blockquote>
-
-<p> For the same reasons you might want to limit the list of plugins
-used for authentication. With SASL version 1.5.5 your only choice is to
-delete the corresponding libraries from /usr/local/lib/sasl. With SASL
-version 2.1.1: </p>
-
-<blockquote>
-<pre>
-/usr/local/lib/sasl2/smtpd.conf:
- pwcheck_method: auxprop
- auxprop_plugin: sql
-</pre>
-</blockquote>
-
<p> IMPORTANT: To get sasldb running, make sure that you set the SASL
domain (realm) to a fully qualified domain name. </p>
<p> EXAMPLE: </p>
<dl>
-<dt> (SASL version 1.5.5)
+<dt> (Cyrus SASL version 1.5.5)
<dd>
<pre>
% saslpasswd -c -u `postconf -h myhostname` exampleuser
</pre>
-<dt> (SASL version 2.1.1)
+<dt> (Cyrus SASL version 2.1.1)
<dd>
<pre>
% saslpasswd2 -c -u `postconf -h myhostname` exampleuser
</dl>
<p> You can find out SASL's idea about the realms of the users
-in sasldb with <i>sasldblistusers</i> (SASL version 1.5.5) or
-<i>sasldblistusers2</i> (SASL version 2.1.1). </p>
+in sasldb with <i>sasldblistusers</i> (Cyrus SASL version 1.5.5) or
+<i>sasldblistusers2</i> (Cyrus SASL version 2.1.1). </p>
<p> On the Postfix side, you can have only one realm per smtpd
instance, and only the users belonging to that realm would be able to
</pre>
</blockquote>
+</ul>
+
+<p> IMPORTANT: all users must be able to authenticate using ALL
+authentication mechanisms advertised by Postfix, otherwise the
+negotiation might end up with an unsupported mechanism, and
+authentication would fail. For example if you configure SASL to
+use <i>saslauthd</i> for authentication against PAM (pluggable
+authentication modules), only the PLAIN and LOGIN mechanisms are
+supported and stand a chance to succeed, yet the SASL library would also
+advertise other mechanisms, such as DIGEST-MD5. This happens because
+those mechanisms are made available by other plugins, and the SASL
+library have no way to know that your only valid authentication source
+is PAM. Thus you might need to limit the list of mechanisms advertised
+by Postfix. </p>
+
+<ul>
+
+<li> <p> With older Cyrus SASL versions you remove the corresponding
+library files from the SASL plug-in directory (and again whenever
+the system is updated). </p>
+
+<li> <p> With Cyrus SASL version 2.1.1 or later: </p>
+
+<blockquote>
+<pre>
+/usr/local/lib/sasl2/smtpd.conf:
+ mech_list: plain login
+</pre>
+</blockquote>
+
+</ul>
+
+<p> For the same reasons you might want to limit the list of plugins
+used for authentication. </p>
+
+<ul>
+
+<li> <p> With Cyrus SASL version 1.5.5 your only choice is to
+delete the corresponding library files from the SASL plug-in
+directory. </p>
+
+<li> <p> With SASL version 2.1.1: </p>
+
+<blockquote>
+<pre>
+/usr/local/lib/sasl2/smtpd.conf:
+ pwcheck_method: auxprop
+ auxprop_plugin: sql
+</pre>
+</blockquote>
+
+</ul>
+
<p> To run software chrooted with SASL support is an interesting
exercise. It probably is not worth the trouble. </p>
</pre>
</blockquote>
+<p> Postfix version 2.3 supports-per-sender SASL password
+information. To search the Postfix SASL password by sender
+before it searches by destination, specify: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ smtp_sender_dependent_authentication = yes
+ smtp_sasl_auth_enable = yes
+ smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
+
+/etc/postfix/sasl_passwd:
+ user@example.com username:password
+ bar.com username
+ [mail.myisp.net] username:password
+ [mail.myisp.net]:submission username:password
+</pre>
+</blockquote>
+
<p> Note: some SMTP servers support PLAIN or LOGIN authentication only.
By default, the Postfix SMTP client does not use authentication
methods that send plaintext passwords, and defers delivery with
<blockquote>
<pre>
/etc/postfix/main.cf:
- smtp_sasl_security_options =
+ smtp_sasl_security_options = noanonymous
</pre>
</blockquote>
-<p> The SASL client password file is opened before the SMTP server
+<p> The Postfix SASL client password file is opened before the SMTP server
enters the optional chroot jail, so you can keep the file in
/etc/postfix. </p>
possess the appropriate credentials to authenticate to the server. It
is possible via the smtp_sasl_mechanism_filter parameter to further
restrict the list of server mechanisms that the smtp(8) client will take
-into consideration. </p>
+into consideration: </p>
+
+<blockquote>
+<pre>
+/etc/postfix/main.cf:
+ smtp_sasl_mechanism_filter = !gssapi, !external, static:all
+</pre>
+</blockquote>
+
+<p> In the above example, Postfix will decline to use mechanisms
+that require special infrastructure such as Kerberos. </p>
<p> The Postfix SMTP client is backwards compatible with SMTP
servers that use the non-standard "AUTH=method..." syntax in response
<li> Wietse trimmed down the code to only the bare necessities.
-<li> Support for SASL version 2 was contributed by Jason Hoos.
+<li> Support for Cyrus SASL version 2 was contributed by Jason Hoos.
<li> Liviu Daia added smtpd_sasl_application_name, split
reject_sender_login_mismatch into
reject_authenticated_sender_login_mismatch and
reject_unauthenticated_sender_login_mismatch, and revised the docs.
+<li> Wietse made another iteration through the code to add
+plug-in support for multiple implementations.
+
</ul>
</body>
client_name=another.domain.tld
reverse_client_name=another.domain.tld
instance=123.456.7
+<b>Postfix version 2.2 and later:</b>
sasl_method=plain
sasl_username=you
sasl_sender=
+size=12345
ccert_subject=solaris9.porcupine.org
ccert_issuer=Wietse Venema
ccert_fingerprint=C2:9D:F4:87:71:73:73:D9:18:E7:C2:F3:C1:DA:6E:04
-size=12345
+<b>Postfix version 2.3 and later:</b>
+encryption_protocol=TLSv1/SSLv3
+encryption_cipher=DHE-RSA-AES256-SHA
+encryption_keysize=256
[empty line]
</pre>
</blockquote>
<li> <p> The "sasl_*" attributes (Postfix 2.2 and later) specify
information about how the client was authenticated via SASL.
+ These attributes are empty in case of no SASL authentication.
</p>
<li> <p> The "ccert_*" attributes (Postfix 2.2 and later) specify
information about how the client was authenticated via TLS.
+ These attributes are empty in case of no certificate authentication.
</p>
+ <li> <p> The "encryption_*" attributes (Postfix 2.3 and later)
+ specify information about how the connection is encrypted. With
+ plaintext connections the protocol and cypher attributes are
+ empty and the keysize is zero. </p>
+
</ul>
<p> The following is specific to SMTPD delegated policy requests:
%PARAM smtp_sasl_security_options noplaintext, noanonymous
-<p>
-What authentication mechanisms the Postfix SMTP client is allowed
-to use. The list of available authentication mechanisms is system
-dependent.
-</p>
+<p> SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL client implementation that is selected
+with <b>smtp_sasl_type</b>. </p>
+
+<p> The following security features are defined for the <b>cyrus</b>
+client SASL implementation: </p>
<p>
Specify zero or more of the following:
response code for rejected requests (default: 550). This feature
is available in Postfix 2.1 and later. </dd>
+<dt><b><a name="reject_plaintext_session">reject_plaintext_session</a></b></dt>
+
+<dd>Reject the request when the connection is not encrypted. This
+restriction should not be used before the client has had a chance
+to negotiate encryption with the AUTH or STARTTLS commands.
+<br>
+The plaintext_session_reject_code parameter specifies the response
+code for rejected requests (default: 450). This feature is available
+in Postfix 2.3 and later. </dd>
+
<dt><b><a name="reject_unauth_pipelining">reject_unauth_pipelining</a></b></dt>
<dd>Reject the request when the client sends SMTP commands ahead
%PARAM smtpd_sasl_security_options noanonymous
+<p> SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL server implementation that is selected
+with <b>smtpd_sasl_type</b>. </p>
+
+<p> The following security features are defined for the <b>cyrus</b>
+server SASL implementation: </p>
+
<p>
Restrict what authentication mechanisms the Postfix SMTP server
will offer to the client. The list of available authentication
%PARAM lmtp_sasl_security_options noplaintext, noanonymous
-<p>
-What authentication mechanisms the Postfix LMTP client is allowed
-to use. The list of available authentication mechanisms is system
-dependent.
-</p>
+<p> SASL security options; as of Postfix 2.3 the list of available
+features depends on the SASL client implementation that is selected
+with <b>lmtp_sasl_type</b>. </p>
+
+<p> The following security features are defined for the <b>cyrus</b>
+client SASL implementation: </p>
<dl>
operations. The time limit is enforced in the client. </p>
<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM smtpd_sasl_type cyrus
+
+<p> The SASL plug-in type that the Postfix SMTP server should use
+for authentication. The available types are listed with the
+"<b>postconf -a</b>" command. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM smtp_sasl_type cyrus
+
+<p> The SASL plug-in type that the Postfix SMTP client should use
+for authentication. The available types are listed with the
+"<b>postconf -A</b>" command. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+
+%PARAM lmtp_sasl_type cyrus
+
+<p> The SASL plug-in type that the Postfix LMTP client should use
+for authentication. The available types are listed with the
+"<b>postconf -A</b>" command. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM smtpd_sasl_path smtpd
+
+<p> Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+<b>smtpd_sasl_type</b>. Typically this specifies the name of a
+configuration file or rendez-vous point. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM smtp_sasl_path
+
+<p> Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+<b>smtp_sasl_type</b>. Typically this specifies the name of a
+configuration file or rendez-vous point. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM lmtp_sasl_path
+
+<p> Implementation-specific information that is passed through to
+the SASL plug-in implementation that is selected with
+<b>lmtp_sasl_type</b>. Typically this specifies the name of a
+configuration file or rendez-vous point. </p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
+
+%PARAM plaintext_session_reject_code 450
+
+<p>
+The numerical Postfix SMTP server response code when a request
+is rejected by the <b>reject_plaintext_session</b> restriction.
+</p>
+
+<p> This feature is available in Postfix 2.3 and later. </p>
#include <string.h>
#include <ctype.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
/* Utility library. */
#include <msg.h>
#include <stdlib.h>
#include <ctype.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
/* Utility library. */
#include <msg.h>
#include <sys_defs.h>
#include <string.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
/* Utility library. */
#include <argv.h>
/* SYNOPSIS
/* #include <dns.h>
/*
-/* int dns_rr_to_sa(rr, port, sa, sa_len)
+/* int dns_rr_to_sa(rr, port, sa, sa_length)
/* DNS_RR *rr;
/* unsigned port;
/* struct sockaddr *sa;
-/* SOCKADDR_SIZE *sa_len;
+/* SOCKADDR_SIZE *sa_length;
/* DESCRIPTION
/* dns_rr_to_sa() converts the address in a DNS resource record into
/* a socket address of the corresponding type.
/* TCP or UDP port, network byte order.
/* .IP sa
/* Socket address pointer.
-/* .IP sa_len
+/* .IP sa_length
/* On input, the available socket address storage space.
/* On output, the amount of space actually used.
/* DIAGNOSTICS
/* dns_rr_to_sa - resource record to socket address */
int dns_rr_to_sa(DNS_RR *rr, unsigned port, struct sockaddr * sa,
- SOCKADDR_SIZE *sa_len)
+ SOCKADDR_SIZE *sa_length)
{
SOCKADDR_SIZE sock_addr_len;
if (rr->data_len != sizeof(SOCK_ADDR_IN_ADDR(sa))) {
errno = EINVAL;
return (-1);
- } else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN_PTR(sa))) > *sa_len) {
+ } else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN_PTR(sa))) > *sa_length) {
errno = ENOSPC;
return (-1);
} else {
#ifdef HAS_SA_LEN
sa->sa_len = sock_addr_len;
#endif
- *sa_len = sock_addr_len;
+ *sa_length = sock_addr_len;
return (0);
}
#ifdef HAS_IPV6
if (rr->data_len != sizeof(SOCK_ADDR_IN6_ADDR(sa))) {
errno = EINVAL;
return (-1);
- } else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN6_PTR(sa))) > *sa_len) {
+ } else if ((sock_addr_len = sizeof(*SOCK_ADDR_IN6_PTR(sa))) > *sa_length) {
errno = ENOSPC;
return (-1);
} else {
#ifdef HAS_SA_LEN
sa->sa_len = sock_addr_len;
#endif
- *sa_len = sock_addr_len;
+ *sa_length = sock_addr_len;
return (0);
}
#endif
MAI_SERVPORT_STR portnum;
struct sockaddr_storage ss;
struct sockaddr *sa = (struct sockaddr *) & ss;
- SOCKADDR_SIZE sa_len = sizeof(ss);
+ SOCKADDR_SIZE sa_length = sizeof(ss);
VSTRING *why;
int type;
int port;
usage();
if (dns_lookup(argv[1], type, 0, &rr, (VSTRING *) 0, why) != DNS_OK)
msg_fatal("%s: %s", argv[1], vstring_str(why));
- sa_len = sizeof(ss);
- if (dns_rr_to_sa(rr, htons(port), sa, &sa_len) != 0)
+ sa_length = sizeof(ss);
+ if (dns_rr_to_sa(rr, htons(port), sa, &sa_length) != 0)
msg_fatal("dns_rr_to_sa: %m");
- SOCKADDR_TO_HOSTADDR(sa, sa_len, &hostaddr, &portnum, 0);
+ SOCKADDR_TO_HOSTADDR(sa, sa_length, &hostaddr, &portnum, 0);
vstream_printf("%s %s -> %s %s\n",
argv[1], argv[2], hostaddr.buf, portnum.buf);
vstream_fflush(VSTREAM_OUT);
deliver_pass.o: ../../include/vbuf.h
deliver_pass.o: ../../include/vstream.h
deliver_pass.o: ../../include/vstring.h
+deliver_pass.o: bounce.h
+deliver_pass.o: defer.h
deliver_pass.o: deliver_pass.c
deliver_pass.o: deliver_pass.h
deliver_pass.o: deliver_request.h
#include <stdio.h>
#include <string.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/* Utility library. */
#include "msg.h"
#include <mail_params.h>
#include <deliver_pass.h>
#include <dsb_scan.h>
+#include <defer.h>
#define DELIVER_PASS_DEFER 1
#define DELIVER_PASS_UNKNOWN 2
#include <ctype.h>
#include <unistd.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/*
* Older APIs have weird memory freeing behavior.
*/
#include <time.h>
#include <mysql.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/* Utility library. */
#include "dict.h"
#define DEF_SMTPD_SASL_OPTS "noanonymous"
extern char *var_smtpd_sasl_opts;
-#define VAR_SMTPD_SASL_APPNAME "smtpd_sasl_application_name"
-#define DEF_SMTPD_SASL_APPNAME "smtpd"
-extern char *var_smtpd_sasl_appname;
+#define VAR_SMTPD_SASL_PATH "smtpd_sasl_path"
+#define DEF_SMTPD_SASL_PATH "smtpd"
+extern char *var_smtpd_sasl_path;
#define VAR_SMTPD_SASL_TLS_OPTS "smtpd_sasl_tls_security_options"
-#define DEF_SMTPD_SASL_TLS_OPTS "$smtpd_sasl_security_options"
+#define DEF_SMTPD_SASL_TLS_OPTS "$" VAR_SMTPD_SASL_OPTS
extern char *var_smtpd_sasl_tls_opts;
#define VAR_SMTPD_SASL_REALM "smtpd_sasl_local_domain"
#define DEF_SMTPD_SASL_EXCEPTIONS_NETWORKS ""
extern char *var_smtpd_sasl_exceptions_networks;
+#ifndef DEF_SERVER_SASL_TYPE
+#define DEF_SERVER_SASL_TYPE "cyrus"
+#endif
+
+#define VAR_SMTPD_SASL_TYPE "smtpd_sasl_type"
+#define DEF_SMTPD_SASL_TYPE DEF_SERVER_SASL_TYPE
+extern char *var_smtpd_sasl_type;
+
#define VAR_SMTPD_SND_AUTH_MAPS "smtpd_sender_login_maps"
#define DEF_SMTPD_SND_AUTH_MAPS ""
extern char *var_smtpd_snd_auth_maps;
#define DEF_SMTP_SASL_OPTS "noplaintext, noanonymous"
extern char *var_smtp_sasl_opts;
+#define VAR_SMTP_SASL_PATH "smtp_sasl_path"
+#define DEF_SMTP_SASL_PATH ""
+extern char *var_smtp_sasl_path;
+
#define VAR_SMTP_SASL_MECHS "smtp_sasl_mechanism_filter"
#define DEF_SMTP_SASL_MECHS ""
#define VAR_LMTP_SASL_MECHS "lmtp_sasl_mechanism_filter"
#define DEF_LMTP_SASL_MECHS ""
extern char *var_smtp_sasl_mechs;
+#ifndef DEF_CLIENT_SASL_TYPE
+#define DEF_CLIENT_SASL_TYPE "cyrus"
+#endif
+
+#define VAR_SMTP_SASL_TYPE "smtp_sasl_type"
+#define DEF_SMTP_SASL_TYPE DEF_CLIENT_SASL_TYPE
+#define VAR_LMTP_SASL_TYPE "lmtp_sasl_type"
+#define DEF_LMTP_SASL_TYPE DEF_CLIENT_SASL_TYPE
+extern char *var_smtp_sasl_type;
+
#define VAR_SMTP_SASL_TLS_OPTS "smtp_sasl_tls_security_options"
-#define DEF_SMTP_SASL_TLS_OPTS "$var_smtp_sasl_opts"
+#define DEF_SMTP_SASL_TLS_OPTS "$" VAR_SMTP_SASL_OPTS
#define VAR_LMTP_SASL_TLS_OPTS "lmtp_sasl_tls_security_options"
-#define DEF_LMTP_SASL_TLS_OPTS "$var_lmtp_sasl_opts"
+#define DEF_LMTP_SASL_TLS_OPTS "$" VAR_LMTP_SASL_OPTS
extern char *var_smtp_sasl_tls_opts;
/*
#define DEF_LMTP_SASL_OPTS "noplaintext, noanonymous"
extern char *var_lmtp_sasl_opts;
+#define VAR_LMTP_SASL_PATH "lmtp_sasl_path"
+#define DEF_LMTP_SASL_PATH ""
+extern char *var_lmtp_sasl_path;
+
/*
* SASL-based relay etc. control.
*/
#define SLEEP "sleep"
+#define REJECT_PLAINTEXT_SESSION "reject_plaintext_session"
+#define VAR_PLAINTEXT_CODE "plaintext_reject_code"
+#define DEF_PLAINTEXT_CODE 450
+extern int var_plaintext_code;
+
#define REJECT_UNKNOWN_CLIENT "reject_unknown_client"
#define REJECT_UNKNOWN_CLIENT_HOSTNAME "reject_unknown_client_hostname"
#define REJECT_UNKNOWN_REVERSE_HOSTNAME "reject_unknown_reverse_client_hostname"
#define MAIL_ATTR_CCERT_SUBJECT "ccert_subject"
#define MAIL_ATTR_CCERT_ISSSUER "ccert_issuer"
#define MAIL_ATTR_CCERT_FINGERPRINT "ccert_fingerprint"
+#define MAIL_ATTR_CRYPTO_PROTOCOL "encryption_protocol"
+#define MAIL_ATTR_CRYPTO_CYPHER "encryption_cipher"
+#define MAIL_ATTR_CRYPTO_KEYSIZE "encryption_keysize"
/*
* Suffixes for sender_name, sender_domain etc.
* Patches change both the patchlevel and the release date. Snapshots have no
* patchlevel; they change the release date only.
*/
-#define MAIL_RELEASE_DATE "20051212"
+#define MAIL_RELEASE_DATE "20051220"
#define MAIL_VERSION_NUMBER "2.3"
#ifdef SNAPSHOT
/* DESCRIPTION
/* .nf
+ /*
+ * System library.
+ */
+#include <ctype.h>
+#include <stdlib.h>
+
/*
* Diagnostic codes, not real record lookup results.
*/
#include <sys_defs.h>
#include <string.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
/* Utility library. */
#include <msg.h>
PROG = postconf
SAMPLES = ../../conf/main.cf.default
INC_DIR = ../../include
-LIBS = ../../lib/libglobal.a ../../lib/libutil.a
+LIBS = ../../lib/libxsasl.a ../../lib/libglobal.a ../../lib/libutil.a
.c.o:; $(CC) $(CFLAGS) -c $*.c
postconf.o: ../../include/vstream.h
postconf.o: ../../include/vstring.h
postconf.o: ../../include/vstring_vstream.h
+postconf.o: ../../include/xsasl.h
postconf.o: auto_table.h
postconf.o: auto_vars.h
postconf.o: bool_table.h
/* Postfix configuration utility
/* SYNOPSIS
/* .fi
-/* \fBpostconf\fR [\fB-dhmlnv\fR] [\fB-c \fIconfig_dir\fR]
+/* \fBpostconf\fR [\fB-dhnv\fR] [\fB-c \fIconfig_dir\fR]
/* [\fIparameter ...\fR]
/*
+/* \fBpostconf\fR [\fB-aAmlv\fR] [\fB-c \fIconfig_dir\fR]
+/*
/* \fBpostconf\fR [\fB-ev\fR] [\fB-c \fIconfig_dir\fR]
/* [\fIparameter=value ...\fR]
/*
/* the Postfix mail system.
/*
/* Options:
+/* .IP \fB-a\fR
+/* List the available SASL server plug-in types. The SASL
+/* plug-in type is selected with the \fBsmtpd_sasl_type\fR
+/* configuration parameter.
+/*
+/* This feature is available with Postfix 2.3 and later.
+/* .IP \fB-A\fR
+/* List the available SASL client plug-in types. The SASL
+/* plug-in type is selected with the \fBsmtp_sasl_type\fR or
+/* \fBlmtp_sasl_type\fR configuration parameters.
+/*
+/* This feature is available with Postfix 2.3 and later.
/* .IP "\fB-b\fR [\fItemplate_file\fR]"
/* Display the message text that appears at the beginning of
/* delivery status notification (DSN) messages, with $\fBname\fR
#include <unistd.h>
#include <ctype.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
#ifdef USE_PATHS_H
#include <paths.h>
#endif
#include <mbox_conf.h>
#include <mail_run.h>
+/* XSASL library. */
+
+#include <xsasl.h>
+
/*
* What we're supposed to be doing.
*/
#define EDIT_MAIN (1<<4) /* edit main.cf */
#define SHOW_LOCKS (1<<5) /* show mailbox lock methods */
#define SHOW_EVAL (1<<6) /* expand right-hand sides */
+#define SHOW_SASL_SERV (1<<7) /* show server auth plugin types */
+#define SHOW_SASL_CLNT (1<<7) /* show client auth plugin types */
/*
* Lookup table for in-core parameter info.
static void show_locks(void)
{
- ARGV *maps_argv;
+ ARGV *locks_argv;
int i;
- maps_argv = mbox_lock_names();
- for (i = 0; i < maps_argv->argc; i++)
- vstream_printf("%s\n", maps_argv->argv[i]);
- argv_free(maps_argv);
+ locks_argv = mbox_lock_names();
+ for (i = 0; i < locks_argv->argc; i++)
+ vstream_printf("%s\n", locks_argv->argv[i]);
+ argv_free(locks_argv);
+}
+
+/* show_sasl - show SASL plug-in types */
+
+static void show_sasl(int what)
+{
+ ARGV *sasl_argv;
+ int i;
+
+ sasl_argv = (what & SHOW_SASL_SERV) ? xsasl_server_types() :
+ xsasl_client_types();
+ for (i = 0; i < sasl_argv->argc; i++)
+ vstream_printf("%s\n", sasl_argv->argv[i]);
+ argv_free(sasl_argv);
}
/* show_parameters - show parameter info */
/*
* Parse JCL.
*/
- while ((ch = GETOPT(argc, argv, "bc:deEhmlntv")) > 0) {
+ while ((ch = GETOPT(argc, argv, "aAbc:deEhmlntv")) > 0) {
switch (ch) {
+ case 'a':
+ mode |= SHOW_SASL_SERV;
+ break;
+ case 'A':
+ mode |= SHOW_SASL_CLNT;
+ break;
case 'b':
if (ext_argv)
msg_fatal("specify one of -b and -t");
msg_verbose++;
break;
default:
- msg_fatal("usage: %s [-b (bounce templates)] [-c config_dir] [-d (defaults)] [-e (edit)] [-h (no names)] [-l (lock types)] [-m (map types)] [-n (non-defaults)] [-v] [name...]", argv[0]);
+ msg_fatal("usage: %s [-a (server SASL types)] [-A (client SASL types)] [-b (bounce templates)] [-c config_dir] [-d (defaults)] [-e (edit)] [-h (no names)] [-l (lock types)] [-m (map types)] [-n (non-defaults)] [-v] [name...]", argv[0]);
}
}
/*
* Sanity check.
*/
- junk = (mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | SHOW_LOCKS | EDIT_MAIN));
+ junk = (mode & (SHOW_DEFS | SHOW_NONDEF | SHOW_MAPS | SHOW_LOCKS | EDIT_MAIN | SHOW_SASL_SERV | SHOW_SASL_CLNT));
if (junk != 0 && ((junk != SHOW_DEFS && junk != SHOW_NONDEF
- && junk != SHOW_MAPS && junk != SHOW_LOCKS && junk != EDIT_MAIN)
+ && junk != SHOW_MAPS && junk != SHOW_LOCKS && junk != EDIT_MAIN
+ && junk != SHOW_SASL_SERV && junk != SHOW_SASL_CLNT)
|| ext_argv != 0))
- msg_fatal("specify one of -b, -d, -e, -m, -l and -n");
+ msg_fatal("specify one of -a, -A, -b, -d, -e, -m, -l and -n");
/*
* Display bounce template information and exit.
show_locks();
}
+ /*
+ * If showing SASL plug-in types, show them and exit
+ */
+ else if (mode & SHOW_SASL_SERV) {
+ show_sasl(SHOW_SASL_SERV);
+ } else if (mode & SHOW_SASL_CLNT) {
+ show_sasl(SHOW_SASL_CLNT);
+ }
+
/*
* Edit main.cf.
*/
* Further initialization...
*/
mail_conf_read();
+ mail_dict_init(); /* proxy, sql, ldap */
get_mail_conf_str_table(str_table);
/*
#include <ctype.h>
#include <stdarg.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
/* Utility library. */
#include <msg.h>
char *myname = "qmqpd_peer_init";
struct sockaddr_storage ss;
struct sockaddr *sa;
- SOCKADDR_SIZE sa_len;
+ SOCKADDR_SIZE sa_length;
INET_PROTO_INFO *proto_info = inet_proto_info();
sa = (struct sockaddr *) & ss;
- sa_len = sizeof(ss);
+ sa_length = sizeof(ss);
/*
* Look up the peer address information.
*/
- if (getpeername(vstream_fileno(state->client), sa, &sa_len) >= 0) {
+ if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
errno = 0;
}
/*
* Convert the client address to printable form.
*/
- if ((aierr = sockaddr_to_hostaddr(sa, sa_len, &client_addr,
+ if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr,
(MAI_SERVPORT_STR *) 0, 0)) != 0)
msg_fatal("%s: cannot convert client address to string: %s",
myname, MAI_STRERROR(aierr));
if (aierr)
msg_fatal("%s: cannot convert %s from string to binary: %s",
myname, state->addr, MAI_STRERROR(aierr));
- sa_len = res0->ai_addrlen;
- if (sa_len > sizeof(ss))
- sa_len = sizeof(ss);
- memcpy((char *) sa, res0->ai_addr, sa_len);
+ sa_length = res0->ai_addrlen;
+ if (sa_length > sizeof(ss))
+ sa_length = sizeof(ss);
+ memcpy((char *) sa, res0->ai_addr, sa_length);
freeaddrinfo(res0);
}
state->name = mystrdup(CLIENT_NAME_UNKNOWN); \
}
- if ((aierr = sockaddr_to_hostname(sa, sa_len, &client_name,
+ if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
(MAI_SERVNAME_STR *) 0, 0)) != 0) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
} else {
PROG = smtp
INC_DIR = ../../include
LIBS = ../../lib/libmaster.a ../../lib/libtls.a ../../lib/libdns.a \
- ../../lib/libglobal.a ../../lib/libutil.a
+ ../../lib/libxsasl.a ../../lib/libglobal.a ../../lib/libutil.a
.c.o:; $(CC) $(CFLAGS) -c $*.c
smtp.o: smtp.c smtp_params.c lmtp_params.c
-lmtp_params.c: smtp_params.c $(INC_DIR)/mail_params.h
+lmtp_params.c: smtp_params.c
egrep -v -f smtp-only smtp_params.c | \
sed 's/SMTP/LMTP/g; s/smtp_\([a-z]*_table\)/lmtp_\1/' >$@
smtp_sasl_glue.o: ../../include/msg.h
smtp_sasl_glue.o: ../../include/msg_stats.h
smtp_sasl_glue.o: ../../include/mymalloc.h
-smtp_sasl_glue.o: ../../include/name_mask.h
smtp_sasl_glue.o: ../../include/recipient_list.h
smtp_sasl_glue.o: ../../include/resolve_clnt.h
smtp_sasl_glue.o: ../../include/scache.h
smtp_sasl_glue.o: ../../include/vbuf.h
smtp_sasl_glue.o: ../../include/vstream.h
smtp_sasl_glue.o: ../../include/vstring.h
+smtp_sasl_glue.o: ../../include/xsasl.h
smtp_sasl_glue.o: smtp.h
smtp_sasl_glue.o: smtp_sasl.h
smtp_sasl_glue.o: smtp_sasl_glue.c
VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_smtp_sasl_passwd, 0, 0,
VAR_LMTP_SASL_OPTS, DEF_LMTP_SASL_OPTS, &var_smtp_sasl_opts, 0, 0,
+ VAR_LMTP_SASL_PATH, DEF_LMTP_SASL_PATH, &var_smtp_sasl_path, 0, 0,
#ifdef USE_TLS
VAR_LMTP_SASL_TLS_OPTS, DEF_LMTP_SASL_TLS_OPTS, &var_smtp_sasl_tls_opts, 0, 0,
#endif
VAR_LMTP_SASL_MECHS, DEF_LMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
+ VAR_LMTP_SASL_TYPE, DEF_LMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0,
VAR_LMTP_BIND_ADDR, DEF_LMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
VAR_LMTP_BIND_ADDR6, DEF_LMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0,
VAR_LMTP_HELO_NAME, DEF_LMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
/* .ad
/* .fi
/* SMTP destinations have the following form:
-/* .IP "\fIdomainname\fR, \fIdomainname\fR:\fIport\fR"
-/* Look up the mail exchangers for the specified domain.
-/* .IP "[\fIhostname\fR], [\fIhostname\fR]:\fIport\fR"
-/* Look up the address of the specified host.
-/* .IP "[\fIaddress\fR], [\fIaddress\fR]:\fIport\fR"
-/* Connect to the host at the specified address. An IPv6
-/* address must be formatted as [\fBipv6\fR:\fIaddress\fR].
-/* .PP
-/* In all the above cases, when no port is specified, look up
-/* the port defined as \fBsmtp\fR in \fBservices\fR(4).
+/* .IP \fIdomainname\fR
+/* .IP \fIdomainname\fR:\fIport\fR
+/* Look up the mail exchangers for the specified domain, and
+/* connect to the specified port (default: \fBsmtp\fR).
+/* .IP [\fIhostname\fR]
+/* .IP [\fIhostname\fR]:\fIport\fR
+/* Look up the address(es) of the specified host, and connect to
+/* the specified port (default: \fBsmtp\fR).
+/* .IP [\fIaddress\fR]
+/* .IP [\fIaddress\fR]:\fIport\fR
+/* Connect to the host at the specified address, and connect
+/* to the specified port (default: \fBsmtp\fR). An IPv6 address
+/* must be formatted as [\fBipv6\fR:\fIaddress\fR].
/* LMTP DESTINATION SYNTAX
/* .ad
/* .fi
/* Connect to the local UNIX-domain server that is bound to the specified
/* \fIpathname\fR. If the process runs chrooted, an absolute pathname
/* is interpreted relative to the Postfix queue directory.
-/* .IP "\fBinet\fR:\fIhostname\fR, \fBinet\fB:\fIhostname\fR:\fIport\fR"
-/* .IP "\fBinet\fR:[\fIaddress\fR], \fBinet\fR:[\fIaddress\fR]:\fIport\fR"
+/* .IP \fBinet\fR:\fIhostname\fR
+/* .IP \fBinet\fB:\fIhostname\fR:\fIport\fR
+/* .IP \fBinet\fR:[\fIaddress\fR]
+/* .IP \fBinet\fR:[\fIaddress\fR]:\fIport\fR
/* Connect to the specified TCP port on the specified local or
/* remote host. If no port is specified, connect to the 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.
+/* An IPv6 address must be formatted as [\fBipv6\fR:\fIaddress\fR].
/* .PP
/* SECURITY
/* .ad
/* CONFIGURATION PARAMETERS
/* .ad
/* .fi
+/* Before Postfix version 2.3, the LMTP client is a separate
+/* program that implements only a subset of the functionality
+/* available with SMTP: there is no support for TLS, and
+/* connections are cached in-process, making it ineffective
+/* when the client is used for multiple domains.
+/*
/* Most smtp_\fIxxx\fR configuration parameters have an
/* lmtp_\fIxxx\fR "ghost" parameter for the equivalent LMTP
/* feature. This document describes only those LMTP-related
/* per remote hostname or domain, or sender address when sender-dependent
/* authentication is enabled.
/* .IP "\fBsmtp_sasl_security_options (noplaintext, noanonymous)\fR"
-/* What authentication mechanisms the Postfix SMTP client is allowed
-/* to use.
+/* SASL security options; as of Postfix 2.3 the list of available
+/* features depends on the SASL client implementation that is selected
+/* with \fBsmtp_sasl_type\fR.
/* .PP
/* Available in Postfix version 2.2 and later:
/* .IP "\fBsmtp_sasl_mechanism_filter (empty)\fR"
/* available only with SASL authentication, and disables SMTP connection
/* caching to ensure that mail from different senders will use the
/* appropriate credentials.
+/* .IP "\fBsmtp_sasl_path (empty)\fR"
+/* Implementation-specific information that is passed through to
+/* the SASL plug-in implementation that is selected with
+/* \fBsmtp_sasl_type\fR.
+/* .IP "\fBsmtp_sasl_type (cyrus)\fR"
+/* The SASL plug-in type that the Postfix SMTP client should use
+/* for authentication.
/* STARTTLS SUPPORT CONTROLS
/* .ad
/* .fi
/* The SMTP client time limit for sending the RSET command, and
/* for receiving the server response.
/* .PP
+/* Available in Postfix version 2.2 and earlier:
+/* .IP "\fBlmtp_cache_connection (yes)\fR"
+/* Keep Postfix LMTP client connections open for up to $max_idle
+/* seconds.
+/* .PP
/* Available in Postfix version 2.2 and later:
/* .IP "\fBsmtp_connection_cache_destinations (empty)\fR"
/* Permanently enable SMTP connection caching for the specified
int var_smtp_always_ehlo;
int var_smtp_never_ehlo;
char *var_smtp_sasl_opts;
+char *var_smtp_sasl_path;
char *var_smtp_sasl_passwd;
bool var_smtp_sasl_enable;
char *var_smtp_sasl_mechs;
+char *var_smtp_sasl_type;
char *var_smtp_bind_addr;
char *var_smtp_bind_addr6;
bool var_smtp_rand_addr;
}
}
-/* pre_exit - pre-exit cleanup */
-
-static void pre_exit(void)
-{
-#ifdef USE_SASL_AUTH
- if (var_smtp_sasl_enable)
- sasl_done();
-#endif
-}
-
/* main - pass control to the single-threaded skeleton */
int main(int argc, char **argv)
MAIL_SERVER_PRE_INIT, pre_init,
MAIL_SERVER_POST_INIT, post_init,
MAIL_SERVER_PRE_ACCEPT, pre_accept,
- MAIL_SERVER_EXIT, pre_exit,
0);
}
/* DESCRIPTION
/* .nf
- /*
- * SASL library.
- */
-#ifdef USE_SASL_AUTH
-#include <sasl.h>
-#include <saslutil.h>
-#endif
-
/*
* Utility library.
*/
char *sasl_mechanism_list; /* server mechanism list */
char *sasl_username; /* client username */
char *sasl_passwd; /* client password */
- sasl_conn_t *sasl_conn; /* SASL internal state */
- VSTRING *sasl_encoded; /* encoding buffer */
- VSTRING *sasl_decoded; /* decoding buffer */
- sasl_callback_t *sasl_callbacks; /* stateful callbacks */
+ struct XSASL_CLIENT *sasl_client; /* SASL internal state */
+ VSTRING *sasl_reply; /* client response */
#endif
/*
* Silly little macros.
*/
#define STR(s) vstring_str(s)
+#define LEN(s) VSTRING_LEN(s)
/* LICENSE
/* .ad
#include "smtp.h"
-#define LEN VSTRING_LEN
-
/* smtp_chat_init - initialize SMTP transaction log */
void smtp_chat_init(SMTP_SESSION *session)
*/
session->error_mask |= MAIL_ERROR_PROTOCOL;
if (session->features & SMTP_FEATURE_PIPELINING) {
- msg_warn("non-SMTP response from %s: %s",
+ msg_warn("non-%s response from %s: %s",
+ (session->state->misc_flags &
+ SMTP_MISC_FLAG_USE_LMTP) ? "LMTP" : "ESMTP",
session->namaddr, STR(session->buffer));
vstream_longjmp(session->stream, SMTP_ERR_PROTO);
}
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 SMTP client: errors from %s",
- var_mail_name, session->namaddr);
+ post_mail_fprintf(notice, "Subject: %s %s client: errors from %s",
+ var_mail_name,
+ (session->state->misc_flags &
+ SMTP_MISC_FLAG_USE_LMTP) ? "LMTP" : "SMTP",
+ session->namaddr);
post_mail_fputs(notice, "");
post_mail_fprintf(notice, "Unexpected response from %s.", session->namaddr);
post_mail_fputs(notice, "");
if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) {
smtp_dsn_update(why, DSN_BY_LOCAL_MTA,
"4.4.0", 421, "421 Lost connection",
- "connect to %s[%s]: server dropped connection without sending the initial SMTP greeting",
+ "connect to %s[%s]: server dropped connection"
+ " without sending the initial greeting",
addr->name, hostaddr.buf);
smtp_errno = SMTP_ERR_RETRY;
vstream_fclose(stream);
* destination argument so the parsing can be destructive.
*/
if ((err = host_port(buf, hostp, (char *) 0, &service, def_service)) != 0)
- msg_fatal("%s in SMTP server description: %s", err, destination);
+ msg_fatal("%s in server description: %s", err, destination);
/*
* Convert service to port number, network byte order.
#include <sys_defs.h>
#include <string.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
/* Utility library. */
#include <msg.h>
VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0,
VAR_SMTP_SASL_PASSWD, DEF_SMTP_SASL_PASSWD, &var_smtp_sasl_passwd, 0, 0,
VAR_SMTP_SASL_OPTS, DEF_SMTP_SASL_OPTS, &var_smtp_sasl_opts, 0, 0,
+ VAR_SMTP_SASL_PATH, DEF_SMTP_SASL_PATH, &var_smtp_sasl_path, 0, 0,
#ifdef USE_TLS
VAR_SMTP_SASL_TLS_OPTS, DEF_SMTP_SASL_TLS_OPTS, &var_smtp_sasl_tls_opts, 0, 0,
#endif
VAR_SMTP_SASL_MECHS, DEF_SMTP_SASL_MECHS, &var_smtp_sasl_mechs, 0, 0,
+ VAR_SMTP_SASL_TYPE, DEF_SMTP_SASL_TYPE, &var_smtp_sasl_type, 1, 0,
VAR_SMTP_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0,
VAR_SMTP_BIND_ADDR6, DEF_SMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0,
VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0,
msg_fatal("%s: setsockopt: %m", myname);
}
if (msg_verbose)
- msg_info("Using ESMTP PIPELINING, TCP send buffer size is %d",
+ msg_info("Using %s PIPELINING, TCP send buffer size is %d",
+ (state->misc_flags &
+ SMTP_MISC_FLAG_USE_LMTP) ? "LMTP" : "ESMTP",
session->sndbufsize);
} else {
session->sndbufsize = 0;
}
#endif
#ifdef USE_SASL_AUTH
- if (var_smtp_sasl_enable && (session->features & SMTP_FEATURE_AUTH))
- return (smtp_sasl_helo_login(state));
+ if (var_smtp_sasl_enable && (session->features & SMTP_FEATURE_AUTH)) {
+ if (session->sasl_mechanism_list != 0)
+ return (smtp_sasl_helo_login(state));
+ else
+ return (smtp_site_fail(state, DSN_BY_LOCAL_MTA,
+ SMTP_RESP_FAKE(&fake, 421, "4.7.0",
+ "421 SASL authentication failed: "
+ "server offered no compatible authentication mechanisms"),
+ "SASL authentication failed: "
+ "server %s offered no compatible authentication mechanisms",
+ session->namaddr));
+ }
#endif
return (0);
/*++
/* NAME
-/* smtp_sasl 3
+/* smtp_sasl_glue 3
/* SUMMARY
/* Postfix SASL interface for SMTP client
/* SYNOPSIS
/* case of unsuccessful authentication, > 0 in case of success.
/* The why argument is updated with a reason for failure.
/* This routine must be called only when smtp_sasl_passwd_lookup()
-/* suceeds.
+/* succeeds.
/*
/* smtp_sasl_cleanup() cleans up. It must be called at the
/* end of every SMTP session that uses SASL authentication.
#include <sys_defs.h>
#include <stdlib.h>
#include <string.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
/*
* Utility library
#include <mymalloc.h>
#include <stringops.h>
#include <split_at.h>
-#include <name_mask.h>
/*
* Global library
#include <maps.h>
#include <mail_addr_find.h>
+ /*
+ * XSASL library.
+ */
+#include <xsasl.h>
+
/*
* Application-specific
*/
#ifdef USE_SASL_AUTH
- /*
- * Authentication security options.
- */
-static NAME_MASK smtp_sasl_sec_mask[] = {
- "noplaintext", SASL_SEC_NOPLAINTEXT,
- "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,
-};
-
- /*
- * 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_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.
*/
*/
STRING_LIST *smtp_sasl_mechs;
-/* smtp_sasl_log - logging call-back routine */
-
-static int smtp_sasl_log(void *unused_context, int priority,
- const char *message)
-{
- switch (priority) {
- case SASL_LOG_ERR: /* unusual errors */
-#ifdef SASL_LOG_WARN /* non-fatal warnings (Cyrus-SASL v2) */
- case SASL_LOG_WARN:
-#endif
-#ifdef SASL_LOG_WARNING /* non-fatal warnings (Cyrus-SASL v1) */
- case SASL_LOG_WARNING:
-#endif
- msg_warn("SASL authentication problem: %s", message);
- break;
-#ifdef SASL_LOG_INFO
- case SASL_LOG_INFO: /* other info (Cyrus-SASL v1) */
- if (msg_verbose)
- msg_info("SASL authentication info: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_NOTE
- case SASL_LOG_NOTE: /* other info (Cyrus-SASL v2) */
- if (msg_verbose)
- msg_info("SASL authentication info: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_FAIL
- case SASL_LOG_FAIL: /* authentication failures
- * (Cyrus-SASL v2) */
- msg_warn("SASL authentication failure: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_DEBUG
- case SASL_LOG_DEBUG: /* more verbose than LOG_NOTE
- * (Cyrus-SASL v2) */
- if (msg_verbose > 1)
- msg_info("SASL authentication debug: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_TRACE
- case SASL_LOG_TRACE: /* traces of internal
- * protocols (Cyrus-SASL v2) */
- if (msg_verbose > 1)
- msg_info("SASL authentication trace: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_PASS
- case SASL_LOG_PASS: /* traces of internal
- * protocols, including
- * passwords (Cyrus-SASL v2) */
- if (msg_verbose > 1)
- msg_info("SASL authentication pass: %s", message);
- break;
-#endif
- }
- return (SASL_OK);
-}
-
-/* smtp_sasl_get_user - username lookup call-back routine */
-
-static int smtp_sasl_get_user(void *context, int unused_id, const char **result,
- unsigned *len)
-{
- char *myname = "smtp_sasl_get_user";
- SMTP_SESSION *session = (SMTP_SESSION *) context;
-
- if (msg_verbose)
- msg_info("%s: %s", myname, session->sasl_username);
-
- /*
- * Sanity check.
- */
- if (session->sasl_passwd == 0)
- msg_panic("%s: no username looked up", myname);
-
- *result = session->sasl_username;
- if (len)
- *len = strlen(session->sasl_username);
- return (SASL_OK);
-}
-
-/* smtp_sasl_get_passwd - password lookup call-back routine */
-
-static int smtp_sasl_get_passwd(sasl_conn_t *conn, void *context,
- int id, sasl_secret_t **psecret)
-{
- char *myname = "smtp_sasl_get_passwd";
- SMTP_SESSION *session = (SMTP_SESSION *) context;
- int len;
-
- if (msg_verbose)
- msg_info("%s: %s", myname, session->sasl_passwd);
-
- /*
- * Sanity check.
- */
- if (!conn || !psecret || id != SASL_CB_PASS)
- return (SASL_BADPARAM);
- if (session->sasl_passwd == 0)
- msg_panic("%s: no password looked up", myname);
-
- /*
- * Convert the password into a counted string.
- */
- len = strlen(session->sasl_passwd);
- if ((*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len)) == 0)
- return (SASL_NOMEM);
- (*psecret)->len = len;
- memcpy((*psecret)->data, session->sasl_passwd, len + 1);
-
- return (SASL_OK);
-}
+ /*
+ * SASL implementation handle.
+ */
+static XSASL_CLIENT_IMPL *smtp_sasl_impl;
/* smtp_sasl_passwd_lookup - password lookup routine */
void smtp_sasl_initialize(void)
{
- /*
- * Global callbacks. These have no per-session context.
- */
- static sasl_callback_t callbacks[] = {
- {SASL_CB_LOG, &smtp_sasl_log, 0},
- {SASL_CB_LIST_END, 0, 0}
- };
-
-#if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \
- || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19))
- int sasl_major;
- int sasl_minor;
- int sasl_step;
-
- /*
- * DLL hell guard.
- */
- sasl_version_info((const char **) 0, (const char **) 0,
- &sasl_major, &sasl_minor,
- &sasl_step, (int *) 0);
- if (sasl_major != SASL_VERSION_MAJOR
-#if 0
- || sasl_minor != SASL_VERSION_MINOR
- || sasl_step != SASL_VERSION_STEP
-#endif
- )
- msg_fatal("incorrect SASL library version. "
- "Postfix was built with include files from version %d.%d.%d, "
- "but the run-time library version is %d.%d.%d",
- SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
- sasl_major, sasl_minor, sasl_step);
-#endif
-
/*
* Sanity check.
*/
- if (smtp_sasl_passwd_map)
+ if (smtp_sasl_passwd_map || smtp_sasl_impl)
msg_panic("smtp_sasl_initialize: repeated call");
if (*var_smtp_sasl_passwd == 0)
msg_fatal("specify a password table via the `%s' configuration parameter",
*/
smtp_sasl_passwd_map = maps_create("smtp_sasl_passwd",
var_smtp_sasl_passwd, DICT_FLAG_LOCK);
- if (sasl_client_init(callbacks) != SASL_OK)
+ if ((smtp_sasl_impl = xsasl_client_init(var_smtp_sasl_type,
+ var_smtp_sasl_path)) == 0)
msg_fatal("SASL library initialization");
/*
void smtp_sasl_connect(SMTP_SESSION *session)
{
+
+ /*
+ * This initialization happens whenever we instantiate an SMTP session
+ * object. We don't instantiate a SASL client until we actually need one.
+ */
session->sasl_mechanism_list = 0;
session->sasl_username = 0;
session->sasl_passwd = 0;
- session->sasl_conn = 0;
- session->sasl_encoded = 0;
- session->sasl_decoded = 0;
- session->sasl_callbacks = 0;
+ session->sasl_client = 0;
+ session->sasl_reply = 0;
}
/* smtp_sasl_start - per-session SASL initialization */
void smtp_sasl_start(SMTP_SESSION *session, const char *sasl_opts_name,
const char *sasl_opts_val)
{
- static sasl_callback_t callbacks[] = {
- {SASL_CB_USER, &smtp_sasl_get_user, 0},
- {SASL_CB_AUTHNAME, &smtp_sasl_get_user, 0},
- {SASL_CB_PASS, &smtp_sasl_get_passwd, 0},
- {SASL_CB_LIST_END, 0, 0}
- };
- sasl_callback_t *cp;
- sasl_security_properties_t sec_props;
-
if (msg_verbose)
msg_info("starting new SASL client");
-
- /*
- * Per-session initialization. Provide each session with its own callback
- * context.
- */
-#define NULL_SECFLAGS 0
-
- session->sasl_callbacks = (sasl_callback_t *) mymalloc(sizeof(callbacks));
- memcpy((char *) session->sasl_callbacks, callbacks, sizeof(callbacks));
- for (cp = session->sasl_callbacks; cp->id != SASL_CB_LIST_END; cp++)
- cp->context = (void *) session;
-
-#define NULL_SERVER_ADDR ((char *) 0)
-#define NULL_CLIENT_ADDR ((char *) 0)
-
- if (SASL_CLIENT_NEW(var_procname, session->host,
- NULL_CLIENT_ADDR, NULL_SERVER_ADDR,
- session->sasl_callbacks, NULL_SECFLAGS,
- (sasl_conn_t **) &session->sasl_conn) != SASL_OK)
- msg_fatal("per-session SASL client initialization");
-
- /*
- * Per-session security properties. XXX This routine is not sufficiently
- * documented. What is the purpose of all this?
- */
- memset(&sec_props, 0L, sizeof(sec_props));
- sec_props.min_ssf = 0;
- sec_props.max_ssf = 0; /* don't allow real SASL
- * security layer */
- sec_props.security_flags = name_mask(sasl_opts_name, smtp_sasl_sec_mask,
- sasl_opts_val);
- sec_props.maxbufsize = 0;
- sec_props.property_names = 0;
- sec_props.property_values = 0;
- if (sasl_setprop(session->sasl_conn, SASL_SEC_PROPS,
- &sec_props) != SASL_OK)
- msg_fatal("set per-session SASL security properties");
-
- /*
- * We use long-lived conversion buffers rather than local variables in
- * order to avoid memory leaks in case of read/write timeout or I/O
- * error.
- */
- session->sasl_encoded = vstring_alloc(10);
- session->sasl_decoded = vstring_alloc(10);
+ if ((session->sasl_client =
+ xsasl_client_create(smtp_sasl_impl, session->stream, var_procname,
+ session->host, sasl_opts_val)) == 0)
+ msg_fatal("SASL per-connection initialization failed");
+ session->sasl_reply = vstring_alloc(20);
}
/* smtp_sasl_authenticate - run authentication protocol */
int smtp_sasl_authenticate(SMTP_SESSION *session, DSN_BUF *why)
{
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;
const char *mechanism;
int result;
char *line;
-#define NO_SASL_SECRET 0
-#define NO_SASL_INTERACTION 0
-#define NO_SASL_LANGLIST ((const char *) 0)
-#define NO_SASL_OUTLANG ((const char **) 0)
+ /*
+ * Sanity check.
+ */
+ if (session->sasl_mechanism_list == 0)
+ msg_panic("%s: no mechanism list", myname);
if (msg_verbose)
msg_info("%s: %s: SASL mechanisms %s",
/*
* Start the client side authentication protocol.
*/
- result = SASL_CLIENT_START((sasl_conn_t *) session->sasl_conn,
- session->sasl_mechanism_list,
- NO_SASL_SECRET, NO_SASL_INTERACTION,
- &clientout, &clientoutlen, &mechanism);
- if (result != SASL_OK && result != SASL_CONTINUE) {
+ result = xsasl_client_first(session->sasl_client,
+ session->sasl_mechanism_list,
+ session->sasl_username,
+ session->sasl_passwd,
+ &mechanism, session->sasl_reply);
+ if (result != XSASL_AUTH_OK) {
dsb_update(why, "4.7.0", DSB_DEF_ACTION, DSB_SKIP_RMTA, DSB_DTYPE_SASL,
- 421, sasl_errstring(result, NO_SASL_LANGLIST,
- NO_SASL_OUTLANG),
+ 421, STR(session->sasl_reply),
"cannot authenticate to server %s: %s",
- session->namaddr,
- sasl_errstring(result, NO_SASL_LANGLIST,
- NO_SASL_OUTLANG));
+ session->namaddr, STR(session->sasl_reply));
return (-1);
}
* sasl_encode64() produces four bytes for each complete or incomplete
* triple of input bytes. Allocate an extra byte for string termination.
*/
-#define ENCODE64_LENGTH(n) ((((n) + 2) / 3) * 4)
-
- if (clientoutlen > 0) {
- if (msg_verbose)
- msg_info("%s: %s: uncoded initial reply: %.*s",
- myname, session->namaddr, (int) clientoutlen, clientout);
- enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
- VSTRING_SPACE(session->sasl_encoded, enc_length);
- if (sasl_encode64(clientout, clientoutlen,
- STR(session->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
+ if (LEN(session->sasl_reply) > 0) {
smtp_chat_cmd(session, "AUTH %s %s", mechanism,
- STR(session->sasl_encoded));
+ STR(session->sasl_reply));
} else {
smtp_chat_cmd(session, "AUTH %s", mechanism);
}
*/
line = resp->str;
(void) mystrtok(&line, "- \t\n"); /* skip over result code */
- serverinlen = strlen(line);
- VSTRING_SPACE(session->sasl_decoded, serverinlen);
- if (SASL_DECODE64(line, serverinlen, STR(session->sasl_decoded),
- serverinlen, &enc_length) != SASL_OK) {
- smtp_dsn_update(why, "5.7.0", DSN_BY_LOCAL_MTA,
- 501, "501 malformed SASL challenge",
- "malformed SASL challenge from server %s",
- session->namaddr);
- return (-1);
+ result = xsasl_client_next(session->sasl_client, line,
+ session->sasl_reply);
+ if (result != XSASL_AUTH_OK) {
+ dsb_update(why, "4.7.0", DSB_DEF_ACTION, /* Fix 200512 */
+ DSB_SKIP_RMTA, DSB_DTYPE_SASL,
+ 421, STR(session->sasl_reply),
+ "cannot authenticate to server %s: %s",
+ session->namaddr, STR(session->sasl_reply));
+ return (-1); /* Fix 200512 */
}
- if (msg_verbose)
- msg_info("%s: %s: decoded challenge: %.*s",
- myname, session->namaddr, (int) enc_length,
- STR(session->sasl_decoded));
- result = sasl_client_step((sasl_conn_t *) session->sasl_conn,
- STR(session->sasl_decoded), enc_length,
- NO_SASL_INTERACTION, &clientout, &clientoutlen);
- if (result != SASL_OK && result != SASL_CONTINUE)
- msg_warn("SASL authentication failed to server %s: %s",
- session->namaddr, sasl_errstring(result, NO_SASL_LANGLIST,
- NO_SASL_OUTLANG));
/*
* Send a client response.
*/
- if (clientoutlen > 0) {
- if (msg_verbose)
- msg_info("%s: %s: uncoded client response %.*s",
- myname, session->namaddr,
- (int) clientoutlen, clientout);
- enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
- VSTRING_SPACE(session->sasl_encoded, enc_length);
- if (sasl_encode64(clientout, clientoutlen,
- STR(session->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(session->sasl_encoded, "");
- }
- smtp_chat_cmd(session, "%s", STR(session->sasl_encoded));
+ smtp_chat_cmd(session, "%s", STR(session->sasl_reply));
}
/*
myfree(session->sasl_mechanism_list);
session->sasl_mechanism_list = 0;
}
- if (session->sasl_conn) {
+ if (session->sasl_client) {
if (msg_verbose)
msg_info("disposing SASL state information");
- sasl_dispose(&session->sasl_conn);
- }
- if (session->sasl_callbacks) {
- myfree((char *) session->sasl_callbacks);
- session->sasl_callbacks = 0;
- }
- if (session->sasl_encoded) {
- vstring_free(session->sasl_encoded);
- session->sasl_encoded = 0;
+ xsasl_client_free(session->sasl_client);
+ session->sasl_client = 0;
}
- if (session->sasl_decoded) {
- vstring_free(session->sasl_decoded);
- session->sasl_decoded = 0;
+ if (session->sasl_reply) {
+ vstring_free(session->sasl_reply);
+ session->sasl_reply = 0;
}
}
}
if (strlen(mech_list) > 0) {
session->sasl_mechanism_list = mystrdup(mech_list);
- session->features |= SMTP_FEATURE_AUTH;
} else {
msg_warn(*words ? "%s offered no supported AUTH mechanisms: '%s'" :
"%s offered null AUTH mechanism list",
session->namaddr, words);
}
+ session->features |= SMTP_FEATURE_AUTH;
}
/* smtp_sasl_helo_login - perform SASL login */
PROG = smtpd
INC_DIR = ../../include
LIBS = ../../lib/libmaster.a ../../lib/libtls.a ../../lib/libdns.a \
- ../../lib/libglobal.a ../../lib/libutil.a
+ ../../lib/libxsasl.a ../../lib/libglobal.a ../../lib/libutil.a
.c.o:; $(CC) $(CFLAGS) -c $*.c
smtpd_sasl_glue.o: ../../include/argv.h
smtpd_sasl_glue.o: ../../include/mail_params.h
smtpd_sasl_glue.o: ../../include/mail_stream.h
-smtpd_sasl_glue.o: ../../include/match_list.h
-smtpd_sasl_glue.o: ../../include/match_ops.h
smtpd_sasl_glue.o: ../../include/msg.h
smtpd_sasl_glue.o: ../../include/myaddrinfo.h
smtpd_sasl_glue.o: ../../include/mymalloc.h
-smtpd_sasl_glue.o: ../../include/namadr_list.h
-smtpd_sasl_glue.o: ../../include/name_mask.h
-smtpd_sasl_glue.o: ../../include/smtp_stream.h
smtpd_sasl_glue.o: ../../include/stringops.h
smtpd_sasl_glue.o: ../../include/sys_defs.h
smtpd_sasl_glue.o: ../../include/tls.h
smtpd_sasl_glue.o: ../../include/vbuf.h
smtpd_sasl_glue.o: ../../include/vstream.h
smtpd_sasl_glue.o: ../../include/vstring.h
+smtpd_sasl_glue.o: ../../include/xsasl.h
smtpd_sasl_glue.o: smtpd.h
smtpd_sasl_glue.o: smtpd_chat.h
smtpd_sasl_glue.o: smtpd_sasl_glue.c
/* version of the AUTH command (RFC 2554).
/* .IP "\fBsmtpd_sasl_auth_enable (no)\fR"
/* Enable SASL authentication in the Postfix SMTP server.
-/* .IP "\fBsmtpd_sasl_application_name (smtpd)\fR"
-/* The application name used for SASL server initialization.
/* .IP "\fBsmtpd_sasl_local_domain (empty)\fR"
/* The name of the local SASL authentication realm.
/* .IP "\fBsmtpd_sasl_security_options (noanonymous)\fR"
-/* Restrict what authentication mechanisms the Postfix SMTP server
-/* will offer to the client.
+/* SASL security options; as of Postfix 2.3 the list of available
+/* features depends on the SASL server implementation that is selected
+/* with \fBsmtpd_sasl_type\fR.
/* .IP "\fBsmtpd_sender_login_maps (empty)\fR"
/* Optional lookup table with the SASL login names that own sender
/* (MAIL FROM) addresses.
/* .IP "\fBsmtpd_sasl_authenticated_header (no)\fR"
/* Report the SASL authenticated user name in the \fBsmtpd\fR(8) Received
/* message header.
+/* .IP "\fBsmtpd_sasl_path (smtpd)\fR"
+/* Implementation-specific information that is passed through to
+/* the SASL plug-in implementation that is selected with
+/* \fBsmtpd_sasl_type\fR.
+/* .IP "\fBsmtpd_sasl_type (cyrus)\fR"
+/* The SASL plug-in type that the Postfix SMTP server should use
+/* for authentication.
/* STARTTLS SUPPORT CONTROLS
/* .ad
/* .fi
/* The numerical Postfix SMTP server reply code when a client request
/* is rejected by the reject_non_fqdn_helo_hostname, reject_non_fqdn_sender
/* or reject_non_fqdn_recipient restriction.
+/* .IP "\fBplaintext_reject_code (450)\fR"
+/* The numerical Postfix SMTP server response code when a request
+/* is rejected by the \fBreject_plaintext_session\fR restriction.
/* .IP "\fBreject_code (554)\fR"
/* The numerical Postfix SMTP server response code when a remote SMTP
/* client request is rejected by the "reject" restriction.
bool var_smtpd_sasl_enable;
bool var_smtpd_sasl_auth_hdr;
char *var_smtpd_sasl_opts;
-char *var_smtpd_sasl_appname;
+char *var_smtpd_sasl_path;
char *var_smtpd_sasl_realm;
char *var_smtpd_sasl_exceptions_networks;
+char *var_smtpd_sasl_type;
char *var_filter_xport;
bool var_broken_auth_clients;
char *var_perm_mx_networks;
#endif
bool var_smtpd_peername_lookup;
+int var_plaintext_code;
/*
* Silly little macros.
VAR_VIRT_ALIAS_CODE, DEF_VIRT_ALIAS_CODE, &var_virt_alias_code, 0, 0,
VAR_VIRT_MAILBOX_CODE, DEF_VIRT_MAILBOX_CODE, &var_virt_mailbox_code, 0, 0,
VAR_RELAY_RCPT_CODE, DEF_RELAY_RCPT_CODE, &var_relay_rcpt_code, 0, 0,
+ VAR_PLAINTEXT_CODE, DEF_PLAINTEXT_CODE, &var_plaintext_code, 0, 0,
VAR_VERIFY_POLL_COUNT, DEF_VERIFY_POLL_COUNT, &var_verify_poll_count, 1, 0,
VAR_SMTPD_CRATE_LIMIT, DEF_SMTPD_CRATE_LIMIT, &var_smtpd_crate_limit, 0, 0,
VAR_SMTPD_CCONN_LIMIT, DEF_SMTPD_CCONN_LIMIT, &var_smtpd_cconn_limit, 0, 0,
VAR_ALIAS_MAPS, DEF_ALIAS_MAPS, &var_alias_maps, 0, 0,
VAR_LOCAL_RCPT_MAPS, DEF_LOCAL_RCPT_MAPS, &var_local_rcpt_maps, 0, 0,
VAR_SMTPD_SASL_OPTS, DEF_SMTPD_SASL_OPTS, &var_smtpd_sasl_opts, 0, 0,
- VAR_SMTPD_SASL_APPNAME, DEF_SMTPD_SASL_APPNAME, &var_smtpd_sasl_appname, 1, 0,
+ VAR_SMTPD_SASL_PATH, DEF_SMTPD_SASL_PATH, &var_smtpd_sasl_path, 1, 0,
VAR_SMTPD_SASL_REALM, DEF_SMTPD_SASL_REALM, &var_smtpd_sasl_realm, 0, 0,
VAR_SMTPD_SASL_EXCEPTIONS_NETWORKS, DEF_SMTPD_SASL_EXCEPTIONS_NETWORKS, &var_smtpd_sasl_exceptions_networks, 0, 0,
VAR_FILTER_XPORT, DEF_FILTER_XPORT, &var_filter_xport, 0, 0,
VAR_RELAY_CCERTS, DEF_RELAY_CCERTS, &var_smtpd_relay_ccerts, 0, 0,
VAR_SMTPD_SASL_TLS_OPTS, DEF_SMTPD_SASL_TLS_OPTS, &var_smtpd_sasl_tls_opts, 0, 0,
#endif
+ VAR_SMTPD_SASL_TYPE, DEF_SMTPD_SASL_TYPE, &var_smtpd_sasl_type, 1, 0,
0,
};
static CONFIG_RAW_TABLE raw_table[] = {
#include <sys/time.h>
#include <unistd.h>
- /*
- * SASL library.
- */
-#ifdef USE_SASL_AUTH
-#include <sasl.h>
-#include <saslutil.h>
-#endif
-
/*
* Utility library.
*/
* SASL specific.
*/
#ifdef USE_SASL_AUTH
-#if SASL_VERSION_MAJOR >= 2
- const char *sasl_mechanism_list;
-#else
+ struct XSASL_SERVER *sasl_server;
+ VSTRING *sasl_reply;
char *sasl_mechanism_list;
-#endif
char *sasl_method;
char *sasl_username;
char *sasl_sender;
- sasl_conn_t *sasl_conn;
- VSTRING *sasl_encoded;
- VSTRING *sasl_decoded;
#endif
/*
return (SMTPD_CHECK_DUNNO);
}
+/* reject_plaintext_session - fail if session is not encrypted */
+
+static int reject_plaintext_session(SMTPD_STATE *state)
+{
+#ifdef USE_TLS
+ char *myname = "reject_plaintext_session";
+
+ if (msg_verbose)
+ msg_info("%s: %s %s", myname, state->name, state->addr);
+
+ if (state->tls_context == 0)
+ return (smtpd_check_reject(state, MAIL_ERROR_POLICY,
+ var_plaintext_code, "4.7.1",
+ "Session encryption is required"));
+#endif
+ return (SMTPD_CHECK_DUNNO);
+}
+
/* permit_inet_interfaces - succeed if client my own address */
static int permit_inet_interfaces(SMTPD_STATE *state)
IF_VERIFIED(state->tls_context->issuer_CN),
ATTR_TYPE_STR, MAIL_ATTR_CCERT_FINGERPRINT,
IF_VERIFIED(state->tls_context->peer_fingerprint),
+#define IF_ENCRYPTED(x) ((state->tls_context && ((x) != 0)) ? (x) : "")
+ ATTR_TYPE_STR, MAIL_ATTR_CRYPTO_PROTOCOL,
+ IF_ENCRYPTED(state->tls_context->protocol),
+ ATTR_TYPE_STR, MAIL_ATTR_CRYPTO_CYPHER,
+ IF_ENCRYPTED(state->tls_context->cipher_name),
+ ATTR_TYPE_NUM, MAIL_ATTR_CRYPTO_KEYSIZE,
+ state->tls_context->cipher_usebits,
#endif
ATTR_TYPE_END,
ATTR_FLAG_MISSING, /* Reply attributes. */
"Server configuration error"));
} else
sleep(atoi(*++cpp));
+#endif
+#ifdef USE_TLS
+ } else if (strcasecmp(name, REJECT_PLAINTEXT_SESSION) == 0) {
+ status = reject_plaintext_session(state);
#endif
}
void smtpd_peer_init(SMTPD_STATE *state)
{
char *myname = "smtpd_peer_init";
- SOCKADDR_SIZE sa_len;
+ SOCKADDR_SIZE sa_length;
struct sockaddr *sa;
INET_PROTO_INFO *proto_info = inet_proto_info();
sa = (struct sockaddr *) & (state->sockaddr);
- sa_len = sizeof(state->sockaddr);
+ sa_length = sizeof(state->sockaddr);
/*
* Look up the peer address information.
*/
- if (getpeername(vstream_fileno(state->client), sa, &sa_len) >= 0) {
+ if (getpeername(vstream_fileno(state->client), sa, &sa_length) >= 0) {
errno = 0;
}
/*
* Convert the client address to printable form.
*/
- if ((aierr = sockaddr_to_hostaddr(sa, sa_len, &client_addr,
+ if ((aierr = sockaddr_to_hostaddr(sa, sa_length, &client_addr,
(MAI_SERVPORT_STR *) 0, 0)) != 0)
msg_fatal("%s: cannot convert client address to string: %s",
myname, MAI_STRERROR(aierr));
if (aierr)
msg_fatal("%s: cannot convert %s from string to binary: %s",
myname, state->addr, MAI_STRERROR(aierr));
- sa_len = res0->ai_addrlen;
- if (sa_len > sizeof(state->sockaddr))
- sa_len = sizeof(state->sockaddr);
- memcpy((char *) sa, res0->ai_addr, sa_len);
+ sa_length = res0->ai_addrlen;
+ if (sa_length > sizeof(state->sockaddr))
+ sa_length = sizeof(state->sockaddr);
+ memcpy((char *) sa, res0->ai_addr, sa_length);
freeaddrinfo(res0); /* 200412 */
}
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
state->name_status = SMTPD_PEER_CODE_PERM;
state->reverse_name_status = SMTPD_PEER_CODE_PERM;
- } else if ((aierr = sockaddr_to_hostname(sa, sa_len, &client_name,
+ } else if ((aierr = sockaddr_to_hostname(sa, sa_length, &client_name,
(MAI_SERVNAME_STR *) 0, 0)) != 0) {
state->name = mystrdup(CLIENT_NAME_UNKNOWN);
state->reverse_name = mystrdup(CLIENT_NAME_UNKNOWN);
#include <sys_defs.h>
#include <ctype.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/* Utility library. */
#include <msg.h>
/* SYNOPSIS
/* #include "smtpd_sasl_glue.h"
/*
-/* void smtpd_sasl_initialize()
+/* void smtpd_sasl_initialize()
/*
/* void smtpd_sasl_connect(state, sasl_opts_name, sasl_opts_val)
/* SMTPD_STATE *state;
+/* const char *sasl_opts_name;
+/* const char *sasl_opts_val;
/*
/* char *smtpd_sasl_authenticate(state, sasl_method, init_response)
/* SMTPD_STATE *state;
/* are the postfix configuration parameters setting the security
/* policy of the SASL authentication.
/*
-/* smtpd_sasl_authenticate() implements the authentication dialog.
-/* The result is a null pointer in case of success, an SMTP reply
-/* in case of failure. smtpd_sasl_authenticate() updates the
-/* following state structure members:
+/* smtpd_sasl_authenticate() implements the authentication
+/* dialog. The result is zero in case of success, -1 in case
+/* of failure. smtpd_sasl_authenticate() updates the following
+/* state structure members:
/* .IP sasl_method
/* The authentication method that was successfully applied.
/* This member is a null pointer in the absence of successful
/* Arguments:
/* .IP state
/* SMTP session context.
+/* .IP sasl_opts_name
+/* Security options parameter name.
+/* .IP sasl_opts_val
+/* Security options parameter value.
/* .IP sasl_method
/* A SASL mechanism name
/* .IP init_reply
#include <msg.h>
#include <mymalloc.h>
-#include <namadr_list.h>
-#include <name_mask.h>
#include <stringops.h>
/* Global library. */
#include <mail_params.h>
-#include <smtp_stream.h>
+
+/* XSASL library. */
+
+#include <xsasl.h>
/* Application-specific. */
#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.
+ * SASL server implementation handle.
*/
-
-#if SASL_VERSION_MAJOR < 2
-/* SASL version 1.x */
-#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: /* unusual errors */
-#ifdef SASL_LOG_WARN /* non-fatal warnings (Cyrus-SASL v2) */
- case SASL_LOG_WARN:
-#endif
-#ifdef SASL_LOG_WARNING /* non-fatal warnings (Cyrus-SASL v1) */
- case SASL_LOG_WARNING:
-#endif
- msg_warn("SASL authentication problem: %s", message);
- break;
-#ifdef SASL_LOG_INFO
- case SASL_LOG_INFO: /* other info (Cyrus-SASL v1) */
- if (msg_verbose)
- msg_info("SASL authentication info: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_NOTE
- case SASL_LOG_NOTE: /* other info (Cyrus-SASL v2) */
- if (msg_verbose)
- msg_info("SASL authentication info: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_FAIL
- case SASL_LOG_FAIL: /* authentication failures
- * (Cyrus-SASL v2) */
- msg_warn("SASL authentication failure: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_DEBUG
- case SASL_LOG_DEBUG: /* more verbose than LOG_NOTE
- * (Cyrus-SASL v2) */
- if (msg_verbose > 1)
- msg_info("SASL authentication debug: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_TRACE
- case SASL_LOG_TRACE: /* traces of internal
- * protocols (Cyrus-SASL v2) */
- if (msg_verbose > 1)
- msg_info("SASL authentication trace: %s", message);
- break;
-#endif
-#ifdef SASL_LOG_PASS
- case SASL_LOG_PASS: /* traces of internal
- * protocols, including
- * passwords (Cyrus-SASL v2) */
- if (msg_verbose > 1)
- msg_info("SASL authentication pass: %s", message);
- break;
-#endif
- }
- return (SASL_OK);
-}
-
- /*
- * SASL callback interface structure. These call-backs have no per-session
- * context.
- */
-#define NO_CALLBACK_CONTEXT 0
-
-static sasl_callback_t callbacks[] = {
- {SASL_CB_LOG, &smtpd_sasl_log, NO_CALLBACK_CONTEXT},
- {SASL_CB_LIST_END, 0, 0}
-};
-
-static NAME_MASK smtpd_sasl_mask[] = {
- "noplaintext", SASL_SEC_NOPLAINTEXT,
- "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,
-};
+static XSASL_SERVER_IMPL *smtpd_sasl_impl;
/* smtpd_sasl_initialize - per-process initialization */
void smtpd_sasl_initialize(void)
{
-#if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \
- || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19))
- int sasl_major;
- int sasl_minor;
- int sasl_step;
/*
- * DLL hell guard.
+ * Sanity check.
*/
- sasl_version_info((const char **) 0, (const char **) 0,
- &sasl_major, &sasl_minor,
- &sasl_step, (int *) 0);
- if (sasl_major != SASL_VERSION_MAJOR
-#if 0
- || sasl_minor != SASL_VERSION_MINOR
- || sasl_step != SASL_VERSION_STEP
-#endif
- )
- msg_fatal("incorrect SASL library version. "
- "Postfix was built with include files from version %d.%d.%d, "
- "but the run-time library version is %d.%d.%d",
- SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
- sasl_major, sasl_minor, sasl_step);
-#endif
+ if (smtpd_sasl_impl)
+ msg_panic("smtpd_sasl_initialize: repeated call");
/*
- * Initialize the library: load SASL plug-in routines, etc.
+ * Initialize the SASL library.
*/
- if (msg_verbose)
- msg_info("smtpd_sasl_initialize: SASL config file is %s.conf",
- var_smtpd_sasl_appname);
- if (sasl_server_init(callbacks, var_smtpd_sasl_appname) != SASL_OK)
+ if ((smtpd_sasl_impl = xsasl_server_init(var_smtpd_sasl_type,
+ var_smtpd_sasl_path)) == 0)
msg_fatal("SASL per-process initialization failed");
}
void smtpd_sasl_connect(SMTPD_STATE *state, const char *sasl_opts_name,
const char *sasl_opts_val)
{
-#if SASL_VERSION_MAJOR < 2
- unsigned sasl_mechanism_count;
-
-#else
- int sasl_mechanism_count;
-
-#endif
- sasl_security_properties_t sec_props;
- char *server_address;
- char *client_address;
+ const char *mechanism_list;
/*
* Initialize SASL-specific state variables. Use long-lived storage for
* memory leaks when a read or write routine returns abnormally after
* timeout or I/O error.
*/
+ state->sasl_reply = vstring_alloc(20);
state->sasl_mechanism_list = 0;
state->sasl_username = 0;
state->sasl_method = 0;
state->sasl_sender = 0;
- state->sasl_conn = 0;
- state->sasl_decoded = vstring_alloc(10);
- state->sasl_encoded = vstring_alloc(10);
/*
* Set up a new server context for this connection.
*/
-#define NO_SECURITY_LAYERS (0)
-#define NO_SESSION_CALLBACKS ((sasl_callback_t *) 0)
-#define NO_AUTH_REALM ((char *) 0)
-
-#if SASL_VERSION_MAJOR >= 2 && defined(USE_SASL_IP_AUTH)
-
- /*
- * Get IP addresses of local and remote endpoints for SASL.
- */
-#error "USE_SASL_IP_AUTH is not implemented"
-
-#else
-
- /*
- * Don't give any IP address information to SASL. SASLv1 doesn't use it,
- * and in SASLv2 this will disable any mechaniams that do.
- */
- server_address = 0;
- client_address = 0;
-#endif
-
- if (SASL_SERVER_NEW("smtp", var_myhostname, *var_smtpd_sasl_realm ?
- var_smtpd_sasl_realm : NO_AUTH_REALM,
- server_address, client_address,
- NO_SESSION_CALLBACKS, NO_SECURITY_LAYERS,
- &state->sasl_conn) != SASL_OK)
- msg_fatal("SASL per-connection server initialization");
+#define SMTPD_SASL_SERVICE "smtp"
- /*
- * 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;
- sec_props.max_ssf = 0; /* don't allow real SASL
- * security layer */
- sec_props.security_flags = name_mask(sasl_opts_name, smtpd_sasl_mask,
- sasl_opts_val);
- sec_props.maxbufsize = 0;
- sec_props.property_names = 0;
- sec_props.property_values = 0;
-
- if (sasl_setprop(state->sasl_conn, SASL_SEC_PROPS,
- &sec_props) != SASL_OK)
- msg_fatal("SASL per-connection security setup");
+ if ((state->sasl_server =
+ xsasl_server_create(smtpd_sasl_impl, state->client,
+ SMTPD_SASL_SERVICE, *var_smtpd_sasl_realm ?
+ var_smtpd_sasl_realm : (char *) 0,
+ sasl_opts_val)) == 0)
+ msg_fatal("SASL per-connection initialization failed");
/*
* Get the list of authentication mechanisms.
*/
-#define UNSUPPORTED_USER ((char *) 0)
-#define IGNORE_MECHANISM_LEN ((unsigned *) 0)
-
- if (sasl_listmech(state->sasl_conn, UNSUPPORTED_USER,
- "", " ", "",
- &state->sasl_mechanism_list,
- IGNORE_MECHANISM_LEN,
- &sasl_mechanism_count) != SASL_OK)
- msg_fatal("cannot lookup SASL authentication mechanisms");
- if (sasl_mechanism_count <= 0)
+ if ((mechanism_list =
+ xsasl_server_get_mechanism_list(state->sasl_server)) == 0)
msg_fatal("no SASL authentication mechanisms");
+ state->sasl_mechanism_list = mystrdup(mechanism_list);
}
/* smtpd_sasl_disconnect - per-connection cleanup */
void smtpd_sasl_disconnect(SMTPD_STATE *state)
{
+ if (state->sasl_reply) {
+ vstring_free(state->sasl_reply);
+ state->sasl_reply = 0;
+ }
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
+ myfree(state->sasl_mechanism_list);
state->sasl_mechanism_list = 0;
}
- if (state->sasl_conn) {
- sasl_dispose(&state->sasl_conn);
- state->sasl_conn = 0;
+ if (state->sasl_username) {
+ myfree(state->sasl_username);
+ state->sasl_username = 0;
+ }
+ if (state->sasl_method) {
+ myfree(state->sasl_method);
+ state->sasl_method = 0;
+ }
+ if (state->sasl_sender) {
+ myfree(state->sasl_sender);
+ state->sasl_sender = 0;
+ }
+ if (state->sasl_server) {
+ xsasl_server_free(state->sasl_server);
+ state->sasl_server = 0;
}
- vstring_free(state->sasl_decoded);
- vstring_free(state->sasl_encoded);
}
/* smtpd_sasl_authenticate - per-session authentication */
-char *smtpd_sasl_authenticate(SMTPD_STATE *state,
+int smtpd_sasl_authenticate(SMTPD_STATE *state,
const char *sasl_method,
const char *init_response)
{
- char *myname = "smtpd_sasl_authenticate";
- char *dec_buffer;
- unsigned dec_length;
- unsigned enc_length;
- unsigned enc_length_out;
- unsigned reply_len;
- 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))
-
- if (msg_verbose)
- msg_info("%s: sasl_method %s%s%s", myname, sasl_method,
- IFELSE(init_response, ", init_response ", ""),
- IFELSE(init_response, init_response, ""));
-
- /*
- * Sanity check.
- */
- if (state->sasl_username || state->sasl_method)
- msg_panic("%s: already authenticated", myname);
+ int status;
+ const char *sasl_username;
/*
* SASL authentication protocol start-up. Process any initial client
* response that was sent along in the AUTH command.
*/
- if (init_response) {
- 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, reply_len, &dec_length) != SASL_OK)
- return ("501 5.7.0 Authentication failed: malformed initial response");
- if (msg_verbose)
- msg_info("%s: decoded initial response %s", myname, dec_buffer);
- } else {
- dec_buffer = 0;
- dec_length = 0;
- }
- result = SASL_SERVER_START(state->sasl_conn, sasl_method, dec_buffer,
- dec_length, &serverout, &serveroutlen, &errstr);
-
- /*
- * Repeat until done or until the client gives up.
- */
- while (result == SASL_CONTINUE) {
+ for (status = xsasl_server_first(state->sasl_server, sasl_method,
+ init_response, state->sasl_reply);
+ status == XSASL_AUTH_MORE;
+ status = xsasl_server_next(state->sasl_server, STR(state->buffer),
+ state->sasl_reply)) {
/*
- * Send a server challenge. Avoid storing the challenge in a local
- * variable, because we would leak memory when smtpd_chat_reply()
- * does not return due to timeout or I/O error. sasl_encode64()
- * null-terminates the result if the result buffer is large enough.
- *
- * Regarding the hairy expression below: output from sasl_encode64()
- * 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.
+ * Send a server challenge.
*/
- if (msg_verbose)
- msg_info("%s: uncoded challenge: %.*s",
- myname, (int) serveroutlen, serverout);
- enc_length = ((serveroutlen + 2) / 3) * 4 + 1;
- VSTRING_SPACE(state->sasl_encoded, enc_length);
- 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));
+ smtpd_chat_reply(state, "334 %s", STR(state->sasl_reply));
/*
* Receive the client response. "*" means that the client gives up.
- * XXX For now we ignore the fact that excessively long responses
- * will be truncated. To handle such responses, we need to change
- * smtpd_chat_query() so that it returns an error indication.
+ * XXX For now we ignore the fact that an excessively long response
+ * will be chopped into multiple reponses. To handle such responses,
+ * we need to change smtpd_chat_query() so that it returns an error
+ * indication.
*/
smtpd_chat_query(state);
- if (strcmp(vstring_str(state->buffer), "*") == 0)
- return ("501 5.7.0 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), reply_len,
- &dec_length) != SASL_OK)
- return ("501 5.7.0 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),
- dec_length, &serverout, &serveroutlen, &errstr);
+ if (strcmp(STR(state->buffer), "*") == 0) {
+ msg_warn("%s[%s]: SASL %s authentication aborted",
+ state->name, state->addr, sasl_method);
+ smtpd_chat_reply(state, "501 5.7.0 Authentication aborted");
+ return (-1);
+ }
}
-
- /*
- * Cleanup. What an awful interface.
- */
-#if SASL_VERSION_MAJOR < 2
- if (serverout)
- free(serverout);
-#endif
-
- /*
- * The authentication protocol was completed.
- */
- if (result != SASL_OK)
- return ("535 5.7.0 Error: authentication failed");
-
- /*
- * Authentication succeeded. Find out the login name for logging and for
- * 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);
+ if (status != XSASL_AUTH_DONE) {
+ msg_warn("%s[%s]: SASL %s authentication failed: %s",
+ state->name, state->addr, sasl_method,
+ STR(state->sasl_reply));
+ smtpd_chat_reply(state, "535 5.7.0 Error: authentication failed: %s",
+ STR(state->sasl_reply));
+ return (-1);
+ }
+ smtpd_chat_reply(state, "235 2.0.0 Authentication successful");
+ if ((sasl_username = xsasl_server_get_username(state->sasl_server)) == 0)
+ msg_panic("cannot look up the authenticated SASL username");
+ state->sasl_username = mystrdup(sasl_username);
printable(state->sasl_username, '?');
state->sasl_method = mystrdup(sasl_method);
printable(state->sasl_method, '?');
/* SUMMARY
/* Postfix SMTP server, SASL support interface
/* SYNOPSIS
-/* #include "smtpd_sasl.h"
+/* #include "smtpd_sasl_glue.h"
/* DESCRIPTION
/* .nf
extern void smtpd_sasl_initialize(void);
extern void smtpd_sasl_connect(SMTPD_STATE *, const char *, const char *);
extern void smtpd_sasl_disconnect(SMTPD_STATE *);
-extern char *smtpd_sasl_authenticate(SMTPD_STATE *, const char *, const char *);
+extern int smtpd_sasl_authenticate(SMTPD_STATE *, const char *, const char *);
extern void smtpd_sasl_logout(SMTPD_STATE *);
extern int permit_sasl_auth(SMTPD_STATE *, int, int);
/* Postfix SMTP protocol support for SASL authentication
/* SYNOPSIS
/* #include "smtpd.h"
-/* #include "smtpd_sasl.h"
+/* #include "smtpd_sasl_proto.h"
/*
/* void smtpd_sasl_auth_cmd(state, argc, argv)
/* SMTPD_STATE *state;
/* the SMTP protocol interface for SASL negotiation. The goal
/* is to reduce clutter of the main SMTP server source code.
/*
-/* smtpd_sasl_auth_cmd() implements the AUTH command.
-/*
+/* smtpd_sasl_auth_cmd() implements the AUTH command and updates
+/* the following state structure members:
+/* .IP sasl_method
+/* The authentication method that was successfully applied.
+/* This member is a null pointer in the absence of successful
+/* authentication.
+/* .IP sasl_username
+/* The username that was successfully authenticated.
+/* This member is a null pointer in the absence of successful
+/* authentication.
+/* .PP
/* smtpd_sasl_auth_reset() cleans up after the AUTH command.
+/* This is required before smtpd_sasl_auth_cmd() can be used again.
/*
/* smtpd_sasl_mail_opt() implements the SASL-specific AUTH=sender
/* option to the MAIL FROM command. The result is an error response
#include <sys_defs.h>
#include <string.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/* Utility library. */
#include <msg.h>
{
char *auth_mechanism;
char *initial_response;
- char *err;
if (var_helo_required && state->helo_name == 0) {
state->error_mask |= MAIL_ERROR_POLICY;
*/
auth_mechanism = argv[1].strval;
initial_response = (argc == 3 ? argv[2].strval : 0);
- err = smtpd_sasl_authenticate(state, auth_mechanism, initial_response);
- if (err != 0) {
- msg_warn("%s[%s]: SASL %s authentication failed",
- state->name, state->addr, auth_mechanism);
- smtpd_chat_reply(state, "%s", err);
- return (-1);
- }
- smtpd_chat_reply(state, "235 2.0.0 Authentication successful");
- return (0);
+ return (smtpd_sasl_authenticate(state, auth_mechanism, initial_response));
}
/* smtpd_sasl_auth_reset - clean up after AUTH command */
#include <string.h>
#include <unistd.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/* Utility library. */
#include <mymalloc.h>
#include <fcntl.h>
#include <signal.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
/* Utility library. */
#include <msg.h>
#ifdef USE_TLS
#include <string.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/* Utility library. */
#include <mymalloc.h>
#ifdef USE_TLS
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/* Utility library. */
#include <msg.h>
#ifdef USE_TLS
#include <string.h>
-#ifdef STRCASECMP_IN_STRINGS_H
-#include <strings.h>
-#endif
-
/* Utility library. */
#include <msg.h>
#include <string.h>
#include <ctype.h>
+#ifdef STRCASECMP_IN_STRINGS_H
+#include <strings.h>
+#endif
+
/* Utility library. */
#include "mymalloc.h"
/* .IP NAME_MASK_RETURN
/* Require that all names listed in \fIname\fR exist in \fItable\fR,
/* and that all bits listed in \fImask\fR exist in \fItable\fR.
-/* Return 0 (name_mask()) or a null pointer (str_name_mask())
-/* if this condition is not met.
+/* Log a warning, and return 0 (name_mask()) or a null pointer
+/* (str_name_mask()) if this condition is not met.
/* .IP NAME_MASK_ANY_CASE
/* Enable case-insensitive matching.
/* This feature is not enabled by default when calling name_mask();
if (flags & NAME_MASK_FATAL)
msg_fatal("unknown %s value \"%s\" in \"%s\"",
context, name, names);
- if (flags & NAME_MASK_RETURN)
+ if (flags & NAME_MASK_RETURN) {
+ msg_warn("unknown %s value \"%s\" in \"%s\"",
+ context, name, names);
return (0);
+ }
break;
}
if (lookup(name, np->name) == 0) {
if (flags & NAME_MASK_FATAL)
msg_fatal("%s: invalid %s bit in mask: 0x%x",
myname, context, mask);
- if (flags & NAME_MASK_RETURN)
+ if (flags & NAME_MASK_RETURN) {
+ msg_warn("%s: invalid %s bit in mask: 0x%x",
+ myname, context, mask);
return (0);
+ }
break;
}
if (mask & np->mask) {
/* System library. */
#include <sys_defs.h>
+#include <string.h>
/* Utility library. */
extern char *sane_basename(VSTRING *, const char *);
extern char *sane_dirname(VSTRING *, const char *);
extern VSTRING *unescape(VSTRING *, const char *);
+extern VSTRING *escape(VSTRING *, const char *, ssize_t);
extern int alldig(const char *);
extern int allprint(const char *);
extern int allspace(const char *);
/* VSTRING *unescape(result, input)
/* VSTRING *result;
/* const char *input;
+/*
+/* VSTRING *escape(result, input, len)
+/* VSTRING *result;
+/* const char *input;
+/* ssize_t len;
/* DESCRIPTION
/* unescape() translates C-like escape sequences in the null-terminated
/* string \fIinput\fR and places the result in \fIresult\fR. The result
/* is null-terminated, and is the function result value.
/*
+/* escape() does the reverse transformation.
+/*
/* Escape sequences and their translations:
/* .IP \ea
/* Bell character.
return (result);
}
+/* escape - reverse transformation */
+
+VSTRING *escape(VSTRING *result, const char *data, ssize_t len)
+{
+ int ch;
+
+ VSTRING_RESET(result);
+ while (len-- > 0) {
+ ch = *UCHAR(data++);
+ if (ISASCII(ch)) {
+ if (ISPRINT(ch)) {
+ if (ch == '\\')
+ VSTRING_ADDCH(result, ch);
+ VSTRING_ADDCH(result, ch);
+ continue;
+ } else if (ch == '\a') { /* \a -> audible bell */
+ vstring_strcat(result, "\a");
+ continue;
+ } else if (ch == '\b') { /* \b -> backspace */
+ vstring_strcat(result, "\b");
+ continue;
+ } else if (ch == '\f') { /* \f -> formfeed */
+ vstring_strcat(result, "\f");
+ continue;
+ } else if (ch == '\n') { /* \n -> newline */
+ vstring_strcat(result, "\n");
+ continue;
+ } else if (ch == '\r') { /* \r -> carriagereturn */
+ vstring_strcat(result, "\r");
+ continue;
+ } else if (ch == '\t') { /* \t -> horizontal tab */
+ vstring_strcat(result, "\t");
+ continue;
+ } else if (ch == '\v') { /* \v -> vertical tab */
+ vstring_strcat(result, "\v");
+ continue;
+ }
+ }
+ vstring_sprintf_append(result, "\\%03d", ch);
+ }
+ VSTRING_TERMINATE(result);
+ return (result);
+}
+
#ifdef TEST
#include <stdlib.h>
#include <sys_defs.h> /* includes <sys/types.h> */
#include <sys/socket.h>
#include <sys/uio.h>
+#include <string.h>
/* Utility library. */
} control_un;
struct cmsghdr *cmptr;
+ memset((char *) &msg, 0, sizeof(msg));
msg.msg_control = control_un.control;
msg.msg_controllen = CMSG_LEN(sizeof(newfd)); /* Fix 200506 */
#else
#include <sys_defs.h> /* includes <sys/types.h> */
#include <sys/socket.h>
#include <sys/uio.h>
+#include <string.h>
/* Utility library. */
} control_un;
struct cmsghdr *cmptr;
+ memset((char *) &msg, 0, sizeof(msg));
msg.msg_control = control_un.control;
msg.msg_controllen = CMSG_LEN(sizeof(sendfd)); /* Fix 200506 */
VBUF *vbuf_print(VBUF *bp, const char *format, va_list ap)
{
+ const char *myname = "vbuf_print";
static VSTRING *fmt; /* format specifier */
unsigned char *cp;
- unsigned width; /* field width */
- unsigned prec; /* numerical precision */
+ int width; /* width and numerical precision */
+ int prec; /* are signed for overflow defense */
unsigned long_flag; /* long or plain integer */
int ch;
char *s;
VSTRING_ADDCH(fmt, ch);
}
}
+ if (width < 0) {
+ msg_warn("%s: bad width %d in %.50s", myname, width, format);
+ width = 0;
+ }
if (*cp == '.') /* width/precision separator */
VSTRING_ADDCH(fmt, *cp++);
if (*cp == '*') { /* dynamic precision */
VSTRING_ADDCH(fmt, ch);
}
}
+ if (prec < 0) {
+ msg_warn("%s: bad precision %d in %.50s", myname, prec, format);
+ prec = 0;
+ }
if ((long_flag = (*cp == 'l')) != 0)/* long whatever */
VSTRING_ADDCH(fmt, *cp++);
if (*cp == 0) /* premature end, punt */
--- /dev/null
+../../.indent.pro
\ No newline at end of file
--- /dev/null
+SHELL = /bin/sh
+SRCS = xsasl_server.c xsasl_cyrus_server.c xsasl_cyrus_log.c \
+ xsasl_cyrus_security.c xsasl_client.c xsasl_cyrus_client.c
+OBJS = xsasl_server.o xsasl_cyrus_server.o xsasl_cyrus_log.o \
+ xsasl_cyrus_security.o xsasl_client.o xsasl_cyrus_client.o
+HDRS = xsasl.h
+TESTSRC =
+DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE)
+CFLAGS = $(DEBUG) $(OPT) $(DEFS)
+INCL =
+LIB = libxsasl.a
+TESTPROG=
+
+LIBS = ../../lib/libglobal.a ../../lib/libutil.a
+LIB_DIR = ../../lib
+INC_DIR = ../../include
+MAKES =
+
+.c.o:; $(CC) $(CFLAGS) -c $*.c
+
+all: $(LIB)
+
+$(OBJS): ../../conf/makedefs.out
+
+Makefile: Makefile.in
+ (cat ../../conf/makedefs.out $?) >$@
+
+test: $(TESTPROG)
+
+$(LIB): $(OBJS)
+ $(AR) $(ARFL) $(LIB) $?
+ $(RANLIB) $(LIB)
+
+$(LIB_DIR)/$(LIB): $(LIB)
+ cp $(LIB) $(LIB_DIR)
+ $(RANLIB) $(LIB_DIR)/$(LIB)
+
+update: $(LIB_DIR)/$(LIB) $(HDRS)
+ -for i in $(HDRS); \
+ do \
+ cmp -s $$i $(INC_DIR)/$$i 2>/dev/null || cp $$i $(INC_DIR); \
+ done
+ cd $(INC_DIR); chmod 644 $(HDRS)
+
+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 $(LIB) *core $(TESTPROG) junk
+ rm -rf printfck
+
+tidy: clean
+
+foo: $(LIB) $(LIBS)
+ mv $@.o junk
+ $(CC) $(CFLAGS) -DTEST -o $@ $@.c $(LIB) $(LIBS) $(SYSLIBS)
+ mv junk $@.o
+
+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 | grep -v '[<>]' | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \
+ -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' \
+ -e 's/o: \.\//o: /' -e p -e '}' ; \
+ done | sort -u) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in
+ @$(EXPORT) make -f Makefile.in Makefile 1>&2
+
+# do not edit below this line - it is generated by 'make depend'
+xsasl_client.o: ../../include/argv.h
+xsasl_client.o: ../../include/msg.h
+xsasl_client.o: ../../include/mymalloc.h
+xsasl_client.o: ../../include/sys_defs.h
+xsasl_client.o: ../../include/vbuf.h
+xsasl_client.o: ../../include/vstream.h
+xsasl_client.o: ../../include/vstring.h
+xsasl_client.o: xsasl.h
+xsasl_client.o: xsasl_client.c
+xsasl_client.o: xsasl_cyrus.h
+xsasl_cyrus_client.o: ../../include/argv.h
+xsasl_cyrus_client.o: ../../include/msg.h
+xsasl_cyrus_client.o: ../../include/mymalloc.h
+xsasl_cyrus_client.o: ../../include/stringops.h
+xsasl_cyrus_client.o: ../../include/sys_defs.h
+xsasl_cyrus_client.o: ../../include/vbuf.h
+xsasl_cyrus_client.o: ../../include/vstream.h
+xsasl_cyrus_client.o: ../../include/vstring.h
+xsasl_cyrus_client.o: xsasl.h
+xsasl_cyrus_client.o: xsasl_cyrus.h
+xsasl_cyrus_client.o: xsasl_cyrus_client.c
+xsasl_cyrus_client.o: xsasl_cyrus_common.h
+xsasl_cyrus_log.o: ../../include/msg.h
+xsasl_cyrus_log.o: ../../include/sys_defs.h
+xsasl_cyrus_log.o: xsasl_cyrus_common.h
+xsasl_cyrus_log.o: xsasl_cyrus_log.c
+xsasl_cyrus_security.o: ../../include/name_mask.h
+xsasl_cyrus_security.o: ../../include/sys_defs.h
+xsasl_cyrus_security.o: xsasl_cyrus_common.h
+xsasl_cyrus_security.o: xsasl_cyrus_security.c
+xsasl_cyrus_server.o: ../../include/argv.h
+xsasl_cyrus_server.o: ../../include/mail_params.h
+xsasl_cyrus_server.o: ../../include/msg.h
+xsasl_cyrus_server.o: ../../include/mymalloc.h
+xsasl_cyrus_server.o: ../../include/name_mask.h
+xsasl_cyrus_server.o: ../../include/stringops.h
+xsasl_cyrus_server.o: ../../include/sys_defs.h
+xsasl_cyrus_server.o: ../../include/vbuf.h
+xsasl_cyrus_server.o: ../../include/vstream.h
+xsasl_cyrus_server.o: ../../include/vstring.h
+xsasl_cyrus_server.o: xsasl.h
+xsasl_cyrus_server.o: xsasl_cyrus.h
+xsasl_cyrus_server.o: xsasl_cyrus_common.h
+xsasl_cyrus_server.o: xsasl_cyrus_server.c
+xsasl_server.o: ../../include/argv.h
+xsasl_server.o: ../../include/msg.h
+xsasl_server.o: ../../include/mymalloc.h
+xsasl_server.o: ../../include/sys_defs.h
+xsasl_server.o: ../../include/vbuf.h
+xsasl_server.o: ../../include/vstream.h
+xsasl_server.o: ../../include/vstring.h
+xsasl_server.o: xsasl.h
+xsasl_server.o: xsasl_cyrus.h
+xsasl_server.o: xsasl_server.c
--- /dev/null
+Purpose of this document
+========================
+
+This document describes how to add your own SASL implementation to
+Postfix. You don't have to provide both the server and client side.
+You can provide just one and omit the other. The examples below
+assume you do both.
+
+The plug-in API is described in cyrus_server.c and cyrus_client.c.
+It was unavoidably contaminated^h^h^h^h^h^h^h^h^h^h^h^hinfluenced
+by Cyrus SASL and may need revision as other implementations are
+added.
+
+For an example of how the plug-in interface is implemented, have a
+look at the xsasl/xsasl_cyrus_client.c and xsasl/xsasl_cyrus_server.c.
+
+Configuration features
+======================
+
+There are two configuration parameters that allow you to pass
+information from main.cf into the plug_in:
+
+ smtpd_sasl_path, smtpd_sasl_security_options
+ smtp_sasl_path, smtp_sasl_security_options
+ lmtp_sasl_path, lmtp_sasl_security_options
+
+The parameter values are passed to the plug-in without any
+interpretation. The following restrictions are imposed by the main.cf
+file parser: parameter values never contain newlines, and they never
+start or end with whitespace characters.
+
+The _path parameter value is passed only once during process
+initialization (i.e. it is a class variable). The path typically
+specifies the location of a configuration file or rendez-vous point.
+The _security_options parameter value is passed each time SASL is
+turned on for a connection (i.e. it is an instance variable). The
+options may depend on whether or not TLS encryption is turned on.
+Remember that one Postfix process may perform up to 100 mail
+transactions during its life time. Things that happen in one
+transaction must not affect later transactions.
+
+Adding Postfix support for your own SASL implementation
+=======================================================
+
+To add your own SASL implementation, say, FOOBAR:
+
+- Copy xsasl/xsasl_cyrus.h to xsasl/xsasl_foobar.h and replace
+ CYRUS by FOOBAR:
+
+ #if defined(USE_SASL_AUTH) && defined(USE_FOOBAR_SASL)
+ /*
+ * SASL protocol interface
+ */
+ #define XSASL_TYPE_FOOBAR "foobar"
+ extern XSASL_SERVER_IMPL *xsasl_foobar_server_init(const char *, const char *);
+ extern XSASL_CLIENT_IMPL *xsasl_foobar_client_init(const char *, const char *);
+ #endif
+
+- Edit xsasl/xsasl_server.c, add your #include <xsasl_foobar.h> line
+ under #include <xsasl_cyrus.h> at the top, and add your initialization
+ function in the table at the bottom as shown below:
+
+ static XSASL_SERVER_IMPL_INFO server_impl_info[] = {
+ #ifdef XSASL_TYPE_CYRUS
+ XSASL_TYPE_CYRUS, xsasl_cyrus_server_init,
+ #endif
+ #ifdef XSASL_TYPE_FOOBAR
+ XSASL_TYPE_FOOBAR, xsasl_foobar_server_init,
+ #endif
+ 0,
+ };
+
+- Repeat the (almost) same procedure for xsasl/xsasl_client.c.
+
+- Create your own xsasl/xsasl_foobar_{client,server}.c and support
+ files. Perhaps it's convenient to copy the cyrus files, rip out
+ the function bodies, and replace CYRUS by FOOBAR.
+
+- List your source files in Makefile.in. Don't forget to do "make
+ depend" after you do "make makefiles" in the step that follows
+ after this one.
+
+ SRCS = xsasl_server.c xsasl_cyrus_server.c xsasl_cyrus_log.c \
+ xsasl_cyrus_security.c xsasl_client.c xsasl_cyrus_client.c \
+ xsasl_foobar_client.c xsasl_foobar_server.c
+ OBJS = xsasl_server.o xsasl_cyrus_server.o xsasl_cyrus_log.o \
+ xsasl_cyrus_security.o xsasl_client.o xsasl_cyrus_client.o \
+ xsasl_foobar_client.o xsasl_foobar_server.o
+
+- Create the Postfix makefiles from the top-level directory:
+
+ % make makefiles CCARGS='-DUSE_SASL_AUTH -DUSE_FOOBAR_SASL \
+ -DDEF_CLIENT_SASL_TYPE=\"foobar\" -DDEF_SERVER_TYPE=\"foobar\" \
+ -I/some/where/include' AUXLIBS='-L/some/where/lib -lfoobar'
+
+ Yes, you can have different default SASL implementation types for
+ the client and server plug-ins.
+
+ Of course you don't have to override the default SASL implementation
+ type; it is shown here as an example.
+
+
+- Don't forget to do "make depend" in the xsasl directory.
+
+- Document your build and configuration with a README document.
--- /dev/null
+#ifndef _XSASL_H_INCLUDED_
+#define _XSASL_H_INCLUDED_
+
+/*++
+/* NAME
+/* xsasl 3h
+/* SUMMARY
+/* Postfix SASL plug-in interface
+/* SYNOPSIS
+/* #include <xsasl.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * Utility library.
+ */
+#include <argv.h>
+#include <vstream.h>
+#include <vstring.h>
+
+ /*
+ * Generic server object. Specific instances extend this with their own
+ * private data.
+ */
+typedef struct XSASL_SERVER {
+ void (*free) (struct XSASL_SERVER *);
+ int (*first) (struct XSASL_SERVER *, const char *, const char *, VSTRING *);
+ int (*next) (struct XSASL_SERVER *, const char *, VSTRING *);
+ const char *(*get_mechanism_list) (struct XSASL_SERVER *);
+ const char *(*get_username) (struct XSASL_SERVER *);
+} XSASL_SERVER;
+
+#define xsasl_server_free(server) (server)->free(server)
+#define xsasl_server_first(server, method, init_resp, reply) \
+ (server)->first((server), (method), (init_resp), (reply))
+#define xsasl_server_next(server, request, reply) \
+ (server)->next((server), (request), (reply))
+#define xsasl_server_get_mechanism_list(server) \
+ (server)->get_mechanism_list((server))
+#define xsasl_server_get_username(server) \
+ (server)->get_username((server))
+
+ /*
+ * Generic server implementation. Specific instances extend this with their
+ * own private data.
+ */
+typedef struct XSASL_SERVER_IMPL {
+ XSASL_SERVER *(*create) (struct XSASL_SERVER_IMPL *, VSTREAM *, const char *, const char *, const char *);
+ void (*done) (struct XSASL_SERVER_IMPL *);
+} XSASL_SERVER_IMPL;
+
+extern XSASL_SERVER_IMPL *xsasl_server_init(const char *, const char *);
+extern ARGV *xsasl_server_types(void);
+
+#define xsasl_server_create(impl, stream, service, realm, sec_props) \
+ (impl)->create((impl), (stream), (service), (realm), (sec_props))
+#define xsasl_server_done(impl) (impl)->done((impl));
+
+ /*
+ * Generic client object. Specific instances extend this with their own
+ * private data.
+ */
+typedef struct XSASL_CLIENT {
+ void (*free) (struct XSASL_CLIENT *);
+ int (*first) (struct XSASL_CLIENT *, const char *, const char *, const char *, const char **, VSTRING *);
+ int (*next) (struct XSASL_CLIENT *, const char *, VSTRING *);
+} XSASL_CLIENT;
+
+#define xsasl_client_free(client) (client)->free(client)
+#define xsasl_client_first(client, server, method, user, pass, init_resp) \
+ (client)->first((client), (server), (method), (user), (pass), (init_resp))
+#define xsasl_client_next(client, request, reply) \
+ (client)->next((client), (request), (reply))
+#define xsasl_client_set_password(client, user, pass) \
+ (client)->set_password((client), (user), (pass))
+
+ /*
+ * Generic client implementation. Specific instances extend this with their
+ * own private data.
+ */
+typedef struct XSASL_CLIENT_IMPL {
+ XSASL_CLIENT *(*create) (struct XSASL_CLIENT_IMPL *, VSTREAM *, const char *, const char *, const char *);
+ void (*done) (struct XSASL_CLIENT_IMPL *);
+} XSASL_CLIENT_IMPL;
+
+extern XSASL_CLIENT_IMPL *xsasl_client_init(const char *, const char *);
+extern ARGV *xsasl_client_types(void);
+
+#define xsasl_client_create(impl, stream, service, server, sec_props) \
+ (impl)->create((impl), (stream), (service), (server), (sec_props))
+#define xsasl_client_done(impl) (impl)->done((impl));
+
+ /*
+ * Status codes.
+ */
+#define XSASL_AUTH_OK 1 /* Success */
+#define XSASL_AUTH_MORE 2 /* Need another c/s protocol exchange */
+#define XSASL_AUTH_DONE 3 /* Authentication completed */
+#define XSASL_AUTH_FORM 4 /* Cannot decode response */
+#define XSASL_AUTH_FAIL 5 /* 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
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* xsasl_client 3
+/* SUMMARY
+/* Postfix SASL client plug-in interface
+/* SYNOPSIS
+/* #include <xsasl.h>
+/*
+/* XSASL_CLIENT_IMPL *xsasl_client_init(client_type, path_info)
+/* const char *client_type;
+/* const char *path_info;
+/*
+/* void xsasl_client_done(implementation)
+/* XSASL_CLIENT_IMPL *implementation;
+/*
+/* ARGV *xsasl_client_types()
+/*
+/* XSASL_CLIENT *xsasl_client_create(implementation, stream, service,
+/* server_name, security_properties)
+/* XSASL_CLIENT_IMPL *implementation;
+/* VSTREAM *stream;
+/* const char *service;
+/* const char *server_name;
+/* const char *security_properties;
+/*
+/* void xsasl_client_free(client)
+/* XSASL_CLIENT *client;
+/*
+/* int xsasl_client_first(client, stream, mech_list, username,
+/* password, auth_method, init_resp)
+/* XSASL_CLIENT *client;
+/* const char *mech_list;
+/* const char *username;
+/* const char *password;
+/* const char **auth_method;
+/* VSTRING *init_resp;
+/*
+/* int xsasl_client_next(client, server_reply, client_reply)
+/* XSASL_CLIENT *client;
+/* const char *server_reply;
+/* VSTRING *client_reply;
+/* DESCRIPTION
+/* The XSASL_CLIENT abstraction implements a generic interface
+/* to one or more SASL authentication implementations.
+/*
+/* xsasl_client_init() is called once during process initialization.
+/* It selects a SASL implementation by name, specifies the
+/* location of a configuration file or rendez-vous point, and
+/* returns an implementation handle that can be used to generate
+/* SASL client instances. This function is typically used to
+/* initialize the underlying implementation.
+/*
+/* xsasl_client_done() disposes of an implementation handle,
+/* and allows the underlying implementation to release resources.
+/*
+/* xsasl_client_types() lists the available implementation types.
+/* The result should be destroyed by the caller.
+/*
+/* xsasl_client_create() is called at the start of an SMTP
+/* session. It generates a Postfix SASL plug-in client instance
+/* for the specified service and server name, with the specified
+/* security properties. The stream handle is stored so that
+/* encryption can be turned on after successful negotiations.
+/*
+/* xsasl_client_free() is called at the end of an SMTP session.
+/* It destroys a SASL client instance, and disables further
+/* read/write operations if encryption was turned on.
+/*
+/* xsasl_client_first() produces the client input for the AUTH
+/* command. The input is an authentication method list from
+/* an EHLO response, a username and a password. On return, the
+/* method argument specifies the authentication method; storage
+/* space is owned by the underlying implementation. The initial
+/* response and client non-error replies are BASE64 encoded.
+/* Client error replies are 7-bit ASCII text without control
+/* characters, and without BASE64 encoding. They are meant for
+/* the local application, not for transmission to the server.
+/* The client may negotiate encryption of the client-server
+/* connection.
+/*
+/* The result is one of the following:
+/* .IP XSASL_AUTH_OK
+/* Success.
+/* .IP XSASL_AUTH_FORM
+/* The server reply is incorrectly formatted. The client error
+/* reply explains why.
+/* .IP XSASL_AUTH_FAIL
+/* Other error. The client error reply explains why.
+/* .PP
+/* xsasl_client_next() supports the subsequent stages of the
+/* AUTH protocol. Both the client reply and client non-error
+/* responses are BASE64 encoded. See xsasl_client_first() for
+/* other details.
+/*
+/* Arguments:
+/* .IP client
+/* SASL plug-in client handle.
+/* .IP client_reply
+/* BASE64 encoded non-error client reply, or ASCII error
+/* description for the user.
+/* .IP client_type
+/* The name of a Postfix SASL client plug_in implementation.
+/* .IP client_types
+/* Null-terminated array of strings with SASL client plug-in
+/* implementation names.
+/* .IP init_resp
+/* The AUTH command initial response.
+/* .IP implementation
+/* Implementation handle that was obtained with xsasl_client_init().
+/* .IP mech_list
+/* List of SASL mechanisms as announced by the server.
+/* .IP auth_method
+/* The AUTH command authentication method.
+/* .IP password
+/* Information from the Postfix SASL password file or equivalent.
+/* .IP path_info
+/* The value of the smtp_sasl_path parameter or equivalent.
+/* This specifies the implementation-dependent location of a
+/* configuration file, rendez-vous point, etc., and is passed
+/* unchanged to the plug-in.
+/* .IP security_options
+/* The value of the smtp_sasl_security_options parameter or
+/* equivalent. This is passed unchanged to the plug-in.
+/* .IP server_name
+/* The remote server fully qualified hostname.
+/* .IP server_reply
+/* BASE64 encoded server reply without SMTP reply code or
+/* enhanced status code.
+/* .IP service
+/* The service that is implemented by the local client (typically,
+/* "lmtp" or "smtp").
+/* .IP stream
+/* The connection between client and server.
+/* When SASL encryption is negotiated, the plug-in will
+/* transparently intercept the socket read/write operations.
+/* .IP username
+/* Information from the Postfix SASL password file.
+/* SECURITY
+/* .ad
+/* .fi
+/* The caller does not sanitize the server reply. It is the
+/* responsibility of the underlying SASL client implementation
+/* to produce 7-bit ASCII without control characters as client
+/* non-error and error replies.
+/* DIAGNOSTICS
+/* In case of error, xsasl_client_init() and xsasl_client_create()
+/* log a warning and return a null pointer.
+/*
+/* Functions that normally return XSASL_AUTH_OK will log a warning
+/* and return an appropriate result value.
+/*
+/* Panic: interface violation.
+/*
+/* Fatal errors: out of memory.
+/* SEE ALSO
+/* cyrus_security(3) Cyrus SASL security features
+/* 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>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+
+/* SASL implementations. */
+
+#include <xsasl.h>
+#include <xsasl_cyrus.h>
+
+ /*
+ * Lookup table for available SASL client implementations.
+ */
+typedef struct {
+ char *client_type;
+ struct XSASL_CLIENT_IMPL *(*client_init) (const char *, const char *);
+} XSASL_CLIENT_IMPL_INFO;
+
+static XSASL_CLIENT_IMPL_INFO client_impl_info[] = {
+#ifdef XSASL_TYPE_CYRUS
+ XSASL_TYPE_CYRUS, xsasl_cyrus_client_init,
+#endif
+ 0,
+};
+
+/* xsasl_client_init - look up client implementation by name */
+
+XSASL_CLIENT_IMPL *xsasl_client_init(const char *client_type,
+ const char *path_info)
+{
+ XSASL_CLIENT_IMPL_INFO *xp;
+
+ for (xp = client_impl_info; xp->client_type; xp++)
+ if (strcmp(client_type, xp->client_type) == 0)
+ return (xp->client_init(client_type, path_info));
+ msg_warn("unsupported SASL client implementation: %s", client_type);
+ return (0);
+}
+
+/* xsasl_client_types - report available implementation types */
+
+ARGV *xsasl_client_types(void)
+{
+ XSASL_CLIENT_IMPL_INFO *xp;
+ ARGV *argv = argv_alloc(1);
+
+ for (xp = client_impl_info; xp->client_type; xp++)
+ argv_add(argv, xp->client_type, ARGV_END);
+ return (argv);
+}
--- /dev/null
+#ifndef _XSASL_CYRUS_H_INCLUDED_
+#define _XSASL_CYRUS_H_INCLUDED_
+
+/*++
+/* NAME
+/* xsasl_cyrus 3h
+/* SUMMARY
+/* Cyrus SASL plug-in
+/* SYNOPSIS
+/* #include <xsasl_cyrus.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * XSASL library.
+ */
+#include <xsasl.h>
+
+#if defined(USE_SASL_AUTH) && defined(USE_CYRUS_SASL)
+
+ /*
+ * SASL protocol interface
+ */
+#define XSASL_TYPE_CYRUS "cyrus"
+
+extern XSASL_SERVER_IMPL *xsasl_cyrus_server_init(const char *, const char *);
+extern XSASL_CLIENT_IMPL *xsasl_cyrus_client_init(const char *, const char *);
+
+#endif
+
+/* 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
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* xsasl_cyrus_client 3
+/* SUMMARY
+/* Cyrus SASL client-side plug-in
+/* SYNOPSIS
+/* #include <xsasl_cyrus_client.h>
+/*
+/* XSASL_CLIENT_IMPL *xsasl_cyrus_client_init(client_type, path_info)
+/* const char *client_type;
+/* DESCRIPTION
+/* This module implements the Cyrus SASL client-side authentication
+/* plug-in.
+/*
+/* xsasl_cyrus_client_init() initializes the Cyrus SASL library and
+/* returns an implementation handle that can be used to generate
+/* SASL client instances.
+/*
+/* Arguments:
+/* .IP client_type
+/* The plug-in SASL client type (cyrus). This argument is
+/* ignored, but it could be used when one implementation
+/* provides multiple variants.
+/* .IP path_info
+/* Implementation-specific information to specify the location
+/* of a configuration file, rendez-vous point, etc. This
+/* information is ignored by the Cyrus SASL client plug-in.
+/* DIAGNOSTICS
+/* Fatal: out of memory.
+/*
+/* Panic: interface violation.
+/*
+/* Other: the routines log a warning and return an error result
+/* as specified in xsasl_client(3).
+/* SEE ALSO
+/* xsasl_client(3) Client API
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Original author:
+/* Till Franke
+/* SuSE Rhein/Main AG
+/* 65760 Eschborn, Germany
+/*
+/* Adopted by:
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+ /*
+ * System library.
+ */
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <string.h>
+
+ /*
+ * Utility library
+ */
+#include <msg.h>
+#include <mymalloc.h>
+#include <stringops.h>
+
+ /*
+ * Application-specific
+ */
+#include <xsasl.h>
+#include <xsasl_cyrus.h>
+#include <xsasl_cyrus_common.h>
+
+#if defined(USE_SASL_AUTH) && defined(USE_CYRUS_SASL)
+
+#include <sasl.h>
+#include <saslutil.h>
+
+/*
+ * Silly little macros.
+ */
+#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_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_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)
+typedef char *CLIENTOUT_TYPE;
+
+#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)
+typedef const char *CLIENTOUT_TYPE;
+
+#endif
+
+ /*
+ * The XSASL_CYRUS_CLIENT object is derived from the generic XSASL_CLIENT
+ * object.
+ */
+typedef struct {
+ XSASL_CLIENT xsasl; /* generic members, must be first */
+ VSTREAM *stream; /* client-server connection */
+ sasl_conn_t *sasl_conn; /* SASL context */
+ VSTRING *decoded; /* decoded server challenge */
+ sasl_callback_t *callbacks; /* user/password lookup */
+ char *username;
+ char *password;
+} XSASL_CYRUS_CLIENT;
+
+ /*
+ * Forward declarations.
+ */
+static void xsasl_cyrus_client_done(XSASL_CLIENT_IMPL *);
+static XSASL_CLIENT *xsasl_cyrus_client_create(XSASL_CLIENT_IMPL *,
+ VSTREAM *,
+ const char *,
+ const char *,
+ const char *);
+static int xsasl_cyrus_client_set_security(XSASL_CLIENT *, const char *);
+static int xsasl_cyrus_client_first(XSASL_CLIENT *, const char *, const char *,
+ const char *, const char **, VSTRING *);
+static int xsasl_cyrus_client_next(XSASL_CLIENT *, const char *, VSTRING *);
+static void xsasl_cyrus_client_free(XSASL_CLIENT *);
+
+/* xsasl_cyrus_client_get_user - username lookup call-back routine */
+
+static int xsasl_cyrus_client_get_user(void *context, int unused_id,
+ const char **result,
+ unsigned *len)
+{
+ char *myname = "xsasl_cyrus_get_user";
+ XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) context;
+
+ if (msg_verbose)
+ msg_info("%s: %s", myname, client->username);
+
+ /*
+ * Sanity check.
+ */
+ if (client->password == 0)
+ msg_panic("%s: no username looked up", myname);
+
+ *result = client->username;
+ if (len)
+ *len = strlen(client->username);
+ return (SASL_OK);
+}
+
+/* xsasl_cyrus_client_get_passwd - password lookup call-back routine */
+
+static int xsasl_cyrus_client_get_passwd(sasl_conn_t *conn, void *context,
+ int id, sasl_secret_t **psecret)
+{
+ char *myname = "xsasl_cyrus_get_passwd";
+ XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) context;
+ int len;
+
+ if (msg_verbose)
+ msg_info("%s: %s", myname, client->password);
+
+ /*
+ * Sanity check.
+ */
+ if (!conn || !psecret || id != SASL_CB_PASS)
+ return (SASL_BADPARAM);
+ if (client->password == 0)
+ msg_panic("%s: no password looked up", myname);
+
+ /*
+ * Convert the password into a counted string.
+ */
+ len = strlen(client->password);
+ if ((*psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len)) == 0)
+ return (SASL_NOMEM);
+ (*psecret)->len = len;
+ memcpy((*psecret)->data, client->password, len + 1);
+
+ return (SASL_OK);
+}
+
+/* xsasl_cyrus_client_init - initialize Cyrus SASL library */
+
+XSASL_CLIENT_IMPL *xsasl_cyrus_client_init(const char *unused_client_type,
+ const char *unused_path_info)
+{
+ XSASL_CLIENT_IMPL *xp;
+ int sasl_status;
+
+ /*
+ * Global callbacks. These have no per-session context.
+ */
+ static sasl_callback_t callbacks[] = {
+ {SASL_CB_LOG, &xsasl_cyrus_log, 0},
+ {SASL_CB_LIST_END, 0, 0}
+ };
+
+#if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \
+ || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19))
+ int sasl_major;
+ int sasl_minor;
+ int sasl_step;
+
+ /*
+ * DLL hell guard.
+ */
+ sasl_version_info((const char **) 0, (const char **) 0,
+ &sasl_major, &sasl_minor,
+ &sasl_step, (int *) 0);
+ if (sasl_major != SASL_VERSION_MAJOR
+#if 0
+ || sasl_minor != SASL_VERSION_MINOR
+ || sasl_step != SASL_VERSION_STEP
+#endif
+ ) {
+ msg_warn("incorrect SASL library version. "
+ "Postfix was built with include files from version %d.%d.%d, "
+ "but the run-time library version is %d.%d.%d",
+ SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
+ sasl_major, sasl_minor, sasl_step);
+ return (0);
+ }
+#endif
+
+ /*
+ * Initialize the SASL library.
+ */
+ if ((sasl_status = sasl_client_init(callbacks)) != SASL_OK) {
+ msg_warn("SASL library initialization error: %s",
+ xsasl_cyrus_strerror(sasl_status));
+ return (0);
+ }
+
+ /*
+ * Return a generic XSASL_CLIENT_IMPL object. We don't need to extend it
+ * with our own methods or data.
+ */
+ xp = (XSASL_CLIENT_IMPL *) mymalloc(sizeof(*xp));
+ xp->create = xsasl_cyrus_client_create;
+ xp->done = xsasl_cyrus_client_done;
+ return (xp);
+}
+
+/* xsasl_cyrus_client_done - dispose of implementation */
+
+static void xsasl_cyrus_client_done(XSASL_CLIENT_IMPL *impl)
+{
+ myfree((char *) impl);
+ sasl_done();
+}
+
+/* xsasl_cyrus_client_create - per-session SASL initialization */
+
+XSASL_CLIENT *xsasl_cyrus_client_create(XSASL_CLIENT_IMPL *unused_impl,
+ VSTREAM *stream,
+ const char *service,
+ const char *server,
+ const char *sec_props)
+{
+ XSASL_CYRUS_CLIENT *client = 0;
+ static sasl_callback_t callbacks[] = {
+ {SASL_CB_USER, &xsasl_cyrus_client_get_user, 0},
+ {SASL_CB_AUTHNAME, &xsasl_cyrus_client_get_user, 0},
+ {SASL_CB_PASS, &xsasl_cyrus_client_get_passwd, 0},
+ {SASL_CB_LIST_END, 0, 0}
+ };
+ sasl_conn_t *sasl_conn = 0;
+ sasl_callback_t *custom_callbacks = 0;
+ sasl_callback_t *cp;
+ int sasl_status;
+
+ /*
+ * The optimizer will eliminate duplication and/or dead code.
+ */
+#define XSASL_CYRUS_CLIENT_CREATE_ERROR_RETURN(x) \
+ do { \
+ if (client) { \
+ xsasl_cyrus_client_free(&client->xsasl); \
+ } else { \
+ if (custom_callbacks) \
+ myfree((char *) custom_callbacks); \
+ if (sasl_conn) \
+ sasl_dispose(&sasl_conn); \
+ } \
+ return (x); \
+ } while (0)
+
+ /*
+ * Per-session initialization. Provide each session with its own callback
+ * context.
+ */
+#define NULL_SECFLAGS 0
+
+ custom_callbacks = (sasl_callback_t *) mymalloc(sizeof(callbacks));
+ memcpy((char *) custom_callbacks, callbacks, sizeof(callbacks));
+
+#define NULL_SERVER_ADDR ((char *) 0)
+#define NULL_CLIENT_ADDR ((char *) 0)
+
+ if ((sasl_status = SASL_CLIENT_NEW(service, server,
+ NULL_CLIENT_ADDR, NULL_SERVER_ADDR,
+ custom_callbacks, NULL_SECFLAGS,
+ &sasl_conn)) != SASL_OK) {
+ msg_warn("per-session SASL client initialization: %s",
+ xsasl_cyrus_strerror(sasl_status));
+ XSASL_CYRUS_CLIENT_CREATE_ERROR_RETURN(0);
+ }
+
+ /*
+ * Extend XSASL_CLIENT_IMPL object with our own state. We use long-lived
+ * conversion buffers rather than local variables to avoid memory leaks
+ * in case of read/write timeout or I/O error.
+ *
+ * XXX If we enable SASL encryption, there needs to be a way to inform the
+ * application, so that they can turn off connection caching, refuse
+ * STARTTLS, etc.
+ */
+ client = (XSASL_CYRUS_CLIENT *) mymalloc(sizeof(*client));
+ client->xsasl.free = xsasl_cyrus_client_free;
+ client->xsasl.first = xsasl_cyrus_client_first;
+ client->xsasl.next = xsasl_cyrus_client_next;
+ client->stream = stream;
+ client->sasl_conn = sasl_conn;
+ client->callbacks = custom_callbacks;
+ client->decoded = vstring_alloc(20);
+ client->username = 0;
+ client->password = 0;
+
+ for (cp = custom_callbacks; cp->id != SASL_CB_LIST_END; cp++)
+ cp->context = (void *) client;
+
+ if (xsasl_cyrus_client_set_security(&client->xsasl, sec_props)
+ != XSASL_AUTH_OK)
+ XSASL_CYRUS_CLIENT_CREATE_ERROR_RETURN(0);
+
+ return (&client->xsasl);
+}
+
+/* xsasl_cyrus_client_set_security - set security properties */
+
+static int xsasl_cyrus_client_set_security(XSASL_CLIENT *xp,
+ const char *sasl_opts_val)
+{
+ XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp;
+ sasl_security_properties_t sec_props;
+ int sasl_status;
+
+ /*
+ * Per-session security properties. XXX This routine is not sufficiently
+ * documented. What is the purpose of all this?
+ */
+ memset(&sec_props, 0L, sizeof(sec_props));
+ sec_props.min_ssf = 0;
+ sec_props.max_ssf = 0; /* don't allow real SASL
+ * security layer */
+ if (*sasl_opts_val == 0) {
+ sec_props.security_flags = 0;
+ } else {
+ sec_props.security_flags =
+ xsasl_cyrus_security_parse_opts(sasl_opts_val);
+ if (sec_props.security_flags == 0) {
+ msg_warn("bad per-session SASL security properties");
+ return (XSASL_AUTH_FAIL);
+ }
+ }
+ sec_props.maxbufsize = 0;
+ sec_props.property_names = 0;
+ sec_props.property_values = 0;
+ if ((sasl_status = sasl_setprop(client->sasl_conn, SASL_SEC_PROPS,
+ &sec_props)) != SASL_OK) {
+ msg_warn("set per-session SASL security properties: %s",
+ xsasl_cyrus_strerror(sasl_status));
+ return (XSASL_AUTH_FAIL);
+ }
+ return (XSASL_AUTH_OK);
+}
+
+/* xsasl_cyrus_client_first - run authentication protocol */
+
+static int xsasl_cyrus_client_first(XSASL_CLIENT *xp,
+ const char *mechanism_list,
+ const char *username,
+ const char *password,
+ const char **mechanism,
+ VSTRING *init_resp)
+{
+ char *myname = "xsasl_cyrus_client_first";
+ XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp;
+ unsigned enc_length;
+ unsigned enc_length_out;
+ CLIENTOUT_TYPE clientout;
+ unsigned clientoutlen;
+ int sasl_status;
+
+#define NO_SASL_SECRET 0
+#define NO_SASL_INTERACTION 0
+
+ /*
+ * Save the username and password for the call-backs.
+ */
+ if (client->username)
+ myfree(client->username);
+ client->username = mystrdup(username);
+ if (client->password)
+ myfree(client->password);
+ client->password = mystrdup(password);
+
+ /*
+ * Start the client side authentication protocol.
+ */
+ sasl_status = SASL_CLIENT_START((sasl_conn_t *) client->sasl_conn,
+ mechanism_list,
+ NO_SASL_SECRET, NO_SASL_INTERACTION,
+ &clientout, &clientoutlen, mechanism);
+ if (sasl_status != SASL_OK && sasl_status != SASL_CONTINUE) {
+ vstring_strcpy(init_resp, xsasl_cyrus_strerror(sasl_status));
+ return (XSASL_AUTH_FAIL);
+ }
+
+ /*
+ * Generate the AUTH command and the optional initial client response.
+ * sasl_encode64() produces four bytes for each complete or incomplete
+ * triple of input bytes. Allocate an extra byte for string termination.
+ */
+#define ENCODE64_LENGTH(n) ((((n) + 2) / 3) * 4)
+
+ if (clientoutlen > 0) {
+ if (msg_verbose) {
+ escape(client->decoded, clientout, clientoutlen);
+ msg_info("%s: uncoded initial reply: %s",
+ myname, STR(client->decoded));
+ }
+ enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
+ VSTRING_RESET(init_resp); /* Fix 200512 */
+ VSTRING_SPACE(init_resp, enc_length);
+ if ((sasl_status = sasl_encode64(clientout, clientoutlen,
+ STR(init_resp),
+ vstring_avail(init_resp),
+ &enc_length_out)) != SASL_OK)
+ msg_panic("%s: sasl_encode64 botch: %s",
+ myname, xsasl_cyrus_strerror(sasl_status));
+ VSTRING_AT_OFFSET(init_resp, enc_length_out); /* XXX */
+#if SASL_VERSION_MAJOR < 2
+ /* SASL version 1 doesn't free memory that it allocates. */
+ free(clientout);
+#endif
+ } else {
+ vstring_strcpy(init_resp, "");
+ }
+ return (XSASL_AUTH_OK);
+}
+
+/* xsasl_cyrus_client_next - continue authentication */
+
+static int xsasl_cyrus_client_next(XSASL_CLIENT *xp, const char *server_reply,
+ VSTRING *client_reply)
+{
+ char *myname = "xsasl_cyrus_client_next";
+ XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp;
+ unsigned enc_length;
+ unsigned enc_length_out;
+ CLIENTOUT_TYPE clientout;
+ unsigned clientoutlen;
+ unsigned serverinlen;
+ int sasl_status;
+
+ /*
+ * Process a server challenge.
+ */
+ serverinlen = strlen(server_reply);
+ VSTRING_RESET(client->decoded); /* Fix 200512 */
+ VSTRING_SPACE(client->decoded, serverinlen);
+ if ((sasl_status = SASL_DECODE64(server_reply, serverinlen,
+ STR(client->decoded),
+ vstring_avail(client->decoded),
+ &enc_length)) != SASL_OK) {
+ vstring_strcpy(client_reply, xsasl_cyrus_strerror(sasl_status));
+ return (XSASL_AUTH_FORM);
+ }
+ if (msg_verbose)
+ msg_info("%s: decoded challenge: %.*s",
+ myname, (int) enc_length, STR(client->decoded));
+ sasl_status = sasl_client_step(client->sasl_conn, STR(client->decoded),
+ enc_length, NO_SASL_INTERACTION,
+ &clientout, &clientoutlen);
+ if (sasl_status != SASL_OK && sasl_status != SASL_CONTINUE) {
+ vstring_strcpy(client_reply, xsasl_cyrus_strerror(sasl_status));
+ return (XSASL_AUTH_FAIL);
+ }
+
+ /*
+ * Send a client response.
+ */
+ if (clientoutlen > 0) {
+ if (msg_verbose)
+ msg_info("%s: uncoded client response %.*s",
+ myname, (int) clientoutlen, clientout);
+ enc_length = ENCODE64_LENGTH(clientoutlen) + 1;
+ VSTRING_RESET(client_reply); /* Fix 200512 */
+ VSTRING_SPACE(client_reply, enc_length);
+ if ((sasl_status = sasl_encode64(clientout, clientoutlen,
+ STR(client_reply),
+ vstring_avail(client_reply),
+ &enc_length_out)) != SASL_OK)
+ msg_panic("%s: sasl_encode64 botch: %s",
+ myname, xsasl_cyrus_strerror(sasl_status));
+#if SASL_VERSION_MAJOR < 2
+ /* SASL version 1 doesn't free memory that it allocates. */
+ free(clientout);
+#endif
+ } else {
+ /* XXX Can't happen. */
+ vstring_strcpy(client_reply, "");
+ }
+ return (XSASL_AUTH_OK);
+}
+
+/* xsasl_cyrus_client_free - per-session cleanup */
+
+void xsasl_cyrus_client_free(XSASL_CLIENT *xp)
+{
+ XSASL_CYRUS_CLIENT *client = (XSASL_CYRUS_CLIENT *) xp;
+
+ if (client->username)
+ myfree(client->username);
+ if (client->password)
+ myfree(client->password);
+ if (client->sasl_conn)
+ sasl_dispose(&client->sasl_conn);
+ myfree((char *) client->callbacks);
+ vstring_free(client->decoded);
+ myfree((char *) client);
+}
+
+#endif
--- /dev/null
+#ifndef _CYRUS_COMMON_H_INCLUDED_
+#define _CYRUS_COMMON_H_INCLUDED_
+
+/*++
+/* NAME
+/* cyrus_common 3h
+/* SUMMARY
+/* Cyrus SASL plug-in helpers
+/* SYNOPSIS
+/* #include <cyrus_common.h>
+/* DESCRIPTION
+/* .nf
+
+ /*
+ * External interface.
+ */
+#if defined(USE_SASL_AUTH) && defined(USE_CYRUS_SASL)
+
+#define NO_SASL_LANGLIST ((const char *) 0)
+#define NO_SASL_OUTLANG ((const char **) 0)
+#define xsasl_cyrus_strerror(status) \
+ sasl_errstring((status), NO_SASL_LANGLIST, NO_SASL_OUTLANG)
+extern int xsasl_cyrus_log(void *, int, const char *);
+extern int xsasl_cyrus_security_parse_opts(const char *);
+
+#endif
+
+/* 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
+/*--*/
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* xsasl_cyrus_log 3
+/* SUMMARY
+/* Cyrus SASL logging call-back routine
+/* SYNOPSIS
+/* #include <xsasl_cyrus_common.h>
+/*
+/* int xsasl_cyrus_log(context, priority, text)
+/* void *context;
+/* int priority;
+/* const char *text;
+/* DESCRIPTION
+/* xsasl_cyrus_log() logs a Cyrus message.
+/* DIAGNOSTICS:
+/* Fatal: out of memory.
+/* 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 <msg.h>
+
+/* Application-specific */
+
+#include <xsasl_cyrus_common.h>
+
+#if defined(USE_SASL_AUTH) && defined(USE_CYRUS_SASL)
+
+#include <sasl.h>
+#include <saslutil.h>
+
+/* xsasl_cyrus_log - logging callback */
+
+int xsasl_cyrus_log(void *unused_context, int priority,
+ const char *message)
+{
+ switch (priority) {
+ case SASL_LOG_ERR: /* unusual errors */
+#ifdef SASL_LOG_WARN /* non-fatal warnings (Cyrus-SASL v2) */
+ case SASL_LOG_WARN:
+#endif
+#ifdef SASL_LOG_WARNING /* non-fatal warnings (Cyrus-SASL v1) */
+ case SASL_LOG_WARNING:
+#endif
+ msg_warn("SASL authentication problem: %s", message);
+ break;
+#ifdef SASL_LOG_INFO
+ case SASL_LOG_INFO: /* other info (Cyrus-SASL v1) */
+ if (msg_verbose)
+ msg_info("SASL authentication info: %s", message);
+ break;
+#endif
+#ifdef SASL_LOG_NOTE
+ case SASL_LOG_NOTE: /* other info (Cyrus-SASL v2) */
+ if (msg_verbose)
+ msg_info("SASL authentication info: %s", message);
+ break;
+#endif
+#ifdef SASL_LOG_FAIL
+ case SASL_LOG_FAIL: /* authentication failures
+ * (Cyrus-SASL v2) */
+ msg_warn("SASL authentication failure: %s", message);
+ break;
+#endif
+#ifdef SASL_LOG_DEBUG
+ case SASL_LOG_DEBUG: /* more verbose than LOG_NOTE
+ * (Cyrus-SASL v2) */
+ if (msg_verbose > 1)
+ msg_info("SASL authentication debug: %s", message);
+ break;
+#endif
+#ifdef SASL_LOG_TRACE
+ case SASL_LOG_TRACE: /* traces of internal
+ * protocols (Cyrus-SASL v2) */
+ if (msg_verbose > 1)
+ msg_info("SASL authentication trace: %s", message);
+ break;
+#endif
+#ifdef SASL_LOG_PASS
+ case SASL_LOG_PASS: /* traces of internal
+ * protocols, including
+ * passwords (Cyrus-SASL v2) */
+ if (msg_verbose > 1)
+ msg_info("SASL authentication pass: %s", message);
+ break;
+#endif
+ }
+ return (SASL_OK);
+}
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* xsasl_cyrus_security 3
+/* SUMMARY
+/* convert Cyrus SASL security properties to bit mask
+/* SYNOPSIS
+/* #include <xsasl_cyrus_common.h>
+/*
+/* int xsasl_cyrus_security_parse_opts(properties)
+/* const char *properties;
+/* DESCRIPTION
+/* xsasl_cyrus_security_parse_opts() converts a list of security
+/* properties to a bit mask. The result is zero in case of error.
+/*
+/* Arguments:
+/* .IP properties
+/* A comma or space separated list of zero or more of the
+/* following:
+/* .RS
+/* .IP noplaintext
+/* Disallow authentication methods that use plaintext passwords.
+/* .IP noactive
+/* Disallow authentication methods that are vulnerable to
+/* non-dictionary active attacks.
+/* .IP nodictionary
+/* Disallow authentication methods that are vulnerable to
+/* passive dictionary attack.
+/* .IP noanonymous
+/* Disallow anonymous logins.
+/* .RE
+/* DIAGNOSTICS:
+/* Warning: bad input.
+/* 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 <name_mask.h>
+
+/* Application-specific. */
+
+#include <xsasl_cyrus_common.h>
+
+#if defined(USE_SASL_AUTH) && defined(USE_CYRUS_SASL)
+
+#include <sasl.h>
+
+ /*
+ * SASL Security options.
+ */
+static NAME_MASK xsasl_cyrus_sec_mask[] = {
+ "noplaintext", SASL_SEC_NOPLAINTEXT,
+ "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,
+};
+
+/* xsasl_cyrus_security - parse security options */
+
+int xsasl_cyrus_security_parse_opts(const char *sasl_opts_val)
+{
+ return (name_mask_opt("SASL security options", xsasl_cyrus_sec_mask,
+ sasl_opts_val, NAME_MASK_RETURN));
+}
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* xsasl_cyrus_server 3
+/* SUMMARY
+/* Cyrus SASL server-side plug-in
+/* SYNOPSIS
+/* #include <xsasl_cyrus_server.h>
+/*
+/* XSASL_SERVER_IMPL *xsasl_cyrus_server_init(server_type, path_info)
+/* const char *server_type;
+/* const char *path_info;
+/* DESCRIPTION
+/* This module implements the Cyrus SASL server-side authentication
+/* plug-in.
+/*
+/* xsasl_cyrus_server_init() initializes the Cyrus SASL library and
+/* returns an implementation handle that can be used to generate
+/* SASL server instances.
+/*
+/* Arguments:
+/* .IP server_type
+/* The server type (cyrus). This argument is ignored, but it
+/* could be used when one implementation provides multiple
+/* variants.
+/* .IP path_info
+/* The base name of the SASL server configuration file (example:
+/* smtpd becomes /usr/lib/sasl2/smtpd.conf).
+/* DIAGNOSTICS
+/* Fatal: out of memory.
+/*
+/* Panic: interface violation.
+/*
+/* Other: the routines log a warning and return an error result
+/* as specified in xsasl_server(3).
+/* LICENSE
+/* .ad
+/* .fi
+/* The Secure Mailer license must be distributed with this software.
+/* AUTHOR(S)
+/* Initial implementation by:
+/* Till Franke
+/* SuSE Rhein/Main AG
+/* 65760 Eschborn, Germany
+/*
+/* Adopted by:
+/* Wietse Venema
+/* IBM T.J. Watson Research
+/* P.O. Box 704
+/* Yorktown Heights, NY 10598, USA
+/*--*/
+
+/* System library. */
+
+#include <sys_defs.h>
+#include <stdlib.h>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+#include <name_mask.h>
+#include <stringops.h>
+
+/* Global library. */
+
+#include <mail_params.h>
+
+/* Application-specific. */
+
+#include <xsasl.h>
+#include <xsasl_cyrus.h>
+#include <xsasl_cyrus_common.h>
+
+#if defined(USE_SASL_AUTH) && defined(USE_CYRUS_SASL)
+
+#include <sasl.h>
+#include <saslutil.h>
+
+/*
+ * Silly little macros.
+ */
+#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_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)
+typedef char *MECHANISM_TYPE;
+typedef unsigned MECHANISM_COUNT_TYPE;
+typedef char *SERVEROUT_TYPE;
+typedef void *VOID_SERVEROUT_TYPE;
+
+#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)
+typedef const char *MECHANISM_TYPE;
+typedef int MECHANISM_COUNT_TYPE;
+typedef const char *SERVEROUT_TYPE;
+typedef const void *VOID_SERVEROUT_TYPE;
+
+#endif
+
+ /*
+ * The XSASL_CYRUS_SERVER object is derived from the generic XSASL_SERVER
+ * object.
+ */
+typedef struct {
+ XSASL_SERVER xsasl; /* generic members, must be first */
+ VSTREAM *stream; /* client-server connection */
+ sasl_conn_t *sasl_conn; /* SASL context */
+ VSTRING *decoded; /* decoded challenge or response */
+ char *username; /* authenticated user */
+ char *mechanism_list; /* applicable mechanisms */
+} XSASL_CYRUS_SERVER;
+
+ /*
+ * Forward declarations.
+ */
+static void xsasl_cyrus_server_done(XSASL_SERVER_IMPL *);
+static XSASL_SERVER *xsasl_cyrus_server_create(XSASL_SERVER_IMPL *,
+ VSTREAM *,
+ const char *,
+ const char *,
+ const char *);
+static void xsasl_cyrus_server_free(XSASL_SERVER *);
+static int xsasl_cyrus_server_first(XSASL_SERVER *, const char *,
+ const char *, VSTRING *);
+static int xsasl_cyrus_server_next(XSASL_SERVER *, const char *, VSTRING *);
+static int xsasl_cyrus_server_set_security(XSASL_SERVER *, const char *);
+static const char *xsasl_cyrus_server_get_mechanism_list(XSASL_SERVER *);
+static const char *xsasl_cyrus_server_get_username(XSASL_SERVER *);
+
+ /*
+ * SASL callback interface structure. These call-backs have no per-session
+ * context.
+ */
+#define NO_CALLBACK_CONTEXT 0
+
+static sasl_callback_t callbacks[] = {
+ {SASL_CB_LOG, &xsasl_cyrus_log, NO_CALLBACK_CONTEXT},
+ {SASL_CB_LIST_END, 0, 0}
+};
+
+/* xsasl_cyrus_server_init - create implementation handle */
+
+XSASL_SERVER_IMPL *xsasl_cyrus_server_init(const char *unused_server_type,
+ const char *path_info)
+{
+ const char *myname = "xsasl_cyrus_server_init";
+ XSASL_SERVER_IMPL *xp;
+ int sasl_status;
+
+#if SASL_VERSION_MAJOR >= 2 && (SASL_VERSION_MINOR >= 2 \
+ || (SASL_VERSION_MINOR == 1 && SASL_VERSION_STEP >= 19))
+ int sasl_major;
+ int sasl_minor;
+ int sasl_step;
+
+ /*
+ * DLL hell guard.
+ */
+ sasl_version_info((const char **) 0, (const char **) 0,
+ &sasl_major, &sasl_minor,
+ &sasl_step, (int *) 0);
+ if (sasl_major != SASL_VERSION_MAJOR
+#if 0
+ || sasl_minor != SASL_VERSION_MINOR
+ || sasl_step != SASL_VERSION_STEP
+#endif
+ ) {
+ msg_warn("incorrect SASL library version. "
+ "Postfix was built with include files from version %d.%d.%d, "
+ "but the run-time library version is %d.%d.%d",
+ SASL_VERSION_MAJOR, SASL_VERSION_MINOR, SASL_VERSION_STEP,
+ sasl_major, sasl_minor, sasl_step);
+ return (0);
+ }
+#endif
+
+ /*
+ * Initialize the library: load SASL plug-in routines, etc.
+ */
+ if (msg_verbose)
+ msg_info("%s: SASL config file is %s.conf", myname, path_info);
+ if ((sasl_status = sasl_server_init(callbacks, path_info)) != SASL_OK) {
+ msg_warn("SASL per-process initialization failed: %s",
+ xsasl_cyrus_strerror(sasl_status));
+ return (0);
+ }
+
+ /*
+ * Return a generic XSASL_SERVER_IMPL object. We don't need to extend it
+ * with our own methods or data.
+ */
+ xp = (XSASL_SERVER_IMPL *) mymalloc(sizeof(*xp));
+ xp->create = xsasl_cyrus_server_create;
+ xp->done = xsasl_cyrus_server_done;
+ return (xp);
+}
+
+/* xsasl_cyrus_server_done - dispose of implementation */
+
+static void xsasl_cyrus_server_done(XSASL_SERVER_IMPL *impl)
+{
+ myfree((char *) impl);
+ sasl_done();
+}
+
+/* xsasl_cyrus_server_create - create server instance */
+
+static XSASL_SERVER *xsasl_cyrus_server_create(XSASL_SERVER_IMPL *unused_impl,
+ VSTREAM *stream,
+ const char *service,
+ const char *realm,
+ const char *sec_props)
+{
+ const char *myname = "xsasl_cyrus_server_create";
+ char *server_address;
+ char *client_address;
+ sasl_conn_t *sasl_conn = 0;
+ XSASL_CYRUS_SERVER *server = 0;
+ int sasl_status;
+
+ if (msg_verbose)
+ msg_info("%s: SASL service=%s, realm=%s",
+ myname, service, realm ? realm : "(null)");
+
+ /*
+ * The optimizer will eliminate duplication and/or dead code.
+ */
+#define XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(x) \
+ do { \
+ if (server) { \
+ xsasl_cyrus_server_free(&server->xsasl); \
+ } else { \
+ if (sasl_conn) \
+ sasl_dispose(&sasl_conn); \
+ } \
+ return (x); \
+ } while (0)
+
+ /*
+ * Set up a new server context.
+ */
+#define NO_SECURITY_LAYERS (0)
+#define NO_SESSION_CALLBACKS ((sasl_callback_t *) 0)
+#define NO_AUTH_REALM ((char *) 0)
+
+#if SASL_VERSION_MAJOR >= 2 && defined(USE_SASL_IP_AUTH)
+
+ /*
+ * Get IP addresses of local and remote endpoints for SASL.
+ */
+#error "USE_SASL_IP_AUTH is not implemented"
+
+#else
+
+ /*
+ * Don't give any IP address information to SASL. SASLv1 doesn't use it,
+ * and in SASLv2 this will disable any mechaniams that do.
+ */
+ server_address = 0;
+ client_address = 0;
+#endif
+
+ if ((sasl_status =
+ SASL_SERVER_NEW(service, var_myhostname,
+ realm ? realm : NO_AUTH_REALM,
+ server_address, client_address,
+ NO_SESSION_CALLBACKS, NO_SECURITY_LAYERS,
+ &sasl_conn)) != SASL_OK) {
+ msg_warn("SASL per-connection server initialization: %s",
+ xsasl_cyrus_strerror(sasl_status));
+ XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(0);
+ }
+
+ /*
+ * Extend the XSASL_SERVER_IMPL object with our own data. We use
+ * long-lived conversion buffers rather than local variables to avoid
+ * memory leaks in case of read/write timeout or I/O error.
+ */
+ server = (XSASL_CYRUS_SERVER *) mymalloc(sizeof(*server));
+ server->xsasl.free = xsasl_cyrus_server_free;
+ server->xsasl.first = xsasl_cyrus_server_first;
+ server->xsasl.next = xsasl_cyrus_server_next;
+ server->xsasl.get_mechanism_list = xsasl_cyrus_server_get_mechanism_list;
+ server->xsasl.get_username = xsasl_cyrus_server_get_username;
+ server->stream = stream;
+ server->sasl_conn = sasl_conn;
+ server->decoded = vstring_alloc(20);
+ server->username = 0;
+ server->mechanism_list = 0;
+
+ if (xsasl_cyrus_server_set_security(&server->xsasl, sec_props)
+ != XSASL_AUTH_OK)
+ XSASL_CYRUS_SERVER_CREATE_ERROR_RETURN(0);
+
+ return (&server->xsasl);
+}
+
+/* xsasl_cyrus_server_set_security - set security properties */
+
+static int xsasl_cyrus_server_set_security(XSASL_SERVER *xp,
+ const char *sasl_opts_val)
+{
+ XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
+ sasl_security_properties_t sec_props;
+ int sasl_status;
+
+ /*
+ * Security options. Some information can be found in the sasl.h include
+ * file.
+ */
+ memset(&sec_props, 0, sizeof(sec_props));
+ sec_props.min_ssf = 0;
+ sec_props.max_ssf = 0; /* don't allow real SASL
+ * security layer */
+ if (*sasl_opts_val == 0) {
+ sec_props.security_flags = 0;
+ } else {
+ sec_props.security_flags =
+ xsasl_cyrus_security_parse_opts(sasl_opts_val);
+ if (sec_props.security_flags == 0) {
+ msg_warn("bad per-session SASL security properties");
+ return (XSASL_AUTH_FAIL);
+ }
+ }
+ sec_props.maxbufsize = 0;
+ sec_props.property_names = 0;
+ sec_props.property_values = 0;
+
+ if ((sasl_status = sasl_setprop(server->sasl_conn, SASL_SEC_PROPS,
+ &sec_props)) != SASL_OK) {
+ msg_warn("SASL per-connection security setup; %s",
+ xsasl_cyrus_strerror(sasl_status));
+ return (XSASL_AUTH_FAIL);
+ }
+ return (XSASL_AUTH_OK);
+}
+
+/* xsasl_cyrus_server_get_mechanism_list - get available mechanisms */
+
+static const char *xsasl_cyrus_server_get_mechanism_list(XSASL_SERVER *xp)
+{
+ const char *myname = "xsasl_cyrus_server_get_mechanism_list";
+ XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
+ MECHANISM_TYPE mechanism_list;
+ MECHANISM_COUNT_TYPE mechanism_count;
+ int sasl_status;
+
+ /*
+ * Get the list of authentication mechanisms.
+ */
+#define UNSUPPORTED_USER ((char *) 0)
+#define IGNORE_MECHANISM_LEN ((unsigned *) 0)
+
+ if ((sasl_status = sasl_listmech(server->sasl_conn, UNSUPPORTED_USER,
+ "", " ", "",
+ &mechanism_list,
+ IGNORE_MECHANISM_LEN,
+ &mechanism_count)) != SASL_OK) {
+ msg_warn("%s: %s", myname, xsasl_cyrus_strerror(sasl_status));
+ return (0);
+ }
+ if (mechanism_count <= 0) {
+ msg_warn("%s: no applicable SASL mechanisms", myname);
+ return (0);
+ }
+ server->mechanism_list = mystrdup(mechanism_list);
+#if SASL_VERSION_MAJOR < 2
+ /* SASL version 1 doesn't free memory that it allocates. */
+ free(mechanism_list);
+#endif
+ return (server->mechanism_list);
+}
+
+/* xsasl_cyrus_server_free - destroy server instance */
+
+static void xsasl_cyrus_server_free(XSASL_SERVER *xp)
+{
+ XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
+
+ sasl_dispose(&server->sasl_conn);
+ vstring_free(server->decoded);
+ if (server->username)
+ myfree(server->username);
+ if (server->mechanism_list)
+ myfree(server->mechanism_list);
+ myfree((char *) server);
+}
+
+/* xsasl_cyrus_server_auth_response - encode server first/next response */
+
+static int xsasl_cyrus_server_auth_response(int sasl_status,
+ SERVEROUT_TYPE serverout,
+ unsigned serveroutlen,
+ VSTRING *reply)
+{
+ const char *myname = "xsasl_cyrus_server_auth_response";
+ unsigned enc_length;
+ unsigned enc_length_out;
+
+ /*
+ * Encode the server first/next non-error response; otherwise return the
+ * unencoded error text that corresponds to the SASL error status.
+ *
+ * Regarding the hairy expression below: output from sasl_encode64() 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.
+ */
+ if (sasl_status == SASL_OK) {
+ vstring_strcpy(reply, "");
+ return (XSASL_AUTH_DONE);
+ } else if (sasl_status == SASL_CONTINUE) {
+ if (msg_verbose)
+ msg_info("%s: uncoded server challenge: %.*s",
+ myname, (int) serveroutlen, serverout);
+ enc_length = ((serveroutlen + 2) / 3) * 4 + 1;
+ VSTRING_RESET(reply); /* Fix 200512 */
+ VSTRING_SPACE(reply, enc_length);
+ if ((sasl_status = sasl_encode64(serverout, serveroutlen,
+ STR(reply), vstring_avail(reply),
+ &enc_length_out)) != SASL_OK)
+ msg_panic("%s: sasl_encode64 botch: %s",
+ myname, xsasl_cyrus_strerror(sasl_status));
+ return (XSASL_AUTH_MORE);
+ } else {
+ vstring_strcpy(reply, xsasl_cyrus_strerror(sasl_status));
+ return (XSASL_AUTH_FAIL);
+ }
+}
+
+/* xsasl_cyrus_server_first - per-session authentication */
+
+int xsasl_cyrus_server_first(XSASL_SERVER *xp, const char *sasl_method,
+ const char *init_response, VSTRING *reply)
+{
+ char *myname = "xsasl_cyrus_server_first";
+ XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
+ char *dec_buffer;
+ unsigned dec_length;
+ unsigned reply_len;
+ unsigned serveroutlen;
+ int sasl_status;
+ SERVEROUT_TYPE serverout = 0;
+ int xsasl_status;
+
+#if SASL_VERSION_MAJOR < 2
+ const char *errstr = 0;
+
+#endif
+
+#define IFELSE(e1,e2,e3) ((e1) ? (e2) : (e3))
+
+ if (msg_verbose)
+ msg_info("%s: sasl_method %s%s%s", myname, sasl_method,
+ IFELSE(init_response, ", init_response ", ""),
+ IFELSE(init_response, init_response, ""));
+
+ /*
+ * SASL authentication protocol start-up. Process any initial client
+ * response that was sent along in the AUTH command.
+ */
+ if (init_response) {
+ reply_len = strlen(init_response);
+ VSTRING_RESET(server->decoded); /* Fix 200512 */
+ VSTRING_SPACE(server->decoded, reply_len);
+ if ((sasl_status = SASL_DECODE64(init_response, reply_len,
+ dec_buffer = STR(server->decoded),
+ vstring_avail(server->decoded),
+ &dec_length)) != SASL_OK) {
+ vstring_strcpy(reply, xsasl_cyrus_strerror(sasl_status));
+ return (XSASL_AUTH_FORM);
+ }
+ if (msg_verbose)
+ msg_info("%s: decoded initial response %s", myname, dec_buffer);
+ } else {
+ dec_buffer = 0;
+ dec_length = 0;
+ }
+ sasl_status = SASL_SERVER_START(server->sasl_conn, sasl_method, dec_buffer,
+ dec_length, &serverout,
+ &serveroutlen, &errstr);
+ xsasl_status = xsasl_cyrus_server_auth_response(sasl_status, serverout,
+ serveroutlen, reply);
+#if SASL_VERSION_MAJOR < 2
+ /* SASL version 1 doesn't free memory that it allocates. */
+ free(serverout);
+#endif
+ return (xsasl_status);
+}
+
+/* xsasl_cyrus_server_next - continue authentication */
+
+static int xsasl_cyrus_server_next(XSASL_SERVER *xp, const char *request,
+ VSTRING *reply)
+{
+ char *myname = "xsasl_cyrus_server_next";
+ XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
+ unsigned dec_length;
+ unsigned request_len;
+ unsigned serveroutlen;
+ int sasl_status;
+ SERVEROUT_TYPE serverout = 0;
+ int xsasl_status;
+
+#if SASL_VERSION_MAJOR < 2
+ const char *errstr = 0;
+
+#endif
+
+ request_len = strlen(request);
+ VSTRING_RESET(server->decoded); /* Fix 200512 */
+ VSTRING_SPACE(server->decoded, request_len);
+ if ((sasl_status = SASL_DECODE64(request, request_len,
+ STR(server->decoded),
+ vstring_avail(server->decoded),
+ &dec_length)) != SASL_OK) {
+ vstring_strcpy(reply, xsasl_cyrus_strerror(sasl_status));
+ return (XSASL_AUTH_FORM);
+ }
+ if (msg_verbose)
+ msg_info("%s: decoded response: %.*s",
+ myname, (int) dec_length, STR(server->decoded));
+ sasl_status = SASL_SERVER_STEP(server->sasl_conn, STR(server->decoded),
+ dec_length, &serverout,
+ &serveroutlen, &errstr);
+ xsasl_status = xsasl_cyrus_server_auth_response(sasl_status, serverout,
+ serveroutlen, reply);
+#if SASL_VERSION_MAJOR < 2
+ /* SASL version 1 doesn't free memory that it allocates. */
+ free(serverout);
+#endif
+ return (xsasl_status);
+}
+
+/* xsasl_cyrus_server_get_username - get authenticated username */
+
+static const char *xsasl_cyrus_server_get_username(XSASL_SERVER *xp)
+{
+ const char *myname = "xsasl_cyrus_server_get_username";
+ XSASL_CYRUS_SERVER *server = (XSASL_CYRUS_SERVER *) xp;
+ VOID_SERVEROUT_TYPE serverout = 0;
+ int sasl_status;
+
+ /*
+ * XXX Do not free(serverout).
+ */
+ sasl_status = sasl_getprop(server->sasl_conn, SASL_USERNAME, &serverout);
+ if (sasl_status != SASL_OK || serverout == 0) {
+ msg_warn("%s: sasl_getprop SASL_USERNAME botch: %s",
+ myname, xsasl_cyrus_strerror(sasl_status));
+ return (0);
+ }
+ if (server->username)
+ myfree(server->username);
+ server->username = mystrdup(serverout);
+ printable(server->username, '?');
+ return (server->username);
+}
+
+#endif
--- /dev/null
+/*++
+/* NAME
+/* xsasl-server 3
+/* SUMMARY
+/* Postfix SASL server plug-in interface
+/* SYNOPSIS
+/* #include <xsasl.h>
+/*
+/* XSASL_SERVER_IMPL *xsasl_server_init(server_type, path_info)
+/* const char *server_type;
+/* const char *path_info;
+/*
+/* void xsasl_server_done(implementation)
+/* XSASL_SERVER_IMPL *implementation;
+/*
+/* ARGV *xsasl_server_types()
+/*
+/* XSASL_SERVER *xsasl_server_create(implementation, stream, service,
+/* user_realm, security_options)
+/* XSASL_SERVER_IMPL *implementation;
+/* const char *service;
+/* VSTREAM *stream;
+/* const char *user_realm;
+/* const char *security_options;
+/*
+/* void xsasl_server_free(server)
+/* XSASL_SERVER *server;
+/*
+/* int xsasl_server_first(server, auth_method, init_resp, server_reply)
+/* XSASL_SERVER *server;
+/* const char *auth_method;
+/* const char *init_resp;
+/* VSTRING *server_reply;
+/*
+/* int xsasl_server_next(server, client_request, server_reply)
+/* XSASL_SERVER *server;
+/* const char *client_request;
+/* VSTRING *server_reply;
+/*
+/* const char *xsasl_server_get_mechanism_list(server)
+/* XSASL_SERVER *server;
+/*
+/* const char *xsasl_server_get_username(server)
+/* XSASL_SERVER *server;
+/* DESCRIPTION
+/* The XSASL_SERVER abstraction implements a generic interface
+/* to one or more SASL authentication implementations.
+/*
+/* xsasl_server_init() is called once during process initialization.
+/* It selects a SASL implementation by name, specifies the
+/* location of a configuration file or rendez-vous point, and
+/* returns an implementation handle that can be used to generate
+/* SASL server instances. This function is typically used to
+/* initialize the underlying implementation.
+/*
+/* xsasl_server_done() disposes of an implementation handle,
+/* and allows the underlying implementation to release resources.
+/*
+/* xsasl_server_types() lists the available implementation types.
+/* The result should be destroyed by the caller.
+/*
+/* xsasl_server_create() is called at the start of an SMTP
+/* session. It generates a Postfix SASL plug-in server instance
+/* for the specified service and authentication realm, and
+/* with the specified security properties. Specify a null
+/* pointer when no realm should be used. The stream handle is
+/* stored so that encryption can be turned on after successful
+/* negotiations.
+/*
+/* xsasl_server_free() is called at the end of an SMTP session.
+/* It destroys a SASL server instance, and disables further
+/* read/write operations if encryption was turned on.
+/*
+/* xsasl_server_first() produces the server reponse for the
+/* client AUTH command. The client input are an authentication
+/* method, and an optional initial response or null pointer.
+/* The initial response and server non-error replies are BASE64
+/* encoded. Server error replies are 7-bit ASCII text without
+/* control characters, without BASE64 encoding, and without
+/* SMTP reply code or enhanced status code.
+/*
+/* The result is one of the following:
+/* .IP XSASL_AUTH_MORE
+/* More client input is needed. The server reply specifies
+/* what.
+/* .IP XSASL_AUTH_DONE
+/* Authentication completed successfully.
+/* .IP XSASL_AUTH_FORM
+/* The client input is incorrectly formatted. The server error
+/* reply explains why.
+/* .IP XSASL_AUTH_FAIL
+/* Authentication failed. The server error reply explains why.
+/* .PP
+/* xsasl_server_next() supports the subsequent stages of the
+/* client-server AUTH protocol. Both the client input and
+/* server non-error responses are BASE64 encoded. See
+/* xsasl_server_first() for other details.
+/*
+/* xsasl_server_get_mechanism_list() returns the authentication
+/* mechanisms that match the security properties, as a white-space
+/* separated list. This is meant to be used in the SMTP EHLO
+/* reply.
+/*
+/* xsasl_server_get_username() returns the stored username
+/* after successful authentication.
+/*
+/* Arguments:
+/* .IP auth_method
+/* AUTH command authentication method.
+/* .IP init_resp
+/* AUTH command initial response or null pointer.
+/* .IP implementation
+/* Implementation handle that was obtained with xsasl_server_init().
+/* .IP path_info
+/* The value of the smtpd_sasl_path parameter or equivalent.
+/* This specifies the implementation-dependent location of a
+/* configuration file, rendez-vous point, etc., and is passed
+/* unchanged to the plug-in.
+/* .IP security_options
+/* The value of the smtpd_security_options parameter or
+/* equivalent. This is passed unchanged to the plug-in.
+/* .IP server
+/* SASL plug-in server handle.
+/* .IP server_reply
+/* BASE64 encoded server non-error reply (without SMTP reply
+/* code or enhanced status code), or ASCII error description.
+/* .IP server_type
+/* The name of a Postfix SASL server plug_in implementation.
+/* .IP server_types
+/* Null-terminated array of strings with SASL server plug-in
+/* implementation names.
+/* .IP service
+/* The service that is implemented by the local server, typically
+/* "smtp" or "lmtp".
+/* .IP stream
+/* The connection between client and server. When SASL
+/* encryption is negotiated, the plug-in will transparently
+/* intercept the socket read/write operations.
+/* .IP user_realm
+/* Authentication domain or null pointer.
+/* SECURITY
+/* .ad
+/* .fi
+/* The caller does not sanitize client input. It is the
+/* responsibility of the underlying SASL server implementation
+/* to produce 7-bit ASCII without control characters as server
+/* non-error and error replies, and as the result from
+/* xsasl_server_method() and xsasl_server_username().
+/* DIAGNOSTICS
+/* In case of failure, xsasl_server_init(), xsasl_server_create(),
+/* xsasl_server_get_mechanism_list() and xsasl_server_get_username()
+/* log a warning and return a null pointer.
+/*
+/* Functions that normally return XSASL_AUTH_OK will log a warning
+/* and return an appropriate result value.
+/*
+/* Fatal errors: out of memory.
+/*
+/* Panic: interface violations.
+/* SEE ALSO
+/* cyrus_security(3) Cyrus SASL security features
+/* 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>
+#include <string.h>
+
+/* Utility library. */
+
+#include <msg.h>
+#include <mymalloc.h>
+
+/* SASL implementations. */
+
+#include <xsasl.h>
+#include <xsasl_cyrus.h>
+
+ /*
+ * Lookup table for available SASL server implementations.
+ */
+typedef struct {
+ char *server_type;
+ struct XSASL_SERVER_IMPL *(*server_init) (const char *, const char *);
+} XSASL_SERVER_IMPL_INFO;
+
+static XSASL_SERVER_IMPL_INFO server_impl_info[] = {
+#ifdef XSASL_TYPE_CYRUS
+ XSASL_TYPE_CYRUS, xsasl_cyrus_server_init,
+#endif
+ 0,
+};
+
+/* xsasl_server_init - look up server implementation by name */
+
+XSASL_SERVER_IMPL *xsasl_server_init(const char *server_type,
+ const char *path_info)
+{
+ XSASL_SERVER_IMPL_INFO *xp;
+
+ for (xp = server_impl_info; xp->server_type; xp++)
+ if (strcmp(server_type, xp->server_type) == 0)
+ return (xp->server_init(server_type, path_info));
+ msg_warn("unsupported SASL server implementation: %s", server_type);
+ return (0);
+}
+
+/* xsasl_server_types - report available implementation types */
+
+ARGV *xsasl_server_types(void)
+{
+ XSASL_SERVER_IMPL_INFO *xp;
+ ARGV *argv = argv_alloc(1);
+
+ for (xp = server_impl_info; xp->server_type; xp++)
+ argv_add(argv, xp->server_type, ARGV_END);
+ return (argv);
+}