Go to:
Gentoo Home
Documentation
Forums
Lists
Bugs
Planet
Store
Wiki
Get Gentoo!
Gentoo's Bugzilla – Attachment 2260 Details for
Bug 5023
postfix-1.1.11.20020613.ebuild + tls + ipv6
Home
|
New
–
[Ex]
|
Browse
|
Search
|
Privacy Policy
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
tls + ipv6 Patch
tls+ipv6-1.1.11-20020613.patch (text/plain), 337.81 KB, created by
Philipp Morger
on 2002-07-15 08:28:11 UTC
(
hide
)
Description:
tls + ipv6 Patch
Filename:
MIME Type:
Creator:
Philipp Morger
Created:
2002-07-15 08:28:11 UTC
Size:
337.81 KB
patch
obsolete
>diff -Pur postfix-1.1.11.20020613-orig/Makefile.in postfix-1.1.11-20020613/Makefile.in >--- postfix-1.1.11.20020613-orig/Makefile.in Sat Jun 8 20:49:42 2002 >+++ postfix-1.1.11.20020613/Makefile.in Wed Jun 26 15:26:47 2002 >@@ -6,7 +6,8 @@ > src/lmtp src/trivial-rewrite src/qmgr src/smtp src/bounce src/pipe \ > src/showq src/postalias src/postcat src/postconf src/postdrop \ > src/postkick src/postlock src/postlog src/postmap src/postqueue \ >- src/postsuper src/nqmgr src/qmqpd src/spawn src/flush src/virtual >+ src/postsuper src/nqmgr src/qmqpd src/spawn src/flush src/virtual \ >+ src/tlsmgr > MANDIRS = proto man html > > default: update >diff -Pur postfix-1.1.11.20020613-orig/conf/master.cf postfix-1.1.11-20020613/conf/master.cf >--- postfix-1.1.11.20020613-orig/conf/master.cf Sat Jun 8 20:21:38 2002 >+++ postfix-1.1.11.20020613/conf/master.cf Wed Jun 26 15:26:47 2002 >@@ -70,11 +70,16 @@ > # (yes) (yes) (yes) (never) (50) > # ========================================================================== > smtp inet n - n - - smtpd >+#smtps inet n - n - - smtpd >+# -o smtpd_tls_wrappermode=yes -o smtpd_sasl_auth_enable=yes >+#submission inet n - n - - smtpd >+# -o smtpd_enforce_tls=yes -o smtpd_sasl_auth_enable=yes > #628 inet n - n - - qmqpd > pickup fifo n - n 60 1 pickup > cleanup unix n - n - 0 cleanup > qmgr fifo n - n 300 1 qmgr > #qmgr fifo n - n 300 1 nqmgr >+#tlsmgr fifo - - n 300 1 tlsmgr > rewrite unix - - n - - trivial-rewrite > bounce unix - - n - 0 bounce > defer unix - - n - 0 bounce >diff -Pur postfix-1.1.11.20020613-orig/conf/postfix-files postfix-1.1.11-20020613/conf/postfix-files >--- postfix-1.1.11.20020613-orig/conf/postfix-files Sun May 26 23:27:31 2002 >+++ postfix-1.1.11.20020613/conf/postfix-files Wed Jun 26 15:26:47 2002 >@@ -69,6 +69,7 @@ > $daemon_directory/smtp:f:root:-:755 > $daemon_directory/smtpd:f:root:-:755 > $daemon_directory/spawn:f:root:-:755 >+$daemon_directory/tlsmgr:f:root:-:755 > $daemon_directory/trivial-rewrite:f:root:-:755 > $daemon_directory/virtual:f:root:-:755 > $command_directory/postalias:f:root:-:755 >@@ -139,6 +140,7 @@ > $manpage_directory/man8/smtp.8:f:root:-:644 > $manpage_directory/man8/smtpd.8:f:root:-:644 > $manpage_directory/man8/spawn.8:f:root:-:644 >+$manpage_directory/man8/tlsmgr.8:f:root:-:644 > $manpage_directory/man8/trivial-rewrite.8:f:root:-:644 > $manpage_directory/man8/virtual.8:f:root:-:644 > $sample_directory/sample-aliases.cf:f:root:-:644 >@@ -166,6 +168,7 @@ > $sample_directory/sample-rewrite.cf:f:root:-:644 > $sample_directory/sample-smtp.cf:f:root:-:644 > $sample_directory/sample-smtpd.cf:f:root:-:644 >+$sample_directory/sample-tls.cf:f:root:-:644 > $sample_directory/sample-transport.cf:f:root:-:644 > $sample_directory/sample-virtual.cf:f:root:-:644 > $readme_directory/DB_README:f:root:-:644 >diff -Pur postfix-1.1.11.20020613-orig/conf/sample-auth.cf postfix-1.1.11-20020613/conf/sample-auth.cf >--- postfix-1.1.11.20020613-orig/conf/sample-auth.cf Fri Mar 29 22:36:53 2002 >+++ postfix-1.1.11.20020613/conf/sample-auth.cf Wed Jun 26 15:26:47 2002 >@@ -117,3 +117,15 @@ > # > #smtp_sasl_security_options = > smtp_sasl_security_options = noplaintext >+ >+# Sending AUTH data over an unencrypted channel poses a security risk. When >+# smtpd_tls_enforce_tls is set, AUTH will only be announced and accepted, >+# once the TLS layer has been activated via the STARTTLS protocol. If >+# TLS layer encryption is optional, it may however still be useful to only >+# offer AUTH, when TLS is active. To not break compatiblity with unpatched >+# postfix versions, the default is to accept AUTH without encryption. In >+# order to change this behaviour, set smtpd_tls_auth_only = yes. >+# THIS OPTION ONLY WORKS WITH SSL/TLS SUPPORT COMPILED IN. >+# >+# smtpd_tls_auth_only = no >+ >diff -Pur postfix-1.1.11.20020613-orig/conf/sample-smtp.cf postfix-1.1.11-20020613/conf/sample-smtp.cf >--- postfix-1.1.11.20020613-orig/conf/sample-smtp.cf Tue Mar 26 22:46:30 2002 >+++ postfix-1.1.11.20020613/conf/sample-smtp.cf Wed Jun 26 15:26:47 2002 >@@ -188,6 +188,14 @@ > # > smtp_helo_timeout = 300s > >+# The smtp_starttls_timeout parameter limits the time in seconds to write and >+# read operations during TLS start and stop handhake procedures. >+# >+# In case of problems the client does NOT try the next address on >+# the mail exchanger list. >+# >+# smtp_starttls_timeout = 300s >+ > # The smtp_mail_timeout parameter specifies the SMTP client timeout > # for sending the SMTP MAIL FROM command, and for receiving the server > # response. >diff -Pur postfix-1.1.11.20020613-orig/conf/sample-smtpd.cf postfix-1.1.11-20020613/conf/sample-smtpd.cf >--- postfix-1.1.11.20020613-orig/conf/sample-smtpd.cf Sat Jun 8 20:21:38 2002 >+++ postfix-1.1.11.20020613/conf/sample-smtpd.cf Wed Jun 26 15:26:47 2002 >@@ -116,6 +116,11 @@ > # > strict_rfc821_envelopes = no > >+# The smtpd_starttls_timeout parameter limits the time in seconds to write and >+# read operations during TLS start and stop handhake procedures. >+# >+# smtpd_starttls_timeout = 300s >+ > # > # TARPIT CONTROLS > # >diff -Pur postfix-1.1.11.20020613-orig/conf/sample-tls.cf postfix-1.1.11-20020613/conf/sample-tls.cf >--- postfix-1.1.11.20020613-orig/conf/sample-tls.cf Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11.20020613/conf/sample-tls.cf Wed Jun 26 15:26:47 2002 >@@ -0,0 +1,497 @@ >+# DO NOT EDIT THIS FILE. EDIT THE MAIN.CF FILE INSTEAD. THE STUFF >+# HERE JUST SERVES AS AN EXAMPLE. >+# >+# This file contains example settings of Postfix configuration >+# parameters that control the behaviour of the TLS extensions. >+# >+# We strictly seperate between server side TLS (smtpd_) and client side >+# TLS (smtp_), as for practical reasons we might choose differently. >+ >+# Section with SMTPD specific settings >+ >+# To use TLS we do need a certificate and a private key. Both must be in >+# "pem" format, the private key must not be encrypted, that does mean: >+# it must be accessable without password. Both parts (certificate and >+# private key) may be in the same file. >+# >+# Both RSA and DSA are certificates are supported. Typically you will only >+# have RSA certificates issued by a commercial CA, also the tools supplied >+# with OpenSSL will by default issue RSA certificates. >+# You can have both at the same time, in this case the cipher used decides, >+# which certificate is presented. For Netscape and OpenSSL clients without >+# special cipher choices, the RSA certificate is preferred. >+# >+# In order to check the certificates, the CA-certificate (in case of a >+# certificate chain, all CA-certificates) must be available. >+# You should add these certificates to the server certificate, the server >+# certificate first, then the issuing CA(s). >+# >+# Example: the certificate for "server.dom.ain" was issued by "intermediate CA" >+# which itself has a certificate of "root CA". Create the server.pem file by >+# 'cat server_cert.pem intemediate_CA.pem root_CA.pem > server.pem' >+# >+# If you want to accept certificates issued by these CAs yourself, you can >+# also add the CA-certificates to the smtpd_tls_CAfile, in which case it is >+# not necessary to have them in the smtpd_tls_[d]cert_file. >+# >+# A certificate supplied here must be useable as SSL server certificate and >+# hence pass the "openssl verify -purpose sslserver ..." test. >+# >+smtpd_tls_cert_file = /etc/postfix/server.pem >+smtpd_tls_key_file = $smtpd_tls_cert_file >+# >+# Its DSA counterparts: >+smtpd_tls_dcert_file = /etc/postfix/server-dsa.pem >+smtpd_tls_dkey_file = $smtpd_tls_dcert_file >+ >+# The certificate was issued by a certification authority (CA), the CA-cert >+# of which must be available, if not in the certificate file. >+# This file may also contain the the CA certificates of other trusted CAs. >+# You must use this file for the list of trusted CAs if you want to use >+# chroot-mode. No default is supplied for this value as of now. >+# >+# smtpd_tls_CAfile = /etc/postfix/CAcert.pem >+ >+# To verify the peer certificate, we need to know the certificates of >+# certification authorities. These certificates in "pem" format are >+# collected in a directory. The same CAs are offered to clients for >+# client verification. Don't forget to create the necessary "hash" >+# links with $OPENSSL_HOME/bin/c_rehash /etc/postfix/certs. A typical >+# place for the CA-certs may also be $OPENSSL_HOME/certs, so there is >+# no default and you explicitly have to set the value here! >+# >+# To use this option in chroot mode, this directory itself or a copy of it >+# must be inside the chroot jail. Please note also, that the CAs in this >+# directory are not listed to the client, so that e.g. Netscape might not >+# offer certificates issued by them. >+# >+# I therefore discourage the use of this option. >+# >+smtpd_tls_CApath = /etc/postfix/certs >+ >+# To get additional information during the TLS setup and negotiations >+# you can increase the loglevel from 0..4: >+# 0: No output about the TLS subsystem >+# 1: Printout startup and certificate information >+# 2: 1 + Printout of levels during negotiation >+# 3: 2 + Hex and ASCII dump of negotiation process >+# 4: 3 + Hex and ASCII dump of complete transmission after STARTTLS >+# Use loglevel 3 only in case of problems. Use of loglevel 4 is strongly >+# discouraged. >+# >+# smtpd_tls_loglevel = 0 >+ >+# To include information about the protocol and cipher used as well as the >+# client and issuer CommonName into the "Received:" header, set the >+# smtpd_tls_received_header variable to true. The default is no, as the >+# information is not necessarily authentic. Only the final destination >+# is reliable, since the headers might have been changed in between. >+# >+#smtpd_tls_received_header = yes >+ >+# By default TLS is disabled, so no difference to plain postfix is visible. >+# Explicitely switch it on using "smtpd_use_tls". (Note: when invoked >+# via "sendmail -bs", STARTTLS is never offered due to insufficient >+# privileges to access the private key. This is intended behaviour.) >+# >+smtpd_use_tls = yes >+ >+# You can ENFORCE the use of TLS, so that no commands (except QUIT of course) >+# are allowed without TLS. According to RFC2487 this MUST NOT be applied >+# in case of a publicly-referenced SMTP server. So this option is off >+# by default and should only seldom be used. Using this option implies >+# smtpd_use_tls = yes. (Note: when invoked via "sendmail -bs", STARTTLS >+# is never offered due to insufficient privileges to access the private key. >+# This is intended behaviour.) >+# >+# smtpd_enforce_tls = no >+ >+# Besides RFC2487 some clients, namely Outlook [Express] prefer to run the >+# non-standard "wrapper" mode, not the STARTTLS enhancement to SMTP. >+# This is true for OE (Win32 < 5.0 and Win32 >=5.0 when run on a port!=25 >+# and OE (5.01 Mac on all ports). >+# It is strictly discouraged to use this mode from main.cf. If you want to >+# support this service, enable a special port in master.cf. Port 465 (smtps) >+# was once chosen for this feature. >+# >+# smtpd_tls_wrappermode = no >+ >+# To receive a client certificate, the server must explicitly ask for one. >+# Hence netscape will either complain if no certificate is available (for >+# the list of CAs in /etc/postfix/certs) or will offer you client certificates >+# to choose from. This might be annoying, so this option is "off" by default. >+# You will however need the certificate if you want to to e.g. certificate >+# based relaying. >+# >+# smtpd_tls_ask_ccert = no >+ >+# You may also decide to REQUIRE a client certificate to allow TLS connections. >+# I don't think it will be necessary often, it is however included here for >+# completeness. This option implies smtpd_tls_ask_ccert = yes >+# >+# Please be aware, that this will inhibit TLS connections without a proper >+# certificate and only makes sense, when normal submission is disabled and >+# TLS is enforced (smtpd_enforce_tls). Otherwise clients may bypass by simply >+# not using STARTTLS at all. When TLS is not enforced, the connection will be >+# handled, as if only smtpd_tls_ask_ccert = yes would be set and an information >+# is logged. >+# >+# smtpd_tls_req_ccert = no >+ >+# The verification depth for client certificates. A depth of 1 is sufficient, >+# if the certificate ist directly issued by a CA listed in the CA locations. >+# The default value (5) should also suffice for longer chains (root CA issues >+# special CA which then issues the actual certificate...) >+# >+# smtpd_tls_ccert_verifydepth = 5 >+ >+# Sending AUTH data over an unencrypted channel poses a security risk. When >+# smtpd_tls_enforce_tls is set, AUTH will only be announced and accepted, >+# once the TLS layer has been activated via the STARTTLS protocol. If >+# TLS layer encryption is optional, it may however still be useful to only >+# offer AUTH, when TLS is active. To not break compatiblity with unpatched >+# postfix versions, the default is to accept AUTH without encryption. In >+# order to change this behaviour, set smtpd_tls_auth_only = yes. >+# >+# smtpd_tls_auth_only = no >+ >+# The server and client negotiate a session, which takes some computer time >+# and network bandwidth. The session is cached only in the smtpd process >+# actually using this session and is lost when the process dies. >+# To share the session information between the smtpd processes, a disc based >+# session cache can be used based on the SDBM databases (routines included >+# in Postfix/TLS). Since concurrent writing must be supported, only SDBM >+# can be used. >+# >+smtpd_tls_session_cache_database = sdbm:/etc/postfix/smtpd_scache >+ >+# The cached sessions time out after a certain amount of time. For Postfix/TLS >+# I do not use the OpenSSL default of 300sec, but a longer time of 3600sec >+# (=1 hour). RFC2246 recommends a maximum of 24 hours. >+# >+# smtpd_tls_session_cache_timeout = 3600s >+ >+# Two additional options has been added for relay control to the UCE rules: >+# permit_tls_clientcerts (a) >+# and >+# permit_tls_all_clientcerts. (b) >+# >+# If one of these options is added to >+# smtpd_recipient_restrictions, >+# postfix will relay if >+# (a) a valid (it passed the verification) client certificate is presented >+# and its fingerprint is listed in the list of client certs >+# (relay_clientcerts), >+# (b) any valid (it passed the verification) client certificate is presented. >+# >+# Option (b) must only be used, if a special CA issues the certificates and >+# only this CA is listed as trusted CA. If other CAs are trusted, any owner >+# of a valid (SSL client)-certificate can relay. Option (b) can be practical >+# for a specically created email relay. It is however recommended to stay with >+# option (a) and list all certificates, as (b) does not permit any control >+# when a certificate must no longer be used (e.g. an employee leaving). >+# >+# smtpd_recipient_restrictions = ... permit_tls_clientcerts ... >+ >+# The list of client certificates for which relaying will be allowed. >+# Unfortunately the routines for lists in postfix use whitespaces as >+# seperators and choke on special chars. So using the certificate >+# X509ONELINES is quite impractical. We will use the fingerprints at >+# this point, as they are difficult to fake but easy to use for lookup. >+# As postmap (when using e.g. db) insists of having a pair of key and value, >+# but we only need the key, the value can be chosen freely, e.g. the name >+# of the user or host: >+# D7:04:2F:A7:0B:8C:A5:21:FA:31:77:E1:41:8A:EE:80 lutzpc.at.home >+# >+# relay_clientcerts = hash:/etc/postfix/relay_clientcerts >+ >+# To influence the cipher selection scheme, you can give cipherlist-string. >+# A detailed description would go to far here, please refer to the openssl >+# documentation. >+# If you don't know what to do with it, simply don't touch it and leave the >+# (openssl-)compiled in default! >+# >+# DO NOT USE " to enclose the string, just the string!!! >+# >+# smtpd_tls_cipherlist = DEFAULT >+ >+# If you want to take advantage of ciphers with EDH, DH parameters are needed. >+# There are built in DH parameters for both 1025bit and 512bit available. It >+# is however better to have "own" parameters, since otherwise it would "pay" >+# for a possible attacker to start a brute force attack against these >+# parameters commonly used by everybody. For this reason, the parameters >+# chosen are already different from those distributed with other TLS packages. >+# >+# To generate your own set of parameters, use >+# openssl gendh -out /etc/postfix/dh_1024.pem -2 -rand /var/run/egd-pool 1024 >+# openssl gendh -out /etc/postfix/dh_512.pem -2 -rand /var/run/egd-pool 512 >+# (your source for "entropy" might vary; on Linux there is /dev/random, on >+# other system, you might consider the "Entropy Gathering Daemon EGD", >+# available at http://www.lothar.com/tech/crypto/. >+# >+smtpd_tls_dh1024_param_file = /etc/postfix/dh_1024.pem >+smtpd_tls_dh512_param_file = /etc/postfix/dh_512.pem >+ >+# The smtpd_starttls_timeout parameter limits the time in seconds to write and >+# read operations during TLS start and stop handhake procedures. >+# >+# smtpd_starttls_timeout = 300s >+ >+# Section with SMTP specific settings >+ >+# During the startup negotiation we might present a certificate to the server. >+# Netscape is rather clever here and lets the user select between only those >+# certs that will match the CAs accepted from the server. As I simply use >+# the integrated "SSL_connect()" from the OpenSSL package, this is not >+# possible by now and we have to chose just one cert. >+# So for now the default is to use _no_ cert and key unless explictly >+# set here. It is possible to use the same key/cert pair as for the server. >+# If a cert is to be presented, it must be in "pem" format, the private key >+# must not be encrypted, that does mean: it must be accessable without >+# password. Both parts (certificate and private key) may be in the >+# same file. >+# >+# In order to check the certificates, the CA-certificate (in case of a >+# certificate chain, all CA-certificates) must be available. >+# You should add these certificates to the server certificate, the server >+# certificate first, then the issuing CA(s). >+# >+# Example: the certificate for "client.dom.ain" was issued by "intermediate CA" >+# which itself has a certificate of "root CA". Create the client.pem file by >+# 'cat client_cert.pem intemediate_CA.pem root_CA.pem > client.pem' >+# >+# If you want to accept certificates issued by these CAs yourself, you can >+# also add the CA-certificates to the smtp_tls_CAfile, in which case it is >+# not necessary to have them in the smtp_tls_[d]cert_file. >+# >+# A certificate supplied here must be useable as SSL client certificate and >+# hence pass the "openssl verify -purpose sslclient ..." test. >+# >+smtp_tls_cert_file = /etc/postfix/client.pem >+smtp_tls_key_file = $smtp_tls_cert_file >+ >+# The certificate was issued by a certification authority (CA), the CA-cert >+# of which must be available, if not in the certificate file. >+# This file may also contain the the CA certificates of other trusted CAs. >+# You must use this file for the list of trusted CAs if you want to use >+# chroot-mode. No default is supplied for this value as of now. >+# >+smtp_tls_CAfile = /etc/postfix/CAcert.pem >+ >+# To verify the peer certificate, we need to know the certificates of >+# certification authorities. These certificates in "pem" format are >+# collected in a directory. Don't forget to create the necessary "hash" >+# links with $OPENSSL_HOME/bin/c_rehash /etc/postfix/certs. A typical >+# place for the CA-certs may also be $OPENSSL_HOME/certs, so there is >+# no default and you explicitly have to set the value here! >+# >+# To use this option in chroot mode, this directory itself or a copy of it >+# must be inside the chroot jail. >+# >+smtp_tls_CApath = /etc/postfix/certs >+ >+# To get additional information during the TLS setup and negotiations >+# you can increase the loglevel from 0..4: >+# 0: No output about the TLS subsystem >+# 1: Printout startup and certificate information >+# 2: 1 + Printout of levels during negotiation >+# 3: 2 + Hex and ASCII dump of negotiation process >+# 4: 3 + Hex and ASCII dump of complete transmission after STARTTLS >+# Use loglevel 3 only in case of problems. Use of loglevel 4 is strongly >+# discouraged. >+# >+smtp_tls_loglevel = 0 >+ >+# The server and client negotiate a session, which takes some computer time >+# and network bandwidth. The session is cached only in the smtpd process >+# actually using this session and is lost when the process dies. >+# To share the session information between the smtp processes, a disc based >+# session cache can be used based on the SDBM databases (routines included >+# in Postfix/TLS). Since concurrent writing must be supported, only SDBM >+# can be used. >+# >+smtp_tls_session_cache_database = sdbm:/etc/postfix/smtp_scache >+ >+# The cached sessions time out after a certain amount of time. For Postfix/TLS >+# I do not use the OpenSSL default of 300sec, but a longer time of 3600sec >+# (=1 hour). RFC2246 recommends a maximum of 24 hours. >+# >+# smtp_tls_session_cache_timeout = 3600s >+ >+# By default TLS is disabled, so no difference to plain postfix is visible. >+# If you enable TLS it will be used when offered by the server. >+# WARNING: I didn't have access to other software (except those explicitely >+# listed) to test the interaction. On corresponding mailing list >+# there was a discussion going on about MS exchange servers offering >+# STARTTLS even if it is not configured, so it might be wise to not >+# use this option on your central mail hub, as you don't know in advance >+# whether you are going to hit such host. Use the recipient/site specific >+# options instead. >+# HINT: I have it switched on on my mailservers and did experience one >+# single failure since client side TLS is implemented. (There was one >+# misconfired MS Exchange server; I contacted ths admin.) Hence, I am happy >+# with it running all the time, but I am interested in testing anyway. >+# You have been warned, however :-) >+# >+# In case of failure, a "4xx" code is issued and the mail stays in the queue. >+# >+# Explicitely switch it on here, if you want it. >+# >+smtp_use_tls = yes >+ >+# You can ENFORCE the use of TLS, so that only connections with TLS will >+# be accepted. Additionally, the hostname of the receiving host is matched >+# against the CommonName in the certificate. Also, the certificate must >+# be verified "Ok", so that a CA trusted by the client must have issued >+# the certificate. If the certificate doesn't verify or the hostname doesn't >+# match, a "4xx" will be issued and the mail stays in the queue. >+# The hostname used in the check is beyond question, as it must be the >+# principle hostname (no CNAME allowed here). >+# The behaviour may be changed with the smtp_tls_enforce_peername option >+# >+# This option is useful only if you are definitely sure that you will only >+# connect to servers supporting RFC2487 _and_ with valid certificates. >+# I use it for my clients which will only send email to one mailhub, which >+# does offer the necessary STARTTLS support. >+# >+# smtp_enforce_tls = no >+ >+# As of RFC2487 the requirements for hostname checking for MTA clients are >+# not set. When in smtp_enforce_tls mode, the option smtp_tls_enforce_peername >+# can be set to "no" to disable strict peername checking. In this case, the >+# mail delivery will be continued, if a TLS connection was established >+# _and_ the peer certificate passed verification _but_ regardless of the >+# CommonName listed in the certificate. This option only applies to the >+# default setting smtp_enforce_tls_mode, special settings in the >+# smtp_tls_per_site table override smtp_tls_enforce_peername. >+# >+# This can make sense in closed environment where special CAs are created. >+# If not used carefully, this option opens the danger of a "man-in-the-middle" >+# attack (the CommonName of this attacker is logged). >+# >+# smtp_tls_enforce_peername = yes >+ >+# As generally trying TLS can be a bad idea (some hosts offer STARTTLS but >+# the negotiation will fail leading to unexplainable failures, it may be >+# a good idea to decide based on the recipient or the mailhub to which you are >+# connecting. >+# >+# Deciding per recipient may be difficult, since a singe email can have >+# several recipients. We use the "nexthop" mechanism inside postfix. >+# When an email is to be delivered, the "nexthop" is obtained. If it matches >+# an entry in the smtp_tls_per_site list, appropriate action is taken. >+# Since entries in the transport table or the use of a relay_host override >+# the nexthop setting, in these cases the relay_host etc must be listed >+# in the table. In any case, the hostname of the peer to be contacted is >+# looked up (that is: the MX or the name of the host, if no MX is given). >+# >+# Special hint for enforcement mode: >+# Since there is no secure mechanism for DNS lookups available, the >+# recommended setup is: put the sensible domains with their mailhost >+# into the transport table (since you can asure security of this table >+# unlike DNS), then set MUST mode for this mailhost. >+# >+# Format of the table: >+# The keys entries are on the left hand side, no wildcards allowed. On the >+# right hand side the keywords NONE (don't use TLS at all), MAY (try to use >+# STARTTLS if offered, no problem if not), MUST (enforce usage of STARTTLS, >+# check server certificate CommonName against server FQDN), MUST_NOPEERMATCH >+# (enforce usage of STARTTLS and verify certificate, but ignore differences >+# between CommonName and server FQDN). >+# dom.ain NONE >+# host.dom.ain MAY >+# important.host MUST >+# some.host.dom.ain MUST_NOPEERMATCH >+# >+# If an entry is not matched, the default policy is applied; if the default >+# policy is "enforce", NONE explicitely switches it off, otherwise the >+# "enforce" mode is used even for MAY entries. >+# >+smtp_tls_per_site = hash:/etc/postfix/tls_per_site >+ >+# The verification depth for server certificates. A depth of 1 is sufficient, >+# if the certificate ist directly issued by a CA listed in the CA locations. >+# The default value (5) should also suffice for longer chains (root CA issues >+# special CA which then issues the actual certificate...) >+# >+# smtp_tls_scert_verifydepth = 5 >+ >+# As we decide on a "per site" basis, wether to use TLS or not, it would be >+# good to have a list of sites, that offered "STARTTLS'. We can collect it >+# ourselves with this option. >+# >+# If activated and TLS is not already enabled for this host, a line is added >+# to the logfile: >+# postfix/smtp[pid]: Host offered STARTTLS: [name.of.host] >+# >+smtp_tls_note_starttls_offer = yes >+ >+# To influence the cipher selection scheme, you can give cipherlist-string. >+# A detailed description would go to far here, please refer to the openssl >+# documentation. >+# If you don't know what to do with it, simply don't touch it and leave the >+# (openssl-)compiled in default! >+# >+# DO NOT USE " to enclose the string, just the string!!! >+# >+# smtp_tls_cipherlist = DEFAULT >+ >+# The smtp_starttls_timeout parameter limits the time in seconds to write and >+# read operations during TLS start and stop handhake procedures. >+# >+# In case of problems the client does NOT try the next address on >+# the mail exchanger list. >+# >+# smtp_starttls_timeout = 300s >+ >+# In order to seed the PRNG Pseude Random Number Generator, random data is >+# needed. The PRNG pool is maintained by the "tlsmgr" daemon and is used >+# (read) by the smtp[d] processes after adding some more entropy by stirring >+# in time and process id. >+# The file, which is from time to time rewritten by the tlsmgr, is created >+# if not existant. A default value is given; the default should probably >+# be on the /var partition but _not_ inside chroot jail. >+# >+# tls_random_exchange_name = /etc/postfix/prng_exch >+ >+# To feed the PRNG pool, entropy is being read from an external source, >+# both at startup and during run. >+# Specify a good entropy source here, like EGD or /dev/urandom; make sure >+# to only use non-blocking sources. >+# In both cases, 32 bytes are read at each re-seeding event (which is an >+# amount of 256bits and hence good enough for 128bit symmetric keys). >+# You must specify the type of source: "dev:" for a device special file >+# or "egd:" for a source with EGD compatible socket interface. A maximum >+# 255 bytes is read from these sources in each step. >+# If you specify a normal file, a larger amount of data can be read. >+# >+# The entropy source is queried again after a certain amount of time. The >+# time is calculated using the PRNG, it is between 0 and the time specified, >+# default is a maximum of 1 hour. >+# >+# tls_random_source = dev:/dev/urandom >+tls_random_source = egd:/var/run/egd-pool >+# tls_random_bytes = 32 >+# tls_random_reseed_period = 3600s >+ >+# The PRNG pool inside tlsmgr is used to re-generate the 1024 byte file >+# being read by smtp[d]. The time, after which the exchange file is >+# rewritten is calculated using the PRNG, it is between 0 and the time >+# specified, default is a maximum of 60 seconds. >+# >+# tls_random_upd_period = 60s >+ >+# If you have a entropy source available, that is not easily drained (like >+# /dev/urandom), the daemons can also load additional entropy on startup from >+# the source specified. By default an amount of 32 bytes is read, the >+# equivalent to 256 bits. This is more than enough to generate a 128bit >+# (or 168bit) session key, but we may have to generate more than one. >+# Usage of this option may drain EGD (consider the case of 50 smtp starting >+# up with a full queue and "postfix start", which will request 1600bytes >+# of entropy). This is however not fatal, as long as "entropy" data could >+# be read from the exchange file. >+# >+# tls_daemon_random_source = dev:/dev/urandom >+tls_daemon_random_source = egd:/var/run/egd-pool >+# tls_daemon_random_bytes = 32 >+ >diff -Pur postfix-1.1.11.20020613-orig/makedefs postfix-1.1.11-20020613/makedefs >--- postfix-1.1.11.20020613-orig/makedefs Sat May 4 15:36:19 2002 >+++ postfix-1.1.11.20020613/makedefs Wed Jun 26 15:26:47 2002 >@@ -52,6 +52,21 @@ > SYSTEM=`(uname -s) 2>/dev/null` > RELEASE=`(uname -r) 2>/dev/null` > VERSION=`(uname -v) 2>/dev/null` >+if test -f /usr/include/netinet6/in6.h; then >+ grep __KAME__ /usr/include/netinet6/in6.h 2>&1 >/dev/null >+ if [ $? = 1 ]; then >+ INET6= >+ else >+ if [ -f /usr/local/v6/lib/libinet6.a ]; then >+ INET6=kame >+ else >+ INET6=kame-merged >+ fi >+ fi >+fi >+if [ -z "$INET6" -a -f /usr/include/netinet/ip6.h -a -f /usr/include/linux/icmpv6.h ]; then >+ INET6=linux >+fi > > case "$VERSION" in > dcosx*) SYSTEM=$VERSION;; >@@ -295,6 +310,26 @@ > esac > > : ${CC='gcc $(WARN)'} ${OPT='-O'} ${DEBUG='-g'} ${AWK=awk} >+ >+case "$INET6" in >+kame) >+ CCARGS="$CCARGS -DINET6 -D__ss_family=ss_family -D__ss_len=ss_len" >+ if test -f /usr/local/v6/lib/libinet6.a; then >+ SYSLIBS="$SYSLIBS -L/usr/local/v6/lib -linet6" >+ fi >+ ;; >+kame-merged) >+ CCARGS="$CCARGS -DINET6 -D__ss_family=ss_family -D__ss_len=ss_len" >+ ;; >+linux) >+ CCARGS="$CCARGS -DINET6 -D__ss_family=ss_family" >+ if test -f /usr/include/libinet6/netinet/ip6.h -a \ >+ -f /usr/lib/libinet6.a; then >+ CCARGS="$CCARGS -I/usr/include/libinet6 -DUSAGI_LIBINET6" >+ SYSLIBS="$SYSLIBS -linet6" >+ fi >+ ;; >+esac > > export SYSTYPE AR ARFL RANLIB SYSLIBS CC OPT DEBUG AWK OPTS > >diff -Pur postfix-1.1.11.20020613-orig/man/man8/tlsmgr.8 postfix-1.1.11-20020613/man/man8/tlsmgr.8 >--- postfix-1.1.11.20020613-orig/man/man8/tlsmgr.8 Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11.20020613/man/man8/tlsmgr.8 Wed Jun 26 15:26:47 2002 >@@ -0,0 +1,130 @@ >+.TH TLSMGR 8 >+.ad >+.fi >+.SH NAME >+tlsmgr >+\- >+Postfix TLS session cache and PRNG handling manager >+.SH SYNOPSIS >+.na >+.nf >+\fBtlsmgr\fR [generic Postfix daemon options] >+.SH DESCRIPTION >+.ad >+.fi >+The tlsmgr process does housekeeping on the session cache database >+files. It runs through the databases and removes expired entries >+and entries written by older (incompatible) versions. >+ >+The tlsmgr is responsible for the PRNG handling. The used internal >+OpenSSL PRNG has a pool size of 8192 bits (= 1024 bytes). The pool >+is initially seeded at startup from an external source (EGD or >+/dev/urandom) and additional seed is obtained later during program >+run at a configurable period. The exact time of seed query is >+using random information and is equally distributed in the range of >+[0-\fBtls_random_reseed_period\fR] with a \fBtls_random_reseed_period\fR >+having a default of 1 hour. >+ >+Tlsmgr can be run chrooted and with dropped privileges, as it will >+connect to the entropy source at startup. >+ >+The PRNG is additionally seeded internally by the data found in the >+session cache and timevalues. >+ >+Tlsmgr reads the old value of the exchange file at startup to keep >+entropy already collected during previous runs. >+ >+From the PRNG random pool a cryptographically strong 1024 byte random >+sequence is written into the PRNG exchange file. The file is updated >+periodically with the time changing randomly from >+[0-\fBtls_random_prng_update_period\fR]. >+.SH STANDARDS >+.na >+.nf >+.SH SECURITY >+.na >+.nf >+.ad >+.fi >+Tlsmgr is not security-sensitive. It only deals with external data >+to be fed into the PRNG, the contents is never trusted. The session >+cache housekeeping will only remove entries if expired and will never >+touch the contents of the cached data. >+.SH DIAGNOSTICS >+.ad >+.fi >+Problems and transactions are logged to the syslog daemon. >+.SH BUGS >+.ad >+.fi >+There is no automatic means to limit the number of entries in the >+session caches and/or the size of the session cache files. >+.SH CONFIGURATION PARAMETERS >+.na >+.nf >+.ad >+.fi >+The following \fBmain.cf\fR parameters are especially relevant to >+this program. See the Postfix \fBmain.cf\fR file for syntax details >+and for default values. Use the \fBpostfix reload\fR command after >+a configuration change. >+.SH Session Cache >+.ad >+.fi >+.IP \fBsmtpd_tls_session_cache_database\fR >+Name of the SDBM file (type sdbm:) containing the SMTP server session >+cache. If the file does not exist, it is created. >+.IP \fBsmtpd_tls_session_cache_timeout\fR >+Expiry time of SMTP server session cache entries in seconds. Entries >+older than this are removed from the session cache. A cleanup-run is >+performed periodically every \fBsmtpd_tls_session_cache_timeout\fR >+seconds. Default is 3600 (= 1 hour). >+.IP \fBsmtp_tls_session_cache_database\fR >+Name of the SDBM file (type sdbm:) containing the SMTP client session >+cache. If the file does not exist, it is created. >+.IP \fBsmtp_tls_session_cache_timeout\fR >+Expiry time of SMTP client session cache entries in seconds. Entries >+older than this are removed from the session cache. A cleanup-run is >+performed periodically every \fBsmtp_tls_session_cache_timeout\fR >+seconds. Default is 3600 (= 1 hour). >+.SH Pseudo Random Number Generator >+.ad >+.fi >+.IP \fBtls_random_source\fR >+Name of the EGD socket or device or regular file to obtain entropy >+from. The type of entropy source must be specified by preceding the >+name with the appropriate type: egd:/path/to/egd_socket, >+dev:/path/to/devicefile, or /path/to/regular/file. >+tlsmgr opens \fBtls_random_source\fR and tries to read >+\fBtls_random_bytes\fR from it. >+.IP \fBtls_random_bytes\fR >+Number of bytes to be read from \fBtls_random_source\fR. >+Default value is 32 bytes. If using EGD, a maximum of 255 bytes is read. >+.IP \fBtls_random_exchange_name\fR >+Name of the file written by tlsmgr and read by smtp and smtpd at >+startup. The length is 1024 bytes. Default value is >+/etc/postfix/prng_exch. >+.IP \fBtls_random_reseed_period\fR >+Time in seconds until the next reseed from external sources is due. >+This is the maximum value. The actual point in time is calculated >+with a random factor equally distributed between 0 and this maximum >+value. Default is 3600 (= 60 minutes). >+.IP \fBtls_random_prng_update_period\fR >+Time in seconds until the PRNG exchange file is updated with new >+pseude random values. This is the maximum value. The actual point >+in time is calculated with a random factor equally distributed >+between 0 and this maximum value. Default is 60 (= 1 minute). >+.SH SEE ALSO >+.na >+.nf >+smtp(8) SMTP client >+smtpd(8) SMTP server >+.SH LICENSE >+.na >+.nf >+.ad >+.fi >+The Secure Mailer license must be distributed with this software. >+.SH AUTHOR(S) >+.na >+.nf >diff -Pur postfix-1.1.11.20020613-orig/src/dns/dns_lookup.c postfix-1.1.11-20020613/src/dns/dns_lookup.c >--- postfix-1.1.11.20020613-orig/src/dns/dns_lookup.c Sun Feb 4 19:16:20 2001 >+++ postfix-1.1.11.20020613/src/dns/dns_lookup.c Wed Jun 26 15:26:47 2002 >@@ -132,6 +132,9 @@ > } DNS_REPLY; > > #define INET_ADDR_LEN 4 /* XXX */ >+#ifdef INET6 >+#define INET6_ADDR_LEN 16 >+#endif > > /* dns_query - query name server and pre-parse the reply */ > >@@ -337,6 +340,19 @@ > memcpy(temp, pos, fixed->length); > data_len = fixed->length; > break; >+#ifdef INET6 >+ case T_AAAA: >+ if (fixed->length != INET6_ADDR_LEN) { >+ msg_warn("extract_answer: bad IPv6 address length: %d", fixed->length); >+ return (0); >+ } >+ if (fixed->length > sizeof(temp)) >+ msg_panic("dns_get_rr: length %d > DNS_NAME_LEN", >+ fixed->length); >+ memcpy(temp, pos, fixed->length); >+ data_len = fixed->length; >+ break; >+#endif > case T_TXT: > data_len = MIN2(pos[0] + 1, MIN2(fixed->length + 1, sizeof(temp))); > for (src = pos + 1, dst = (unsigned char *) (temp); >diff -Pur postfix-1.1.11.20020613-orig/src/global/Makefile.in postfix-1.1.11-20020613/src/global/Makefile.in >--- postfix-1.1.11.20020613-orig/src/global/Makefile.in Tue Jun 11 03:13:13 2002 >+++ postfix-1.1.11.20020613/src/global/Makefile.in Wed Jun 26 15:26:47 2002 >@@ -20,7 +20,7 @@ > tok822_resolve.c tok822_rewrite.c tok822_tree.c xtext.c bounce_log.c \ > flush_clnt.c mail_conf_time.c mbox_conf.c mbox_open.c abounce.c \ > verp_sender.c match_parent_style.c mime_state.c header_token.c \ >- strip_addr.c >+ strip_addr.c pfixtls.c wildcard_inet_addr.c > OBJS = been_here.o bounce.o canon_addr.o cleanup_strerror.o clnt_stream.o \ > debug_peer.o debug_process.o defer.o deliver_completed.o \ > deliver_flock.o deliver_pass.o deliver_request.o domain_list.o \ >@@ -42,7 +42,7 @@ > tok822_resolve.o tok822_rewrite.o tok822_tree.o xtext.o bounce_log.o \ > flush_clnt.o mail_conf_time.o mbox_conf.o mbox_open.o abounce.o \ > verp_sender.o match_parent_style.o mime_state.o header_token.o \ >- strip_addr.o >+ strip_addr.o pfixtls.o wildcard_inet_addr.o > HDRS = been_here.h bounce.h canon_addr.h cleanup_user.h clnt_stream.h \ > config.h debug_peer.h debug_process.h defer.h deliver_completed.h \ > deliver_flock.h deliver_pass.h deliver_request.h domain_list.h \ >@@ -60,7 +60,7 @@ > sys_exits.h timed_ipc.h tok822.h xtext.h bounce_log.h flush_clnt.h \ > mbox_conf.h mbox_open.h abounce.h qmqp_proto.h verp_sender.h \ > match_parent_style.h quote_flags.h mime_state.h header_token.h \ >- lex_822.h strip_addr.h >+ lex_822.h strip_addr.h pfixtls.h wildcard_inet_addr.h > TESTSRC = rec2stream.c stream2rec.c recdump.c > WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ > -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ >@@ -1160,3 +1160,16 @@ > xtext.o: ../../include/vbuf.h > xtext.o: ../../include/vstring.h > xtext.o: xtext.h >+pfixtls.o: pfixtls.c >+pfixtls.o: ../../include/sys_defs.h >+pfixtls.o: ../../include/iostuff.h >+pfixtls.o: ../../include/mymalloc.h >+pfixtls.o: ../../include/vstring.h >+pfixtls.o: ../../include/vstream.h >+pfixtls.o: ../../include/dict.h >+pfixtls.o: ../../include/myflock.h >+pfixtls.o: ../../include/stringops.h >+pfixtls.o: ../../include/msg.h >+pfixtls.o: ../../include/connect.h >+pfixtls.o: mail_params.h >+pfixtls.o: pfixtls.h >diff -Pur postfix-1.1.11.20020613-orig/src/global/mail_params.c postfix-1.1.11-20020613/src/global/mail_params.c >--- postfix-1.1.11.20020613-orig/src/global/mail_params.c Sat Jun 8 20:21:40 2002 >+++ postfix-1.1.11.20020613/src/global/mail_params.c Wed Jun 26 15:26:47 2002 >@@ -223,6 +223,31 @@ > int var_in_flow_delay; > char *var_par_dom_match; > char *var_config_dirs; >+char *var_tls_rand_exch_name; >+char *var_smtpd_tls_cert_file; >+char *var_smtpd_tls_key_file; >+char *var_smtpd_tls_dcert_file; >+char *var_smtpd_tls_dkey_file; >+char *var_smtpd_tls_CAfile; >+char *var_smtpd_tls_CApath; >+char *var_smtpd_tls_cipherlist; >+char *var_smtpd_tls_dh512_param_file; >+char *var_smtpd_tls_dh1024_param_file; >+int var_smtpd_tls_loglevel; >+char *var_smtpd_tls_scache_db; >+int var_smtpd_tls_scache_timeout; >+char *var_smtp_tls_cert_file; >+char *var_smtp_tls_key_file; >+char *var_smtp_tls_dcert_file; >+char *var_smtp_tls_dkey_file; >+char *var_smtp_tls_CAfile; >+char *var_smtp_tls_CApath; >+char *var_smtp_tls_cipherlist; >+int var_smtp_tls_loglevel; >+char *var_smtp_tls_scache_db; >+int var_smtp_tls_scache_timeout; >+char *var_tls_daemon_rand_source; >+int var_tls_daemon_rand_bytes; > > char *var_import_environ; > char *var_export_environ; >@@ -467,6 +492,26 @@ > VAR_SHOWQ_SERVICE, DEF_SHOWQ_SERVICE, &var_showq_service, 1, 0, > VAR_ERROR_SERVICE, DEF_ERROR_SERVICE, &var_error_service, 1, 0, > VAR_FLUSH_SERVICE, DEF_FLUSH_SERVICE, &var_flush_service, 1, 0, >+ VAR_TLS_RAND_EXCH_NAME, DEF_TLS_RAND_EXCH_NAME, &var_tls_rand_exch_name, 0, 0, >+ VAR_SMTPD_TLS_CERT_FILE, DEF_SMTPD_TLS_CERT_FILE, &var_smtpd_tls_cert_file, 0, 0, >+ VAR_SMTPD_TLS_KEY_FILE, DEF_SMTPD_TLS_KEY_FILE, &var_smtpd_tls_key_file, 0, 0, >+ VAR_SMTPD_TLS_DCERT_FILE, DEF_SMTPD_TLS_DCERT_FILE, &var_smtpd_tls_dcert_file, 0, 0, >+ VAR_SMTPD_TLS_DKEY_FILE, DEF_SMTPD_TLS_DKEY_FILE, &var_smtpd_tls_dkey_file, 0, 0, >+ VAR_SMTPD_TLS_CA_FILE, DEF_SMTPD_TLS_CA_FILE, &var_smtpd_tls_CAfile, 0, 0, >+ VAR_SMTPD_TLS_CA_PATH, DEF_SMTPD_TLS_CA_PATH, &var_smtpd_tls_CApath, 0, 0, >+ VAR_SMTPD_TLS_CLIST, DEF_SMTPD_TLS_CLIST, &var_smtpd_tls_cipherlist, 0, 0, >+ VAR_SMTPD_TLS_512_FILE, DEF_SMTPD_TLS_512_FILE, &var_smtpd_tls_dh512_param_file, 0, 0, >+ VAR_SMTPD_TLS_1024_FILE, DEF_SMTPD_TLS_1024_FILE, &var_smtpd_tls_dh1024_param_file, 0, 0, >+ VAR_SMTPD_TLS_SCACHE_DB, DEF_SMTPD_TLS_SCACHE_DB, &var_smtpd_tls_scache_db, 0, 0, >+ VAR_SMTP_TLS_CERT_FILE, DEF_SMTP_TLS_CERT_FILE, &var_smtp_tls_cert_file, 0, 0, >+ VAR_SMTP_TLS_KEY_FILE, DEF_SMTP_TLS_KEY_FILE, &var_smtp_tls_key_file, 0, 0, >+ VAR_SMTP_TLS_DCERT_FILE, DEF_SMTP_TLS_DCERT_FILE, &var_smtp_tls_dcert_file, 0, 0, >+ VAR_SMTP_TLS_DKEY_FILE, DEF_SMTP_TLS_DKEY_FILE, &var_smtp_tls_dkey_file, 0, 0, >+ VAR_SMTP_TLS_CA_FILE, DEF_SMTP_TLS_CA_FILE, &var_smtp_tls_CAfile, 0, 0, >+ VAR_SMTP_TLS_CA_PATH, DEF_SMTP_TLS_CA_PATH, &var_smtp_tls_CApath, 0, 0, >+ VAR_SMTP_TLS_CLIST, DEF_SMTP_TLS_CLIST, &var_smtp_tls_cipherlist, 0, 0, >+ VAR_SMTP_TLS_SCACHE_DB, DEF_SMTP_TLS_SCACHE_DB, &var_smtp_tls_scache_db, 0, 0, >+ VAR_TLS_DAEMON_RAND_SOURCE, DEF_TLS_DAEMON_RAND_SOURCE, &var_tls_daemon_rand_source, 0, 0, > 0, > }; > static CONFIG_STR_FN_TABLE function_str_defaults_2[] = { >@@ -489,6 +534,9 @@ > VAR_TOKEN_LIMIT, DEF_TOKEN_LIMIT, &var_token_limit, 1, 0, > VAR_MIME_MAXDEPTH, DEF_MIME_MAXDEPTH, &var_mime_maxdepth, 1, 0, > VAR_MIME_BOUND_LEN, DEF_MIME_BOUND_LEN, &var_mime_bound_len, 1, 0, >+ VAR_SMTPD_TLS_LOGLEVEL, DEF_SMTPD_TLS_LOGLEVEL, &var_smtpd_tls_loglevel, 0, 0, >+ VAR_SMTP_TLS_LOGLEVEL, DEF_SMTP_TLS_LOGLEVEL, &var_smtp_tls_loglevel, 0, 0, >+ VAR_TLS_DAEMON_RAND_BYTES, DEF_TLS_DAEMON_RAND_BYTES, &var_tls_daemon_rand_bytes, 0, 0, > 0, > }; > static CONFIG_TIME_TABLE time_defaults[] = { >@@ -499,6 +547,8 @@ > VAR_FORK_DELAY, DEF_FORK_DELAY, &var_fork_delay, 1, 0, > VAR_FLOCK_DELAY, DEF_FLOCK_DELAY, &var_flock_delay, 1, 0, > VAR_FLOCK_STALE, DEF_FLOCK_STALE, &var_flock_stale, 1, 0, >+ VAR_SMTPD_TLS_SCACHTIME, DEF_SMTPD_TLS_SCACHTIME, &var_smtpd_tls_scache_timeout, 0, 0, >+ VAR_SMTP_TLS_SCACHTIME, DEF_SMTP_TLS_SCACHTIME, &var_smtp_tls_scache_timeout, 0, 0, > VAR_DAEMON_TIMEOUT, DEF_DAEMON_TIMEOUT, &var_daemon_timeout, 1, 0, > VAR_IN_FLOW_DELAY, DEF_IN_FLOW_DELAY, &var_in_flow_delay, 0, 10, > 0, >diff -Pur postfix-1.1.11.20020613-orig/src/global/mail_params.h postfix-1.1.11-20020613/src/global/mail_params.h >--- postfix-1.1.11.20020613-orig/src/global/mail_params.h Mon Jun 10 19:49:56 2002 >+++ postfix-1.1.11.20020613/src/global/mail_params.h Wed Jun 26 15:26:47 2002 >@@ -458,6 +458,34 @@ > #define DEF_DUP_FILTER_LIMIT 1000 > extern int var_dup_filter_limit; > >+#define VAR_TLS_RAND_EXCH_NAME "tls_random_exchange_name" >+#define DEF_TLS_RAND_EXCH_NAME "${config_directory}/prng_exch" >+extern char *var_tls_rand_exch_name; >+ >+#define VAR_TLS_RAND_SOURCE "tls_random_source" >+#define DEF_TLS_RAND_SOURCE "" >+extern char *var_tls_rand_source; >+ >+#define VAR_TLS_RAND_BYTES "tls_random_bytes" >+#define DEF_TLS_RAND_BYTES 32 >+extern int var_tls_rand_bytes; >+ >+#define VAR_TLS_DAEMON_RAND_SOURCE "tls_daemon_random_source" >+#define DEF_TLS_DAEMON_RAND_SOURCE "" >+extern char *var_tls_daemon_rand_source; >+ >+#define VAR_TLS_DAEMON_RAND_BYTES "tls_daemon_random_bytes" >+#define DEF_TLS_DAEMON_RAND_BYTES 32 >+extern int var_tls_daemon_rand_bytes; >+ >+#define VAR_TLS_RESEED_PERIOD "tls_random_reseed_period" >+#define DEF_TLS_RESEED_PERIOD "3600s" >+extern int var_tls_reseed_period; >+ >+#define VAR_TLS_PRNG_UPD_PERIOD "tls_random_prng_update_period" >+#define DEF_TLS_PRNG_UPD_PERIOD "60s" >+extern int var_tls_prng_upd_period; >+ > /* > * Queue manager: relocated databases. > */ >@@ -678,6 +706,10 @@ > #define DEF_SMTP_HELO_TMOUT "300s" > extern int var_smtp_helo_tmout; > >+#define VAR_SMTP_STARTTLS_TMOUT "smtp_starttls_timeout" >+#define DEF_SMTP_STARTTLS_TMOUT "300s" >+extern int var_smtp_starttls_tmout; >+ > #define VAR_SMTP_MAIL_TMOUT "smtp_mail_timeout" > #define DEF_SMTP_MAIL_TMOUT "300s" > extern int var_smtp_mail_tmout; >@@ -734,6 +766,12 @@ > #define DEF_SMTP_BIND_ADDR "" > extern char *var_smtp_bind_addr; > >+#ifdef INET6 >+#define VAR_SMTP_BIND_ADDR6 "smtp_bind_address6" >+#define DEF_SMTP_BIND_ADDR6 "" >+extern char *var_smtp_bind_addr6; >+#endif >+ > #define VAR_SMTP_HELO_NAME "smtp_helo_name" > #define DEF_SMTP_HELO_NAME "$myhostname" > extern char *var_smtp_helo_name; >@@ -767,6 +805,10 @@ > #define DEF_SMTPD_TMOUT "300s" > extern int var_smtpd_tmout; > >+#define VAR_SMTPD_STARTTLS_TMOUT "smtpd_starttls_timeout" >+#define DEF_SMTPD_STARTTLS_TMOUT "300s" >+extern int var_smtpd_starttls_tmout; >+ > #define VAR_SMTPD_RCPT_LIMIT "smtpd_recipient_limit" > #define DEF_SMTPD_RCPT_LIMIT 1000 > extern int var_smtpd_rcpt_limit; >@@ -795,6 +837,150 @@ > #define DEF_SMTPD_NOOP_CMDS "" > extern char *var_smtpd_noop_cmds; > >+#define VAR_SMTPD_TLS_WRAPPER "smtpd_tls_wrappermode" >+#define DEF_SMTPD_TLS_WRAPPER 0 >+extern bool var_smtpd_tls_wrappermode; >+ >+#define VAR_SMTPD_USE_TLS "smtpd_use_tls" >+#define DEF_SMTPD_USE_TLS 0 >+extern bool var_smtpd_use_tls; >+ >+#define VAR_SMTPD_ENFORCE_TLS "smtpd_enforce_tls" >+#define DEF_SMTPD_ENFORCE_TLS 0 >+extern bool var_smtpd_enforce_tls; >+ >+#define VAR_SMTPD_TLS_AUTH_ONLY "smtpd_tls_auth_only" >+#define DEF_SMTPD_TLS_AUTH_ONLY 0 >+extern bool var_smtpd_tls_auth_only; >+ >+#define VAR_SMTPD_TLS_ACERT "smtpd_tls_ask_ccert" >+#define DEF_SMTPD_TLS_ACERT 0 >+extern bool var_smtpd_tls_ask_ccert; >+ >+#define VAR_SMTPD_TLS_RCERT "smtpd_tls_req_ccert" >+#define DEF_SMTPD_TLS_RCERT 0 >+extern bool var_smtpd_tls_req_ccert; >+ >+#define VAR_SMTPD_TLS_CCERT_VD "smtpd_tls_ccert_verifydepth" >+#define DEF_SMTPD_TLS_CCERT_VD 5 >+extern int var_smtpd_tls_ccert_vd; >+ >+#define VAR_SMTPD_TLS_CERT_FILE "smtpd_tls_cert_file" >+#define DEF_SMTPD_TLS_CERT_FILE "" >+extern char *var_smtpd_tls_cert_file; >+ >+#define VAR_SMTPD_TLS_KEY_FILE "smtpd_tls_key_file" >+#define DEF_SMTPD_TLS_KEY_FILE "$smtpd_tls_cert_file" >+extern char *var_smtpd_tls_key_file; >+ >+#define VAR_SMTPD_TLS_DCERT_FILE "smtpd_tls_dcert_file" >+#define DEF_SMTPD_TLS_DCERT_FILE "" >+extern char *var_smtpd_tls_dcert_file; >+ >+#define VAR_SMTPD_TLS_DKEY_FILE "smtpd_tls_dkey_file" >+#define DEF_SMTPD_TLS_DKEY_FILE "$smtpd_tls_dcert_file" >+extern char *var_smtpd_tls_dkey_file; >+ >+#define VAR_SMTPD_TLS_CA_FILE "smtpd_tls_CAfile" >+#define DEF_SMTPD_TLS_CA_FILE "" >+extern char *var_smtpd_tls_CAfile; >+ >+#define VAR_SMTPD_TLS_CA_PATH "smtpd_tls_CApath" >+#define DEF_SMTPD_TLS_CA_PATH "" >+extern char *var_smtpd_tls_CApath; >+ >+#define VAR_SMTPD_TLS_CLIST "smtpd_tls_cipherlist" >+#define DEF_SMTPD_TLS_CLIST "" >+extern char *var_smtpd_tls_cipherlist; >+ >+#define VAR_SMTPD_TLS_512_FILE "smtpd_tls_dh512_param_file" >+#define DEF_SMTPD_TLS_512_FILE "" >+extern char *var_smtpd_tls_dh512_param_file; >+ >+#define VAR_SMTPD_TLS_1024_FILE "smtpd_tls_dh1024_param_file" >+#define DEF_SMTPD_TLS_1024_FILE "" >+extern char *var_smtpd_tls_dh1024_param_file; >+ >+#define VAR_SMTPD_TLS_LOGLEVEL "smtpd_tls_loglevel" >+#define DEF_SMTPD_TLS_LOGLEVEL 0 >+extern int var_smtpd_tls_loglevel; >+ >+#define VAR_SMTPD_TLS_RECHEAD "smtpd_tls_received_header" >+#define DEF_SMTPD_TLS_RECHEAD 0 >+extern bool var_smtpd_tls_received_header; >+ >+#define VAR_SMTPD_TLS_SCACHE_DB "smtpd_tls_session_cache_database" >+#define DEF_SMTPD_TLS_SCACHE_DB "" >+extern char *var_smtpd_tls_scache_db; >+ >+#define VAR_SMTPD_TLS_SCACHTIME "smtpd_tls_session_cache_timeout" >+#define DEF_SMTPD_TLS_SCACHTIME "3600s" >+extern int var_smtpd_tls_scache_timeout; >+ >+#define VAR_SMTP_TLS_PER_SITE "smtp_tls_per_site" >+#define DEF_SMTP_TLS_PER_SITE "" >+extern char *var_smtp_tls_per_site; >+ >+#define VAR_SMTP_USE_TLS "smtp_use_tls" >+#define DEF_SMTP_USE_TLS 0 >+extern bool var_smtp_use_tls; >+ >+#define VAR_SMTP_ENFORCE_TLS "smtp_enforce_tls" >+#define DEF_SMTP_ENFORCE_TLS 0 >+extern bool var_smtp_enforce_tls; >+ >+#define VAR_SMTP_TLS_ENFORCE_PN "smtp_tls_enforce_peername" >+#define DEF_SMTP_TLS_ENFORCE_PN 1 >+extern bool var_smtp_tls_enforce_peername; >+ >+#define VAR_SMTP_TLS_SCERT_VD "smtp_tls_scert_verifydepth" >+#define DEF_SMTP_TLS_SCERT_VD 5 >+extern int var_smtp_tls_scert_vd; >+ >+#define VAR_SMTP_TLS_CERT_FILE "smtp_tls_cert_file" >+#define DEF_SMTP_TLS_CERT_FILE "" >+extern char *var_smtp_tls_cert_file; >+ >+#define VAR_SMTP_TLS_KEY_FILE "smtp_tls_key_file" >+#define DEF_SMTP_TLS_KEY_FILE "$smtp_tls_cert_file" >+extern char *var_smtp_tls_key_file; >+ >+#define VAR_SMTP_TLS_DCERT_FILE "smtp_tls_dcert_file" >+#define DEF_SMTP_TLS_DCERT_FILE "" >+extern char *var_smtp_tls_dcert_file; >+ >+#define VAR_SMTP_TLS_DKEY_FILE "smtp_tls_dkey_file" >+#define DEF_SMTP_TLS_DKEY_FILE "$smtp_tls_dcert_file" >+extern char *var_smtp_tls_dkey_file; >+ >+#define VAR_SMTP_TLS_CA_FILE "smtp_tls_CAfile" >+#define DEF_SMTP_TLS_CA_FILE "" >+extern char *var_smtp_tls_CAfile; >+ >+#define VAR_SMTP_TLS_CA_PATH "smtp_tls_CApath" >+#define DEF_SMTP_TLS_CA_PATH "" >+extern char *var_smtp_tls_CApath; >+ >+#define VAR_SMTP_TLS_CLIST "smtp_tls_cipherlist" >+#define DEF_SMTP_TLS_CLIST "" >+extern char *var_smtp_tls_cipherlist; >+ >+#define VAR_SMTP_TLS_LOGLEVEL "smtp_tls_loglevel" >+#define DEF_SMTP_TLS_LOGLEVEL 0 >+extern int var_smtp_tls_loglevel; >+ >+#define VAR_SMTP_TLS_NOTEOFFER "smtp_tls_note_starttls_offer" >+#define DEF_SMTP_TLS_NOTEOFFER 0 >+extern bool var_smtp_tls_note_starttls_offer; >+ >+#define VAR_SMTP_TLS_SCACHE_DB "smtp_tls_session_cache_database" >+#define DEF_SMTP_TLS_SCACHE_DB "" >+extern char *var_smtp_tls_scache_db; >+ >+#define VAR_SMTP_TLS_SCACHTIME "smtp_tls_session_cache_timeout" >+#define DEF_SMTP_TLS_SCACHTIME "3600s" >+extern int var_smtp_tls_scache_timeout; >+ > /* > * SASL authentication support, SMTP server side. > */ >@@ -953,6 +1139,16 @@ > #define DEF_LMTP_QUIT_TMOUT "300s" > extern int var_lmtp_quit_tmout; > >+#define VAR_LMTP_BIND_ADDR "lmtp_bind_address" >+#define DEF_LMTP_BIND_ADDR "" >+extern char *var_lmtp_bind_addr; >+ >+#ifdef INET6 >+#define VAR_LMTP_BIND_ADDR6 "lmtp_bind_address6" >+#define DEF_LMTP_BIND_ADDR6 "" >+extern char *var_lmtp_bind_addr6; >+#endif >+ > /* > * Cleanup service. Header info that exceeds $header_size_limit bytes forces > * the start of the message body. >@@ -1088,6 +1284,10 @@ > #define DEF_RELAY_DOMAINS "$mydestination" > extern char *var_relay_domains; > >+#define VAR_RELAY_CCERTS "relay_clientcerts" >+#define DEF_RELAY_CCERTS "" >+extern char *var_relay_ccerts; >+ > #define VAR_CLIENT_CHECKS "smtpd_client_restrictions" > #define DEF_CLIENT_CHECKS "" > extern char *var_client_checks; >@@ -1167,6 +1367,8 @@ > #define PERMIT_AUTH_DEST "permit_auth_destination" > #define REJECT_UNAUTH_DEST "reject_unauth_destination" > #define CHECK_RELAY_DOMAINS "check_relay_domains" >+#define PERMIT_TLS_CLIENTCERTS "permit_tls_clientcerts" >+#define PERMIT_TLS_ALL_CLIENTCERTS "permit_tls_all_clientcerts" > #define VAR_RELAY_CODE "relay_domains_reject_code" > #define DEF_RELAY_CODE 554 > extern int var_relay_code; >diff -Pur postfix-1.1.11.20020613-orig/src/global/mail_proto.h postfix-1.1.11-20020613/src/global/mail_proto.h >--- postfix-1.1.11.20020613-orig/src/global/mail_proto.h Sun May 12 16:46:59 2002 >+++ postfix-1.1.11.20020613/src/global/mail_proto.h Wed Jun 26 15:26:47 2002 >@@ -34,6 +34,7 @@ > #define MAIL_SERVICE_LOCAL "local" > #define MAIL_SERVICE_PICKUP "pickup" > #define MAIL_SERVICE_QUEUE "qmgr" >+#define MAIL_SERVICE_TLSMGR "tlsmgr" > #define MAIL_SERVICE_RESOLVE "resolve" > #define MAIL_SERVICE_REWRITE "rewrite" > #define MAIL_SERVICE_VIRTUAL "virtual" >diff -Pur postfix-1.1.11.20020613-orig/src/global/mynetworks.c postfix-1.1.11-20020613/src/global/mynetworks.c >--- postfix-1.1.11.20020613-orig/src/global/mynetworks.c Sun Feb 25 02:46:07 2001 >+++ postfix-1.1.11.20020613/src/global/mynetworks.c Wed Jun 26 15:26:47 2002 >@@ -50,6 +50,11 @@ > #include <vstring.h> > #include <inet_addr_list.h> > #include <name_mask.h> >+#ifdef INET6 >+#include <sys/socket.h> >+#include <netinet/in.h> >+#include <netdb.h> >+#endif > > /* Global library. */ > >@@ -75,6 +80,9 @@ > const char *mynetworks(void) > { > static VSTRING *result; >+#ifdef INET6 >+ char hbuf[NI_MAXHOST]; >+#endif > > if (result == 0) { > char *myname = "mynetworks"; >@@ -87,6 +95,9 @@ > int junk; > int i; > int mask_style; >+#ifdef INET6 >+ struct sockaddr *sa; >+#endif > > mask_style = name_mask("mynetworks mask style", mask_styles, > var_mynetworks_style); >@@ -96,8 +107,19 @@ > my_mask_list = own_inet_mask_list(); > > for (i = 0; i < my_addr_list->used; i++) { >+#ifdef INET6 >+ sa = (struct sockaddr *)&my_addr_list->addrs[i]; >+ if (sa->sa_family != AF_INET) { >+ if (sa->sa_family == AF_INET6) >+ vstring_sprintf_append(result, "XAATODOmynetworks "); >+ continue; >+ } >+ addr = ntohl(((struct sockaddr_in *)sa)->sin_addr.s_addr); >+ mask = ntohl(((struct sockaddr_in *)&my_mask_list->addrs[i])->sin_addr.s_addr); >+#else > addr = ntohl(my_addr_list->addrs[i].s_addr); > mask = ntohl(my_mask_list->addrs[i].s_addr); >+#endif > > switch (mask_style) { > >@@ -119,8 +141,15 @@ > mask = IN_CLASSD_NET; > shift = IN_CLASSD_NSHIFT; > } else { >+#ifdef INET6 >+ if (getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), NULL, 0, >+ NI_NUMERICHOST)) >+ strncpy(hbuf, "???", sizeof(hbuf)); >+ msg_fatal("%s: bad address class: %s", myname, hbuf); >+#else > msg_fatal("%s: bad address class: %s", > myname, inet_ntoa(my_addr_list->addrs[i])); >+#endif > } > break; > >diff -Pur postfix-1.1.11.20020613-orig/src/global/own_inet_addr.c postfix-1.1.11-20020613/src/global/own_inet_addr.c >--- postfix-1.1.11.20020613-orig/src/global/own_inet_addr.c Tue Jul 31 20:38:29 2001 >+++ postfix-1.1.11.20020613/src/global/own_inet_addr.c Wed Jun 26 15:26:47 2002 >@@ -39,6 +39,10 @@ > #include <netinet/in.h> > #include <arpa/inet.h> > #include <string.h> >+#ifdef INET6 >+#include <sys/socket.h> >+#include <netdb.h> >+#endif > > #ifdef STRCASECMP_IN_STRINGS_H > #include <strings.h> >@@ -101,10 +105,11 @@ > */ > else { > bufp = hosts = mystrdup(var_inet_interfaces); >- while ((host = mystrtok(&bufp, sep)) != 0) >+ while ((host = mystrtok(&bufp, sep)) != 0) { > if (inet_addr_host(addr_list, host) == 0) > msg_fatal("config variable %s: host not found: %s", > VAR_INET_INTERFACES, host); >+ } > myfree(hosts); > > /* >@@ -121,15 +126,39 @@ > msg_fatal("could not find any active network interfaces"); > for (nvirtual = 0; nvirtual < addr_list->used; nvirtual++) { > for (nlocal = 0; /* see below */ ; nlocal++) { >- if (nlocal >= local_addrs.used) >+ if (nlocal >= local_addrs.used) { >+#ifdef INET6 >+ char hbuf[NI_MAXHOST]; >+ if (getnameinfo((struct sockaddr *)&addr_list->addrs[nvirtual], >+ SS_LEN(addr_list->addrs[nvirtual]), hbuf, >+ sizeof(hbuf), NULL, 0, NI_NUMERICHOST) != 0) >+ strncpy(hbuf, "???", sizeof(hbuf)); >+ msg_fatal("parameter %s: no local interface found for %s", >+ VAR_INET_INTERFACES, hbuf); >+#else > msg_fatal("parameter %s: no local interface found for %s", > VAR_INET_INTERFACES, > inet_ntoa(addr_list->addrs[nvirtual])); >+#endif >+ } >+#ifdef INET6 >+ if (addr_list->addrs[nvirtual].ss_family == >+ local_addrs.addrs[nlocal].ss_family && >+ SS_LEN(addr_list->addrs[nvirtual]) == >+ SS_LEN(local_addrs.addrs[nlocal]) && >+ memcmp(&addr_list->addrs[nvirtual], >+ &local_addrs.addrs[nlocal], >+ SS_LEN(local_addrs.addrs[nlocal])) == 0) { >+ inet_addr_list_append(mask_list, (struct sockaddr *)&local_masks.addrs[nlocal]); >+ break; >+ } >+#else > if (addr_list->addrs[nvirtual].s_addr > == local_addrs.addrs[nlocal].s_addr) { > inet_addr_list_append(mask_list, &local_masks.addrs[nlocal]); > break; > } >+#endif > } > } > inet_addr_list_free(&local_addrs); >@@ -139,6 +168,42 @@ > > /* own_inet_addr - is this my own internet address */ > >+#ifdef INET6 >+int own_inet_addr(struct sockaddr * addr) >+{ >+ int i; >+ char *p, *q; >+ int l; >+ struct sockaddr *sa; >+ >+ if (addr_list.used == 0) >+ own_inet_addr_init(&addr_list, &mask_list); >+ >+ for (i = 0; i < addr_list.used; i++) { >+ sa = (struct sockaddr *)&addr_list.addrs[i]; >+ if (addr->sa_family != sa->sa_family) >+ continue; >+ switch (addr->sa_family) { >+ case AF_INET: >+ p = (char *)&((struct sockaddr_in *)addr)->sin_addr; >+ q = (char *)&((struct sockaddr_in *)&addr_list.addrs[i])->sin_addr; >+ l = sizeof(struct in_addr); >+ break; >+ case AF_INET6: >+ /* XXX scope */ >+ p = (char *)&((struct sockaddr_in6 *)addr)->sin6_addr; >+ q = (char *)&((struct sockaddr_in6 *)&addr_list.addrs[i])->sin6_addr; >+ l = sizeof(struct in6_addr); >+ break; >+ default: >+ continue; >+ } >+ if (memcmp(p, q, l) == 0) >+ return (1); >+ } >+ return (0); >+} >+#else > int own_inet_addr(struct in_addr * addr) > { > int i; >@@ -149,8 +214,8 @@ > for (i = 0; i < addr_list.used; i++) > if (addr->s_addr == addr_list.addrs[i].s_addr) > return (1); >- return (0); > } >+#endif > > /* own_inet_addr_list - return list of addresses */ > >diff -Pur postfix-1.1.11.20020613-orig/src/global/own_inet_addr.h postfix-1.1.11-20020613/src/global/own_inet_addr.h >--- postfix-1.1.11.20020613-orig/src/global/own_inet_addr.h Sat Feb 24 02:25:32 2001 >+++ postfix-1.1.11.20020613/src/global/own_inet_addr.h Wed Jun 26 15:26:48 2002 >@@ -15,11 +15,18 @@ > * System library. > */ > #include <netinet/in.h> >+#ifdef INET6 >+#include <sys/socket.h> >+#endif > > /* > * External interface. > */ >+#ifdef INET6 >+extern int own_inet_addr(struct sockaddr *); >+#else > extern int own_inet_addr(struct in_addr *); >+#endif > extern struct INET_ADDR_LIST *own_inet_addr_list(void); > extern struct INET_ADDR_LIST *own_inet_mask_list(void); > >diff -Pur postfix-1.1.11.20020613-orig/src/global/peer_name.c postfix-1.1.11-20020613/src/global/peer_name.c >--- postfix-1.1.11.20020613-orig/src/global/peer_name.c Sun Jan 28 16:23:02 2001 >+++ postfix-1.1.11.20020613/src/global/peer_name.c Wed Jun 26 15:26:48 2002 >@@ -69,12 +69,32 @@ > PEER_NAME *peer_name(int sock) > { > static PEER_NAME peer; >- struct sockaddr_in sin; >- SOCKADDR_SIZE len = sizeof(sin); >+ union sockunion { >+ struct { >+ u_char si_len; >+ u_char si_family; >+ u_short si_port; >+ } su_si; >+ struct sockaddr peer_un; >+ struct sockaddr_in peer_un4; >+#ifdef INET6 >+ struct sockaddr_in6 peer_un6; >+#endif >+ } p_un; >+#define sun p_un.peer_un >+#define sin p_un.peer_un4 >+#ifdef INET6 >+#define sin6 p_un.peer_un6 >+ static char hbuf[NI_MAXHOST]; >+ static char abuf[NI_MAXHOST]; >+#else > struct hostent *hp; >+#endif >+ SOCKADDR_SIZE len = sizeof(p_un); > >- if (getpeername(sock, (struct sockaddr *) & sin, &len) == 0) { >- switch (sin.sin_family) { >+ if (getpeername(sock, (struct sockaddr *)&p_un, &len) == 0) { >+ switch (p_un.peer_un.sa_family) { >+#ifndef INET6 > case AF_INET: > peer.type = PEER_TYPE_INET; > hp = gethostbyaddr((char *) &(sin.sin_addr), >@@ -83,6 +103,24 @@ > hp->h_name : "unknown"); > peer.addr = inet_ntoa(sin.sin_addr); > return (&peer); >+#else >+ case AF_INET: >+ peer.type = PEER_TYPE_INET; >+ if (getnameinfo(&sun, len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) != 0) >+ peer.name = "unknown"; >+ else >+ peer.name = hbuf; >+ peer.addr = abuf; >+ return (&peer); >+ case AF_INET6: >+ peer.type = PEER_TYPE_INET6; >+ if (getnameinfo(&sun, len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD) != 0) >+ peer.name = "unknown"; >+ else >+ peer.name = hbuf; >+ peer.addr = abuf; >+ return (&peer); >+#endif > case AF_UNSPEC: > case AF_UNIX: > peer.type = PEER_TYPE_LOCAL; >diff -Pur postfix-1.1.11.20020613-orig/src/global/peer_name.h postfix-1.1.11-20020613/src/global/peer_name.h >--- postfix-1.1.11.20020613-orig/src/global/peer_name.h Fri Dec 11 19:55:32 1998 >+++ postfix-1.1.11.20020613/src/global/peer_name.h Wed Jun 26 15:26:48 2002 >@@ -22,6 +22,9 @@ > #define PEER_TYPE_UNKNOWN 0 > #define PEER_TYPE_INET 1 > #define PEER_TYPE_LOCAL 2 >+#ifdef INET6 >+#define PEER_TYPE_INET6 3 >+#endif > > extern PEER_NAME *peer_name(int); > >diff -Pur postfix-1.1.11.20020613-orig/src/global/pfixtls.c postfix-1.1.11-20020613/src/global/pfixtls.c >--- postfix-1.1.11.20020613-orig/src/global/pfixtls.c Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11.20020613/src/global/pfixtls.c Wed Jun 26 15:26:48 2002 >@@ -0,0 +1,2742 @@ >+/*++ >+/* NAME >+/* pfixtls >+/* SUMMARY >+/* interface to openssl routines >+/* SYNOPSIS >+/* #include <pfixtls.h> >+/* >+/* const long scache_db_version; >+/* const long openssl_version; >+/* >+/* int pfixtls_serverengine; >+/* >+/* int pfixtls_clientengine; >+/* >+/* int pfixtls_timed_read(fd, buf, len, timeout, unused_context) >+/* int fd; >+/* void *buf; >+/* unsigned len; >+/* int timeout; >+/* void *context; >+/* >+/* int pfixtls_timed_write(fd, buf, len, timeout, unused_context); >+/* int fd; >+/* void *buf; >+/* unsigned len; >+/* int timeout; >+/* void *context; >+/* >+/* int pfixtls_init_serverengine(verifydepth, askcert); >+/* int verifydepth; >+/* int askcert; >+/* >+/* int pfixtls_start_servertls(stream, timeout, peername, peeraddr, >+/* tls_info, requirecert); >+/* VSTREAM *stream; >+/* int timeout; >+/* const char *peername; >+/* const char *peeraddr; >+/* tls_info_t *tls_info; >+/* int requirecert; >+/* >+/* int pfixtls_stop_servertls(stream, failure, tls_info); >+/* VSTREAM *stream; >+/* int failure; >+/* tls_info_t *tls_info; >+/* >+/* int pfixtls_init_clientengine(verifydepth); >+/* int verifydepth; >+/* >+/* int pfixtls_start_clienttls(stream, timeout, peername, peeraddr, >+/* tls_info); >+/* VSTREAM *stream; >+/* int timeout; >+/* const char *peername; >+/* const char *peeraddr; >+/* tls_info_t *tls_info; >+/* >+/* int pfixtls_stop_clienttls(stream, failure, tls_info); >+/* VSTREAM *stream; >+/* int failure; >+/* tls_info_t *tls_info; >+/* >+/* DESCRIPTION >+/* This module is the interface between Postfix and the OpenSSL library. >+/* >+/* pfixtls_timed_read() reads the requested number of bytes calling >+/* SSL_read(). pfixtls_time_read() will only be called indirect >+/* as a VSTREAM_FN function. >+/* pfixtls_timed_write() is the corresponding write function. >+/* >+/* pfixtls_init_serverengine() is called once when smtpd is started >+/* in order to initialize as much of the TLS stuff as possible. >+/* The certificate handling is also decided during the setup phase, >+/* so that a peer specific handling is not possible. >+/* >+/* pfixtls_init_clientengine() is the corresponding function called >+/* in smtp. Here we take the peer's (server's) certificate in any >+/* case. >+/* >+/* pfixtls_start_servertls() activates the TLS feature for the VSTREAM >+/* passed as argument. We expect that all buffers are flushed and the >+/* TLS handshake can begin immediately. Information about the peer >+/* is stored into the tls_info structure passed as argument. >+/* >+/* pfixtls_stop_servertls() sends the "close notify" alert via >+/* SSL_shutdown() to the peer and resets all connection specific >+/* TLS data. As RFC2487 does not specify a seperate shutdown, it >+/* is supposed that the underlying TCP connection is shut down >+/* immediately afterwards, so we don't care about additional data >+/* coming through the channel. >+/* If the failure flag is set, the session is cleared from the cache. >+/* >+/* pfixtls_start_clienttls() and pfixtls_stop_clienttls() are the >+/* corresponding functions for smtp. >+/* >+/* Once the TLS connection is initiated, information about the TLS >+/* state is available via the tls_info structure: >+/* protocol holds the protocol name (SSLv2, SSLv3, TLSv1), >+/* tls_info->cipher_name the cipher name (e.g. RC4/MD5), >+/* tls_info->cipher_usebits the number of bits actually used (e.g. 40), >+/* tls_info->cipher_algbits the number of bits the algorithm is based on >+/* (e.g. 128). >+/* The last two values may be different when talking to a crippled >+/* - ahem - export controled peer (e.g. 40/128). >+/* >+/* The status of the peer certificate verification is available in >+/* pfixtls_peer_verified. It is set to 1, when the certificate could >+/* be verified. >+/* If the peer offered a certifcate, part of the certificate data are >+/* available as: >+/* tls_info->peer_subject X509v3-oneline with the DN of the peer >+/* tls_info->peer_CN extracted CommonName of the peer >+/* tls_info->peer_issuer X509v3-oneline with the DN of the issuer >+/* tls_info->peer_CN extracted CommonName of the issuer >+/* tls_info->PEER_FINGERPRINT fingerprint of the certificate >+/* >+/* DESCRIPTION (SESSION CACHING) >+/* In order to achieve high performance when using a lot of connections >+/* with TLS, session caching is implemented. It reduces both the CPU load >+/* (less cryptograpic operations) and the network load (the amount of >+/* certificate data exchanged is reduced). >+/* Since postfix uses a setup of independent processes for receiving >+/* and sending email, the processes must exchange the session information. >+/* Several connections at the same time between the identical peers can >+/* occur, so uniqueness and race conditions have to be taken into >+/* account. >+/* I have checked both Apache-SSL (Ben Laurie), using a seperate "gcache" >+/* process and Apache mod_ssl (Ralf S. Engelshall), using shared memory >+/* between several identical processes spawned from one parent. >+/* >+/* Postfix/TLS uses a database approach based on the internal "dict" >+/* interface. Since the session cache information is approximately >+/* 1300 bytes binary data, it will not fit into the dbm/ndbm model. >+/* It also needs write access to the database, ruling out most other >+/* interface, leaving Berkeley DB, which however cannot handle concurrent >+/* access by several processes. Hence a modified SDBM (public domain DBM) >+/* with enhanced buffer size is used and concurrent write capability >+/* is used. SDBM is part of Postfix/TLS. >+/* >+/* Realization: >+/* Both (client and server) session cache are realized by individual >+/* cache databases. A common database would not make sense, since the >+/* key criteria are different (session ID for server, peername for >+/* client). >+/* >+/* Server side: >+/* Session created by OpenSSL have a 32 byte session id, yielding a >+/* 64 char file name. I consider these sessions to be unique. If they >+/* are not, the last session will win, overwriting the older one in >+/* the database. Remember: everything that is lost is a temporary >+/* information and not more than a renegotiation will happen. >+/* Originating from the same client host, several sessions can come >+/* in (e.g. from several users sending mail with Netscape at the same >+/* time), so the session id is the correct identifier; the hostname >+/* is of no importance, here. >+/* >+/* Client side: >+/* We cannot recall sessions based on their session id, because we would >+/* have to check every session on disk for a matching server name, so >+/* the lookup has to be done based on the FQDN of the peer (receiving >+/* host). >+/* With regard to uniqueness, we might experience several open connections >+/* to the same server at the same time. This is even very likely to >+/* happen, since we might have several mails for the same destination >+/* in the queue, when a queue run is started. So several smtp's might >+/* negotiate sessions at the same time. We can however only save one >+/* session for one host. >+/* Like on the server side, the "last write" wins. The reason is >+/* quite simple. If we don't want to overwrite old sessions, an old >+/* session file will just stay in place until it is expired. In the >+/* meantime we would lose "fresh" session however. So we will keep the >+/* fresh one instead to avoid unnecessary renegotiations. >+/* >+/* Session lifetime: >+/* RFC2246 recommends a session lifetime of less than 24 hours. The >+/* default is 300 seconds (5 minutes) for OpenSSL and is also used >+/* this way in e.g. mod_ssl. The typical usage for emails might be >+/* humans typing in emails and sending them, which might take just >+/* a while, so I think 3600 seconds (1 hour) is a good compromise. >+/* If the environment is save (the cached session contains secret >+/* key data), one might even consider using a longer timeout. Anyway, >+/* since everlasting sessions must be avoided, the session timeout >+/* is done based on the creation date of the session and so each >+/* session will timeout eventually. >+/* >+/* Connection failures: >+/* RFC2246 requires us to remove sessions if something went wrong. >+/* Since the in-memory session cache of other smtp[d] processes cannot >+/* be controlled by simple means, we completely rely on the disc >+/* based session caching and remove all sessions from memory after >+/* connection closure. >+/* >+/* Cache cleanup: >+/* Since old entries have to be removed from the session cache, a >+/* cleanup process is needed that runs through the collected session >+/* files on regular basis. The task is performed by tlsmgr based on >+/* the timestamp created by pfixtls and included in the saved session, >+/* so that tlsmgr has not to care about the SSL_SESSION internal data. >+/* >+/* BUGS >+/* The memory allocation policy of the OpenSSL library is not well >+/* documented, especially when loading sessions from disc. Hence there >+/* might be memory leaks. >+/* >+/* LICENSE >+/* AUTHOR(S) >+/* Lutz Jaenicke >+/* BTU Cottbus >+/* Allgemeine Elektrotechnik >+/* Universitaetsplatz 3-4 >+/* D-03044 Cottbus, Germany >+/*--*/ >+ >+/* System library. */ >+ >+#include <sys_defs.h> >+#include <sys/types.h> >+#include <sys/stat.h> >+#include <sys/time.h> /* gettimeofday, not in POSIX */ >+#include <unistd.h> >+#include <stdio.h> >+#include <string.h> >+#include <errno.h> >+#include <ctype.h> >+ >+/* Utility library. */ >+ >+#include <iostuff.h> >+#include <mymalloc.h> >+#include <vstring.h> >+#include <vstream.h> >+#include <dict.h> >+#include <myflock.h> >+#include <stringops.h> >+#include <msg.h> >+#include <connect.h> >+ >+/* Application-specific. */ >+ >+#include "mail_params.h" >+#include "pfixtls.h" >+ >+#define STR vstring_str >+ >+const tls_info_t tls_info_zero = { >+ 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, 0, 0 >+}; >+ >+#ifdef HAS_SSL >+ >+/* OpenSSL library. */ >+ >+#include <openssl/lhash.h> >+#include <openssl/bn.h> >+#include <openssl/err.h> >+#include <openssl/pem.h> >+#include <openssl/x509.h> >+#include <openssl/rand.h> >+#include <openssl/ssl.h> >+ >+/* We must keep some of the info available */ >+static const char hexcodes[] = "0123456789ABCDEF"; >+ >+/* >+ * When saving sessions, we want to make sure, that the lenght of the key >+ * is somehow limited. When saving client sessions, the hostname is used >+ * as key. According to HP-UX 10.20, MAXHOSTNAMELEN=64. Maybe new standards >+ * will increase this value, but as this will break compatiblity with existing >+ * implementations, we won't see this for long. We therefore choose a limit >+ * of 64 bytes. >+ * The length of the (TLS) session id can be up to 32 bytes according to >+ * RFC2246, so it fits well into the 64bytes limit. >+ */ >+#define ID_MAXLENGTH 64 /* Max ID length in bytes */ >+ >+/* >+ * The session_id_context is set, such that the client knows which services >+ * on a host share the same session information (on the postfix host may >+ * as well run a TLS-enabled webserver. >+ */ >+static char server_session_id_context[] = "Postfix/TLS"; /* anything will do */ >+static int TLScontext_index = -1; >+static int TLSpeername_index = -1; >+static int do_dump = 0; >+static DH *dh_512 = NULL, *dh_1024 = NULL; >+static SSL_CTX *ctx = NULL; >+ >+static int rand_exch_fd = -1; >+ >+static DICT *scache_db = NULL; >+const long scache_db_version = 0x00000003L; >+const long openssl_version = OPENSSL_VERSION_NUMBER; >+ >+ >+int pfixtls_serverengine = 0; >+static int pfixtls_serveractive = 0; /* available or not */ >+ >+int pfixtls_clientengine = 0; >+static int pfixtls_clientactive = 0; /* available or not */ >+ >+/* >+ * Define a maxlength for certificate onelines. The length is checked by >+ * all routines when copying. >+ */ >+#define CCERT_BUFSIZ 256 >+ >+typedef struct { >+ SSL *con; >+ BIO *internal_bio; /* postfix/TLS side of pair */ >+ BIO *network_bio; /* netsork side of pair */ >+ char peer_subject[CCERT_BUFSIZ]; >+ char peer_issuer[CCERT_BUFSIZ]; >+ char peer_CN[CCERT_BUFSIZ]; >+ char issuer_CN[CCERT_BUFSIZ]; >+ unsigned char md[EVP_MAX_MD_SIZE]; >+ char fingerprint[EVP_MAX_MD_SIZE * 3]; >+ char peername_save[129]; >+ int enforce_verify_errors; >+ int enforce_CN; >+} TLScontext_t; >+ >+typedef struct { >+ int pid; >+ struct timeval tv; >+} randseed_t; >+ >+static randseed_t randseed; >+ >+/* >+ * Finally some "backup" DH-Parameters to be loaded, if no parameters are >+ * explicitely loaded from file. >+ */ >+static unsigned char dh512_p[] = { >+ 0x88, 0x3F, 0x00, 0xAF, 0xFC, 0x0C, 0x8A, 0xB8, 0x35, 0xCD, 0xE5, 0xC2, >+ 0x0F, 0x55, 0xDF, 0x06, 0x3F, 0x16, 0x07, 0xBF, 0xCE, 0x13, 0x35, 0xE4, >+ 0x1C, 0x1E, 0x03, 0xF3, 0xAB, 0x17, 0xF6, 0x63, 0x50, 0x63, 0x67, 0x3E, >+ 0x10, 0xD7, 0x3E, 0xB4, 0xEB, 0x46, 0x8C, 0x40, 0x50, 0xE6, 0x91, 0xA5, >+ 0x6E, 0x01, 0x45, 0xDE, 0xC9, 0xB1, 0x1F, 0x64, 0x54, 0xFA, 0xD9, 0xAB, >+ 0x4F, 0x70, 0xBA, 0x5B, >+}; >+ >+static unsigned char dh512_g[] = { >+ 0x02, >+}; >+ >+static unsigned char dh1024_p[] = { >+ 0xB0, 0xFE, 0xB4, 0xCF, 0xD4, 0x55, 0x07, 0xE7, 0xCC, 0x88, 0x59, 0x0D, >+ 0x17, 0x26, 0xC5, 0x0C, 0xA5, 0x4A, 0x92, 0x23, 0x81, 0x78, 0xDA, 0x88, >+ 0xAA, 0x4C, 0x13, 0x06, 0xBF, 0x5D, 0x2F, 0x9E, 0xBC, 0x96, 0xB8, 0x51, >+ 0x00, 0x9D, 0x0C, 0x0D, 0x75, 0xAD, 0xFD, 0x3B, 0xB1, 0x7E, 0x71, 0x4F, >+ 0x3F, 0x91, 0x54, 0x14, 0x44, 0xB8, 0x30, 0x25, 0x1C, 0xEB, 0xDF, 0x72, >+ 0x9C, 0x4C, 0xF1, 0x89, 0x0D, 0x68, 0x3F, 0x94, 0x8E, 0xA4, 0xFB, 0x76, >+ 0x89, 0x18, 0xB2, 0x91, 0x16, 0x90, 0x01, 0x99, 0x66, 0x8C, 0x53, 0x81, >+ 0x4E, 0x27, 0x3D, 0x99, 0xE7, 0x5A, 0x7A, 0xAF, 0xD5, 0xEC, 0xE2, 0x7E, >+ 0xFA, 0xED, 0x01, 0x18, 0xC2, 0x78, 0x25, 0x59, 0x06, 0x5C, 0x39, 0xF6, >+ 0xCD, 0x49, 0x54, 0xAF, 0xC1, 0xB1, 0xEA, 0x4A, 0xF9, 0x53, 0xD0, 0xDF, >+ 0x6D, 0xAF, 0xD4, 0x93, 0xE7, 0xBA, 0xAE, 0x9B, >+}; >+ >+static unsigned char dh1024_g[] = { >+ 0x02, >+}; >+ >+/* >+ * DESCRIPTION: Keeping control of the network interface using BIO-pairs. >+ * >+ * When the TLS layer is active, all input/output must be filtered through >+ * it. On the other hand to handle timeout conditions, full control over >+ * the network socket must be kept. This rules out the "normal way" of >+ * connecting the TLS layer directly to the socket. >+ * The TLS layer is realized with a BIO-pair: >+ * >+ * postfix | TLS-engine >+ * | | >+ * +--------> SSL_operations() >+ * | /\ || >+ * | || \/ >+ * | BIO-pair (internal_bio) >+ * +--------< BIO-pair (network_bio) >+ * | | >+ * socket | >+ * >+ * The normal postfix operations connect to the SSL operations to send >+ * and retrieve (cleartext) data. Inside the TLS-engine the data are converted >+ * to/from TLS protocol. The TLS functionality itself is only connected to >+ * the internal_bio and hence only has status information about this internal >+ * interface. >+ * Thus, if the SSL_operations() return successfully (SSL_ERROR_NONE) or want >+ * to read (SSL_ERROR_WANT_READ) there may as well be data inside the buffering >+ * BIO-pair. So whenever an SSL_operation() returns without a fatal error, >+ * the BIO-pair internal buffer must be flushed to the network. >+ * NOTE: This is especially true in the SSL_ERROR_WANT_READ case: the TLS-layer >+ * might want to read handshake data, that will never come since its own >+ * written data will only reach the peer after flushing the buffer! >+ * >+ * The BIO-pair buffer size has been set to 8192 bytes, this is an arbitrary >+ * value that can hold more data than the typical PMTU, so that it does >+ * not force the generation of packets smaller than necessary. >+ * It is also larger than the default VSTREAM_BUFSIZE (4096, see vstream.h), >+ * so that large write operations could be handled within one call. >+ * The internal buffer in the network/network_bio handling layer has been >+ * set to the same value, since this seems to be reasonable. The code is >+ * however able to handle arbitrary values smaller or larger than the >+ * buffer size in the BIO-pair. >+ */ >+ >+const ssize_t BIO_bufsiz = 8192; >+ >+/* >+ * The interface layer between network and BIO-pair. The BIO-pair buffers >+ * the data to/from the TLS layer. Hence, at any time, there may be data >+ * in the buffer that must be written to the network. This writing has >+ * highest priority because the handshake might fail otherwise. >+ * Only then a read_request can be satisfied. >+ */ >+static int network_biopair_interop(int fd, int timeout, BIO *network_bio) >+{ >+ int want_write; >+ int num_write; >+ int write_pos; >+ int from_bio; >+ int want_read; >+ int num_read; >+ int to_bio; >+#define NETLAYER_BUFFERSIZE 8192 >+ char buffer[8192]; >+ >+ while ((want_write = BIO_ctrl_pending(network_bio)) > 0) { >+ if (want_write > NETLAYER_BUFFERSIZE) >+ want_write = NETLAYER_BUFFERSIZE; >+ from_bio = BIO_read(network_bio, buffer, want_write); >+ >+ /* >+ * Write the complete contents of the buffer. Since TLS performs >+ * underlying handshaking, we cannot afford to leave the buffer >+ * unflushed, as we could run into a deadlock trap (the peer >+ * waiting for a final byte and we already waiting for his reply >+ * in read position). >+ */ >+ write_pos = 0; >+ do { >+ if (timeout > 0 && write_wait(fd, timeout) < 0) >+ return (-1); >+ num_write = write(fd, buffer + write_pos, from_bio - write_pos); >+ if (num_write <= 0) >+ return (-1); /* something happened to the socket */ >+ write_pos += num_write; >+ } while (write_pos < from_bio); >+ } >+ >+ while ((want_read = BIO_ctrl_get_read_request(network_bio)) > 0) { >+ if (want_read > NETLAYER_BUFFERSIZE) >+ want_read = NETLAYER_BUFFERSIZE; >+ if (timeout > 0 && read_wait(fd, timeout) < 0) >+ return (-1); >+ num_read = read(fd, buffer, want_read); >+ if (num_read <= 0) >+ return (-1); /* something happened to the socket */ >+ to_bio = BIO_write(network_bio, buffer, num_read); >+ if (to_bio != num_read) >+ msg_fatal("to_bio != num_read"); >+ } >+ >+ return (0); >+} >+ >+static void pfixtls_print_errors(void); >+ >+ /* >+ * Function to perform the handshake for SSL_accept(), SSL_connect(), >+ * and SSL_shutdown() and perform the SSL_read(), SSL_write() operations. >+ * Call the underlying network_biopair_interop-layer to make sure the >+ * write buffer is flushed after every operation (that did not fail with >+ * a fatal error). >+ */ >+static int do_tls_operation(int fd, int timeout, TLScontext_t *TLScontext, >+ int (*hsfunc)(SSL *), >+ int (*rfunc)(SSL *, void *, int), >+ int (*wfunc)(SSL *, const void *, int), >+ char *buf, int num) >+{ >+ int status; >+ int err; >+ int retval = 0; >+ int biop_retval; >+ int done = 0; >+ >+ while (!done) { >+ if (hsfunc) >+ status = hsfunc(TLScontext->con); >+ else if (rfunc) >+ status = rfunc(TLScontext->con, buf, num); >+ else >+ status = wfunc(TLScontext->con, (const char *)buf, num); >+ err = SSL_get_error(TLScontext->con, status); >+ >+#if (OPENSSL_VERSION_NUMBER <= 0x0090581fL) >+ /* >+ * There is a bug up to and including OpenSSL-0.9.5a: if an error >+ * occurs while checking the peers certificate due to some certificate >+ * error (e.g. as happend with a RSA-padding error), the error is put >+ * onto the error stack. If verification is not enforced, this error >+ * should be ignored, but the error-queue is not cleared, so we >+ * can find this error here. The bug has been fixed on May 28, 2000. >+ * >+ * This bug so far has only manifested as >+ * 4800:error:0407006A:rsa routines:RSA_padding_check_PKCS1_type_1:block type is not 01:rsa_pk1.c:100: >+ * 4800:error:04067072:rsa routines:RSA_EAY_PUBLIC_DECRYPT:padding check failed:rsa_eay.c:396: >+ * 4800:error:0D079006:asn1 encoding routines:ASN1_verify:bad get asn1 object call:a_verify.c:109: >+ * so that we specifically test for this error. We print the errors >+ * to the logfile and automatically clear the error queue. Then we >+ * retry to get another error code. We cannot do better, since we >+ * can only retrieve the last entry of the error-queue without >+ * actually cleaning it on the way. >+ * >+ * This workaround is secure, as verify_result is set to "failed" >+ * anyway. >+ */ >+ if (err == SSL_ERROR_SSL) { >+ if (ERR_peek_error() == 0x0407006AL) { >+ pfixtls_print_errors(); /* Keep information for the logfile */ >+ msg_info("OpenSSL <= 0.9.5a workaround called: certificate errors ignored"); >+ err = SSL_get_error(TLScontext->con, status); >+ } >+ } >+#endif >+ >+ switch (err) { >+ case SSL_ERROR_NONE: /* success */ >+ retval = status; >+ done = 1; /* no break, flush buffer before */ >+ /* leaving */ >+ case SSL_ERROR_WANT_WRITE: >+ case SSL_ERROR_WANT_READ: >+ biop_retval = network_biopair_interop(fd, timeout, >+ TLScontext->network_bio); >+ if (biop_retval < 0) >+ return (-1); /* fatal network error */ >+ break; >+ case SSL_ERROR_ZERO_RETURN: /* connection was closed cleanly */ >+ case SSL_ERROR_SYSCALL: >+ case SSL_ERROR_SSL: >+ default: >+ retval = status; >+ done = 1; >+ ; >+ } >+ }; >+ return retval; >+} >+ >+int pfixtls_timed_read(int fd, void *buf, unsigned buf_len, int timeout, >+ void *context) >+{ >+ int i; >+ int ret; >+ char mybuf[40]; >+ char *mybuf2; >+ TLScontext_t *TLScontext; >+ >+ TLScontext = (TLScontext_t *)context; >+ if (!TLScontext) >+ msg_fatal("Called tls_timed_read() without TLS-context"); >+ >+ ret = do_tls_operation(fd, timeout, TLScontext, NULL, SSL_read, NULL, >+ (char *)buf, buf_len); >+ if ((pfixtls_serveractive && var_smtpd_tls_loglevel >= 4) || >+ (pfixtls_clientactive && var_smtp_tls_loglevel >= 4)) { >+ mybuf2 = (char *) buf; >+ if (ret > 0) { >+ i = 0; >+ while ((i < 39) && (i < ret) && (mybuf2[i] != 0)) { >+ mybuf[i] = mybuf2[i]; >+ i++; >+ } >+ mybuf[i] = '\0'; >+ msg_info("Read %d chars: %s", ret, mybuf); >+ } >+ } >+ return (ret); >+} >+ >+int pfixtls_timed_write(int fd, void *buf, unsigned len, int timeout, >+ void *context) >+{ >+ int i; >+ char mybuf[40]; >+ char *mybuf2; >+ TLScontext_t *TLScontext; >+ >+ TLScontext = (TLScontext_t *)context; >+ if (!TLScontext) >+ msg_fatal("Called tls_timed_write() without TLS-context"); >+ >+ if ((pfixtls_serveractive && var_smtpd_tls_loglevel >= 4) || >+ (pfixtls_clientactive && var_smtp_tls_loglevel >= 4)) { >+ mybuf2 = (char *) buf; >+ if (len > 0) { >+ i = 0; >+ while ((i < 39) && (i < len) && (mybuf2[i] != 0)) { >+ mybuf[i] = mybuf2[i]; >+ i++; >+ } >+ mybuf[i] = '\0'; >+ msg_info("Write %d chars: %s", len, mybuf); >+ } >+ } >+ return (do_tls_operation(fd, timeout, TLScontext, NULL, NULL, SSL_write, >+ buf, len)); >+} >+ >+/* Add some more entropy to the pool by adding the actual time */ >+ >+static void pfixtls_stir_seed(void) >+{ >+ GETTIMEOFDAY(&randseed.tv); >+ RAND_seed(&randseed, sizeof(randseed_t)); >+} >+ >+/* >+ * Skeleton taken from OpenSSL crypto/err/err_prn.c. >+ * Query the error stack and print the error string into the logging facility. >+ * Clear the error stack on the way. >+ */ >+ >+static void pfixtls_print_errors(void) >+{ >+ unsigned long l; >+ char buf[256]; >+ const char *file; >+ const char *data; >+ int line; >+ int flags; >+ unsigned long es; >+ >+ es = CRYPTO_thread_id(); >+ while ((l = ERR_get_error_line_data(&file, &line, &data, &flags)) != 0) { >+ if (flags & ERR_TXT_STRING) >+ msg_info("%lu:%s:%s:%d:%s:", es, ERR_error_string(l, buf), >+ file, line, data); >+ else >+ msg_info("%lu:%s:%s:%d:", es, ERR_error_string(l, buf), >+ file, line); >+ } >+} >+ >+ /* >+ * Set up the cert things on the server side. We do need both the >+ * private key (in key_file) and the cert (in cert_file). >+ * Both files may be identical. >+ * >+ * This function is taken from OpenSSL apps/s_cb.c >+ */ >+ >+static int set_cert_stuff(SSL_CTX * ctx, char *cert_file, char *key_file) >+{ >+ if (cert_file != NULL) { >+ if (SSL_CTX_use_certificate_chain_file(ctx, cert_file) <= 0) { >+ msg_info("unable to get certificate from '%s'", cert_file); >+ pfixtls_print_errors(); >+ return (0); >+ } >+ if (key_file == NULL) >+ key_file = cert_file; >+ if (SSL_CTX_use_PrivateKey_file(ctx, key_file, >+ SSL_FILETYPE_PEM) <= 0) { >+ msg_info("unable to get private key from '%s'", key_file); >+ pfixtls_print_errors(); >+ return (0); >+ } >+ /* Now we know that a key and cert have been set against >+ * the SSL context */ >+ if (!SSL_CTX_check_private_key(ctx)) { >+ msg_info("Private key does not match the certificate public key"); >+ return (0); >+ } >+ } >+ return (1); >+} >+ >+/* taken from OpenSSL apps/s_cb.c */ >+ >+static RSA *tmp_rsa_cb(SSL * s, int export, int keylength) >+{ >+ static RSA *rsa_tmp = NULL; >+ >+ if (rsa_tmp == NULL) { >+ rsa_tmp = RSA_generate_key(keylength, RSA_F4, NULL, NULL); >+ } >+ return (rsa_tmp); >+} >+ >+ >+static DH *get_dh512(void) >+{ >+ DH *dh; >+ >+ if (dh_512 == NULL) { >+ /* No parameter file loaded, use the compiled in parameters */ >+ if ((dh = DH_new()) == NULL) return(NULL); >+ dh->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL); >+ dh->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL); >+ if ((dh->p == NULL) || (dh->g == NULL)) >+ return(NULL); >+ else >+ dh_512 = dh; >+ } >+ return (dh_512); >+} >+ >+static DH *get_dh1024(void) >+{ >+ DH *dh; >+ >+ if (dh_1024 == NULL) { >+ /* No parameter file loaded, use the compiled in parameters */ >+ if ((dh = DH_new()) == NULL) return(NULL); >+ dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL); >+ dh->g = BN_bin2bn(dh1024_g, sizeof(dh1024_g), NULL); >+ if ((dh->p == NULL) || (dh->g == NULL)) >+ return(NULL); >+ else >+ dh_1024 = dh; >+ } >+ return (dh_1024); >+} >+ >+/* partly inspired by mod_ssl */ >+ >+static DH *tmp_dh_cb(SSL *s, int export, int keylength) >+{ >+ DH *dh_tmp = NULL; >+ >+ if (export) { >+ if (keylength == 512) >+ dh_tmp = get_dh512(); /* export cipher */ >+ else if (keylength == 1024) >+ dh_tmp = get_dh1024(); /* normal */ >+ else >+ dh_tmp = get_dh1024(); /* not on-the-fly (too expensive) */ >+ /* so use the 1024bit instead */ >+ } >+ else { >+ dh_tmp = get_dh1024(); /* sign-only certificate */ >+ } >+ return (dh_tmp); >+} >+ >+ >+/* >+ * Skeleton taken from OpenSSL apps/s_cb.c >+ * >+ * The verify_callback is called several times (directly or indirectly) from >+ * crypto/x509/x509_vfy.c. It is called as a last check for several issues, >+ * so this verify_callback() has the famous "last word". If it does return "0", >+ * the handshake is immediately shut down and the connection fails. >+ * >+ * Postfix/TLS has two modes, the "use" mode and the "enforce" mode: >+ * >+ * In the "use" mode we never want the connection to fail just because there is >+ * something wrong with the certificate (as we would have sent happily without >+ * TLS). Therefore the return value is always "1". >+ * >+ * In the "enforce" mode we can shut down the connection as soon as possible. >+ * In server mode TLS itself may be enforced (e.g. to protect passwords), >+ * but certificates are optional. In this case the handshake must not fail >+ * if we are unhappy with the certificate and return "1" in any case. >+ * Only if a certificate is required the certificate must pass the verification >+ * and failure to do so will result in immediate termination (return 0). >+ * In the client mode the decision is made with respect to the peername >+ * enforcement. If we strictly enforce the matching of the expected peername >+ * the verification must fail immediatly on verification errors. We can also >+ * immediatly check the expected peername, as it is the CommonName at level 0. >+ * In all other cases, the problem is logged, so the SSL_get_verify_result() >+ * will inform about the verification failure, but the handshake (and SMTP >+ * connection will continue). >+ * >+ * The only error condition not handled inside the OpenSSL-Library is the >+ * case of a too-long certificate chain, so we check inside verify_callback(). >+ * We only take care of this problem, if "ok = 1", because otherwise the >+ * verification already failed because of another problem and we don't want >+ * to overwrite the other error message. And if the verification failed, >+ * there is no such thing as "more failed", "most failed"... :-) >+ */ >+ >+static int verify_callback(int ok, X509_STORE_CTX * ctx) >+{ >+ char buf[256]; >+ char *CN_lowercase; >+ char *peername_left; >+ X509 *err_cert; >+ int err; >+ int depth; >+ int verify_depth; >+ int hostname_matched; >+ SSL *con; >+ TLScontext_t *TLScontext; >+ >+ err_cert = X509_STORE_CTX_get_current_cert(ctx); >+ err = X509_STORE_CTX_get_error(ctx); >+ depth = X509_STORE_CTX_get_error_depth(ctx); >+ >+ con = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); >+ TLScontext = SSL_get_ex_data(con, TLScontext_index); >+ >+ X509_NAME_oneline(X509_get_subject_name(err_cert), buf, 256); >+ if (((pfixtls_serverengine) && (var_smtpd_tls_loglevel >= 2)) || >+ ((pfixtls_clientengine) && (var_smtp_tls_loglevel >= 2))) >+ msg_info("Peer cert verify depth=%d %s", depth, buf); >+ >+ verify_depth = SSL_get_verify_depth(con); >+ if (ok && (verify_depth >= 0) && (depth > verify_depth)) { >+ ok = 0; >+ err = X509_V_ERR_CERT_CHAIN_TOO_LONG; >+ X509_STORE_CTX_set_error(ctx, err); >+ } >+ if (!ok) { >+ msg_info("verify error:num=%d:%s", err, >+ X509_verify_cert_error_string(err)); >+ } >+ >+ if (ok && (depth == 0) && pfixtls_clientengine) { >+ /* >+ * Check out the name certified against the hostname expected. >+ * In case it does not match, print an information about the result. >+ * If a matching is enforced, bump out with a verification error >+ * immediately. >+ */ >+ buf[0] = '\0'; >+ if (!X509_NAME_get_text_by_NID(X509_get_subject_name(err_cert), >+ NID_commonName, buf, 256)) { >+ msg_info("Could not parse server's subject CN"); >+ pfixtls_print_errors(); >+ } >+ CN_lowercase = lowercase(buf); >+ hostname_matched = 0; >+ if (!strcmp(TLScontext->peername_save, CN_lowercase)) >+ hostname_matched = 1; >+ else if ((strlen(CN_lowercase) > 2) && >+ (CN_lowercase[0] == '*') && (CN_lowercase[1] == '.')) { >+ /* >+ * Allow wildcard certificate matching. The proposed rules in >+ * RFCs (2818: HTTP/TLS, 2830: LDAP/TLS) are different, RFC2874 >+ * does not specify a rule, so here the strict rule is applied. >+ * An asterisk '*' is allowed as the leftmost component and may >+ * replace the left most part of the hostname. Matching is done >+ * by removing '*.' from the wildcard name and the `name.` from >+ * the peername and compare what is left. >+ */ >+ peername_left = strchr(TLScontext->peername_save, '.'); >+ if (peername_left) { >+ if (!strcmp(peername_left + 1, CN_lowercase + 2)) >+ hostname_matched = 1; >+ } >+ } >+ >+ if (!hostname_matched) { >+ msg_info("Peer verification: CommonName in certificate does not match: %s != %s", CN_lowercase, TLScontext->peername_save); >+ if (TLScontext->enforce_verify_errors && TLScontext->enforce_CN) { >+ err = X509_V_ERR_CERT_REJECTED; >+ X509_STORE_CTX_set_error(ctx, err); >+ msg_info("Verify failure: Hostname mismatch"); >+ ok = 0; >+ } >+ } >+ } >+ >+ switch (ctx->error) { >+ case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: >+ X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256); >+ msg_info("issuer= %s", buf); >+ break; >+ case X509_V_ERR_CERT_NOT_YET_VALID: >+ case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: >+ msg_info("cert not yet valid"); >+ break; >+ case X509_V_ERR_CERT_HAS_EXPIRED: >+ case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: >+ msg_info("cert has expired"); >+ break; >+ } >+ if (((pfixtls_serverengine) && (var_smtpd_tls_loglevel >= 2)) || >+ ((pfixtls_clientengine) && (var_smtp_tls_loglevel >= 2))) >+ msg_info("verify return:%d", ok); >+ >+ if (TLScontext->enforce_verify_errors) >+ return (ok); >+ else >+ return (1); >+} >+ >+/* taken from OpenSSL apps/s_cb.c */ >+ >+static void apps_ssl_info_callback(SSL * s, int where, int ret) >+{ >+ char *str; >+ int w; >+ >+ w = where & ~SSL_ST_MASK; >+ >+ if (w & SSL_ST_CONNECT) >+ str = "SSL_connect"; >+ else if (w & SSL_ST_ACCEPT) >+ str = "SSL_accept"; >+ else >+ str = "undefined"; >+ >+ if (where & SSL_CB_LOOP) { >+ msg_info("%s:%s", str, SSL_state_string_long(s)); >+ } else if (where & SSL_CB_ALERT) { >+ str = (where & SSL_CB_READ) ? "read" : "write"; >+ if ((ret & 0xff) != SSL3_AD_CLOSE_NOTIFY) >+ msg_info("SSL3 alert %s:%s:%s", str, >+ SSL_alert_type_string_long(ret), >+ SSL_alert_desc_string_long(ret)); >+ } else if (where & SSL_CB_EXIT) { >+ if (ret == 0) >+ msg_info("%s:failed in %s", >+ str, SSL_state_string_long(s)); >+ else if (ret < 0) { >+ msg_info("%s:error in %s", >+ str, SSL_state_string_long(s)); >+ } >+ } >+} >+ >+/* >+ * taken from OpenSSL crypto/bio/b_dump.c, modified to save a lot of strcpy >+ * and strcat by Matti Aarnio. >+ */ >+ >+#define TRUNCATE >+#define DUMP_WIDTH 16 >+ >+static int pfixtls_dump(const char *s, int len) >+{ >+ int ret = 0; >+ char buf[160 + 1]; >+ char *ss; >+ int i; >+ int j; >+ int rows; >+ int trunc; >+ unsigned char ch; >+ >+ trunc = 0; >+ >+#ifdef TRUNCATE >+ for (; (len > 0) && ((s[len - 1] == ' ') || (s[len - 1] == '\0')); len--) >+ trunc++; >+#endif >+ >+ rows = (len / DUMP_WIDTH); >+ if ((rows * DUMP_WIDTH) < len) >+ rows++; >+ >+ for (i = 0; i < rows; i++) { >+ buf[0] = '\0'; /* start with empty string */ >+ ss = buf; >+ >+ sprintf(ss, "%04x ", i * DUMP_WIDTH); >+ ss += strlen(ss); >+ for (j = 0; j < DUMP_WIDTH; j++) { >+ if (((i * DUMP_WIDTH) + j) >= len) { >+ strcpy(ss, " "); >+ } else { >+ ch = ((unsigned char) *((char *) (s) + i * DUMP_WIDTH + j)) >+ & 0xff; >+ sprintf(ss, "%02x%c", ch, j == 7 ? '|' : ' '); >+ ss += 3; >+ } >+ } >+ ss += strlen(ss); >+ *ss++ = ' '; >+ for (j = 0; j < DUMP_WIDTH; j++) { >+ if (((i * DUMP_WIDTH) + j) >= len) >+ break; >+ ch = ((unsigned char) *((char *) (s) + i * DUMP_WIDTH + j)) & 0xff; >+ *ss++ = (((ch >= ' ') && (ch <= '~')) ? ch : '.'); >+ if (j == 7) *ss++ = ' '; >+ } >+ *ss = 0; >+ /* >+ * if this is the last call then update the ddt_dump thing so that >+ * we will move the selection point in the debug window >+ */ >+ msg_info("%s", buf); >+ ret += strlen(buf); >+ } >+#ifdef TRUNCATE >+ if (trunc > 0) { >+ sprintf(buf, "%04x - <SPACES/NULS>\n", len + trunc); >+ msg_info("%s", buf); >+ ret += strlen(buf); >+ } >+#endif >+ return (ret); >+} >+ >+ >+ >+/* taken from OpenSSL apps/s_cb.c */ >+ >+static long bio_dump_cb(BIO * bio, int cmd, const char *argp, int argi, >+ long argl, long ret) >+{ >+ if (!do_dump) >+ return (ret); >+ >+ if (cmd == (BIO_CB_READ | BIO_CB_RETURN)) { >+ msg_info("read from %08X [%08lX] (%d bytes => %ld (0x%X))", >+ (unsigned int)bio, (unsigned long)argp, argi, >+ ret, (unsigned int)ret); >+ pfixtls_dump(argp, (int) ret); >+ return (ret); >+ } else if (cmd == (BIO_CB_WRITE | BIO_CB_RETURN)) { >+ msg_info("write to %08X [%08lX] (%d bytes => %ld (0x%X))", >+ (unsigned int)bio, (unsigned long)argp, argi, >+ ret, (unsigned int)ret); >+ pfixtls_dump(argp, (int) ret); >+ } >+ return (ret); >+} >+ >+ >+ /* >+ * Callback to retrieve a session from the external session cache. >+ */ >+static SSL_SESSION *get_session_cb(SSL *ssl, unsigned char *SessionID, >+ int length, int *copy) >+{ >+ SSL_SESSION *session; >+ char idstring[2 * ID_MAXLENGTH + 1]; >+ int n; >+ int uselength; >+ int hex_length; >+ const char *session_hex; >+ pfixtls_scache_info_t scache_info; >+ unsigned char nibble, *data, *sess_data; >+ >+ if (length > ID_MAXLENGTH) >+ uselength = ID_MAXLENGTH; /* Limit length of ID */ >+ else >+ uselength = length; >+ >+ for(n=0 ; n < uselength ; n++) >+ sprintf(idstring + 2 * n, "%02x", SessionID[n]); >+ if (var_smtpd_tls_loglevel >= 3) >+ msg_info("Trying to reload Session from disc: %s", idstring); >+ >+ session = NULL; >+ >+ session_hex = dict_get(scache_db, idstring); >+ if (session_hex) { >+ hex_length = strlen(session_hex); >+ data = (unsigned char *)mymalloc(hex_length / 2); >+ if (!data) { >+ msg_info("could not allocate memory for session reload"); >+ return(NULL); >+ } >+ >+ memset(data, 0, hex_length / 2); >+ for (n = 0; n < hex_length; n++) { >+ if ((session_hex[n] >= '0') && (session_hex[n] <= '9')) >+ nibble = session_hex[n] - '0'; >+ else >+ nibble = session_hex[n] - 'A' + 10; >+ if (n % 2) >+ data[n / 2] |= nibble; >+ else >+ data[n / 2] |= (nibble << 4); >+ } >+ >+ /* >+ * First check the version numbers, since wrong session data might >+ * hit us hard (SEGFAULT). We also have to check for expiry. >+ */ >+ memcpy(&scache_info, data, sizeof(pfixtls_scache_info_t)); >+ if ((scache_info.scache_db_version != scache_db_version) || >+ (scache_info.openssl_version != openssl_version) || >+ (scache_info.timestamp + var_smtpd_tls_scache_timeout < time(NULL))) >+ dict_del(scache_db, idstring); >+ else { >+ sess_data = data + sizeof(pfixtls_scache_info_t); >+ session = d2i_SSL_SESSION(NULL, &sess_data, >+ hex_length / 2 - sizeof(pfixtls_scache_info_t)); >+ if (!session) >+ pfixtls_print_errors(); >+ } >+ myfree((char *)data); >+ } >+ >+ if (session && (var_smtpd_tls_loglevel >= 3)) >+ msg_info("Successfully reloaded session from disc"); >+ >+ return (session); >+} >+ >+ >+static SSL_SESSION *load_clnt_session(const char *hostname, >+ int enforce_peername) >+{ >+ SSL_SESSION *session = NULL; >+ char idstring[ID_MAXLENGTH + 1]; >+ int n; >+ int uselength; >+ int length; >+ int hex_length; >+ const char *session_hex; >+ pfixtls_scache_info_t scache_info; >+ unsigned char nibble, *data, *sess_data; >+ >+ length = strlen(hostname); >+ if (length > ID_MAXLENGTH) >+ uselength = ID_MAXLENGTH; /* Limit length of ID */ >+ else >+ uselength = length; >+ >+ for(n=0 ; n < uselength ; n++) >+ idstring[n] = tolower(hostname[n]); >+ idstring[uselength] = '\0'; >+ if (var_smtp_tls_loglevel >= 3) >+ msg_info("Trying to reload Session from disc: %s", idstring); >+ >+ session_hex = dict_get(scache_db, idstring); >+ if (session_hex) { >+ hex_length = strlen(session_hex); >+ data = (unsigned char *)mymalloc(hex_length / 2); >+ if (!data) { >+ msg_info("could not allocate memory for session reload"); >+ return(NULL); >+ } >+ >+ memset(data, 0, hex_length / 2); >+ for (n = 0; n < hex_length; n++) { >+ if ((session_hex[n] >= '0') && (session_hex[n] <= '9')) >+ nibble = session_hex[n] - '0'; >+ else >+ nibble = session_hex[n] - 'A' + 10; >+ if (n % 2) >+ data[n / 2] |= nibble; >+ else >+ data[n / 2] |= (nibble << 4); >+ } >+ >+ /* >+ * First check the version numbers, since wrong session data might >+ * hit us hard (SEGFAULT). We also have to check for expiry. >+ * When we enforce_peername, we may find an old session, that was >+ * saved when enforcement was not set. In this case the session will >+ * be removed and a fresh session will be negotiated. >+ */ >+ memcpy(&scache_info, data, sizeof(pfixtls_scache_info_t)); >+ if ((scache_info.scache_db_version != scache_db_version) || >+ (scache_info.openssl_version != openssl_version) || >+ (scache_info.timestamp + var_smtpd_tls_scache_timeout < time(NULL))) >+ dict_del(scache_db, idstring); >+ else if (enforce_peername && (!scache_info.enforce_peername)) >+ dict_del(scache_db, idstring); >+ else { >+ sess_data = data + sizeof(pfixtls_scache_info_t); >+ session = d2i_SSL_SESSION(NULL, &sess_data, >+ hex_length / 2 - sizeof(time_t)); >+ strncpy(SSL_SESSION_get_ex_data(session, TLSpeername_index), >+ idstring, ID_MAXLENGTH + 1); >+ if (!session) >+ pfixtls_print_errors(); >+ } >+ myfree((char *)data); >+ } >+ >+ if (session && (var_smtp_tls_loglevel >= 3)) >+ msg_info("Successfully reloaded session from disc"); >+ >+ return (session); >+} >+ >+ >+static void create_client_lookup_id(char *idstring, char *hostname) >+{ >+ int n, len, uselength; >+ >+ len = strlen(hostname); >+ if (len > ID_MAXLENGTH) >+ uselength = ID_MAXLENGTH; /* Limit length of ID */ >+ else >+ uselength = len; >+ >+ for (n = 0 ; n < uselength ; n++) >+ idstring[n] = tolower(hostname[n]); >+ idstring[uselength] = '\0'; >+} >+ >+ >+static void create_server_lookup_id(char *idstring, SSL_SESSION *session) >+{ >+ int n, uselength; >+ >+ if (session->session_id_length > ID_MAXLENGTH) >+ uselength = ID_MAXLENGTH; /* Limit length of ID */ >+ else >+ uselength = session->session_id_length; >+ >+ for(n = 0; n < uselength ; n++) >+ sprintf(idstring + 2 * n, "%02x", session->session_id[n]); >+} >+ >+ >+static void remove_session_cb(SSL_CTX *ctx, SSL_SESSION *session) >+{ >+ char idstring[2 * ID_MAXLENGTH + 1]; >+ char *hostname; >+ >+ if (pfixtls_clientengine) { >+ hostname = SSL_SESSION_get_ex_data(session, TLSpeername_index); >+ create_client_lookup_id(idstring, hostname); >+ if (var_smtp_tls_loglevel >= 3) >+ msg_info("Trying to remove session from disc: %s", idstring); >+ } >+ else { >+ create_server_lookup_id(idstring, session); >+ if (var_smtpd_tls_loglevel >= 3) >+ msg_info("Trying to remove session from disc: %s", idstring); >+ } >+ >+ if (scache_db) >+ dict_del(scache_db, idstring); >+} >+ >+ >+/* >+ * We need space to save the peername into the SSL_SESSION, as we must >+ * look up the external database for client sessions by peername, not >+ * by session id. We therefore allocate place for the peername string, >+ * when a new SSL_SESSION is generated. It is filled later. >+ */ >+static int new_peername_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, >+ int idx, long argl, void *argp) >+{ >+ char *peername; >+ >+ peername = (char *)mymalloc(ID_MAXLENGTH + 1); >+ if (!peername) >+ return 0; >+ peername[0] = '\0'; /* initialize */ >+ return CRYPTO_set_ex_data(ad, idx, peername); >+} >+ >+/* >+ * When the SSL_SESSION is removed again, we must free the memory to avoid >+ * leaks. >+ */ >+static void free_peername_func(void *parent, void *ptr, CRYPTO_EX_DATA *ad, >+ int idx, long argl, void *argp) >+{ >+ myfree(CRYPTO_get_ex_data(ad, idx)); >+} >+ >+/* >+ * Duplicate application data, when a SSL_SESSION is duplicated >+ */ >+static int dup_peername_func(CRYPTO_EX_DATA *to, CRYPTO_EX_DATA *from, >+ void *from_d, int idx, long argl, void *argp) >+{ >+ char *peername_old, *peername_new; >+ >+ peername_old = CRYPTO_get_ex_data(from, idx); >+ peername_new = CRYPTO_get_ex_data(to, idx); >+ if (!peername_old || !peername_new) >+ return 0; >+ memcpy(peername_new, peername_old, ID_MAXLENGTH + 1); >+ return 1; >+} >+ >+ >+ /* >+ * Save a new session to the external cache >+ */ >+static int new_session_cb(SSL *ssl, SSL_SESSION *session) >+{ >+ char idstring[2 * ID_MAXLENGTH + 1]; >+ int n; >+ int dsize; >+ int len; >+ unsigned char *data, *sess_data; >+ pfixtls_scache_info_t scache_info; >+ char *hexdata, *hostname; >+ TLScontext_t *TLScontext; >+ >+ if (pfixtls_clientengine) { >+ TLScontext = SSL_get_ex_data(ssl, TLScontext_index); >+ hostname = TLScontext->peername_save; >+ create_client_lookup_id(idstring, hostname); >+ strncpy(SSL_SESSION_get_ex_data(session, TLSpeername_index), >+ hostname, ID_MAXLENGTH + 1); >+ /* >+ * Remember, whether peername matching was enforced when the session >+ * was created. If later enforce mode is enabled, we do not want to >+ * reuse a session that was not sufficiently checked. >+ */ >+ scache_info.enforce_peername = >+ (TLScontext->enforce_verify_errors && TLScontext->enforce_CN); >+ >+ if (var_smtp_tls_loglevel >= 3) >+ msg_info("Trying to save session for hostID to disc: %s", idstring); >+ >+#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L) >+ /* >+ * Ugly Hack: OpenSSL before 0.9.6a does not store the verify >+ * result in sessions for the client side. >+ * We modify the session directly which is version specific, >+ * but this bug is version specific, too. >+ * >+ * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before >+ * beta1 have this bug, it has been fixed during development >+ * of 0.9.6a. The development version of 0.9.7 can have this >+ * bug, too. It has been fixed on 2000/11/29. >+ */ >+ session->verify_result = SSL_get_verify_result(TLScontext->con); >+#endif >+ >+ } >+ else { >+ create_server_lookup_id(idstring, session); >+ if (var_smtpd_tls_loglevel >= 3) >+ msg_info("Trying to save Session to disc: %s", idstring); >+ } >+ >+ >+ /* >+ * Get the session and convert it into some "database" useable form. >+ * First, get the length of the session to allocate the memory. >+ */ >+ dsize = i2d_SSL_SESSION(session, NULL); >+ if (dsize < 0) { >+ msg_info("Could not access session"); >+ return 0; >+ } >+ data = (unsigned char *)mymalloc(dsize + sizeof(pfixtls_scache_info_t)); >+ if (!data) { >+ msg_info("could not allocate memory for SSL session"); >+ return 0; >+ } >+ >+ /* >+ * OpenSSL is not robust against wrong session data (might SEGFAULT), >+ * so we secure it against version ids (session cache structure as well >+ * as OpenSSL version). >+ */ >+ scache_info.scache_db_version = scache_db_version; >+ scache_info.openssl_version = openssl_version; >+ >+ /* >+ * Put a timestamp, so that expiration can be checked without >+ * analyzing the session data itself. (We would need OpenSSL funtions, >+ * since the SSL_SESSION is a private structure.) >+ */ >+ scache_info.timestamp = time(NULL); >+ >+ memcpy(data, &scache_info, sizeof(pfixtls_scache_info_t)); >+ sess_data = data + sizeof(pfixtls_scache_info_t); >+ >+ /* >+ * Now, obtain the session. Unfortunately, it is binary and dict_update >+ * cannot handle binary data (it could contain '\0' in it) directly. >+ * To save memory we could use base64 encoding. To make handling easier, >+ * we simply use hex format. >+ */ >+ len = i2d_SSL_SESSION(session, &sess_data); >+ len += sizeof(pfixtls_scache_info_t); >+ >+ hexdata = (char *)mymalloc(2 * len + 1); >+ >+ if (!hexdata) { >+ msg_info("could not allocate memory for SSL session (HEX)"); >+ myfree((char *)data); >+ return 0; >+ } >+ for (n = 0; n < len; n++) { >+ hexdata[n * 2] = hexcodes[(data[n] & 0xf0) >> 4]; >+ hexdata[(n * 2) + 1] = hexcodes[(data[n] & 0x0f)]; >+ } >+ hexdata[len * 2] = '\0'; >+ >+ /* >+ * The session id is a hex string, all uppercase. We are using SDBM as >+ * compiled into Postfix with 8kB maximum entry size, so we set a limit >+ * when caching. If the session is not cached, we have to renegotiate, >+ * not more, not less. For a real session, this limit should never be >+ * met >+ */ >+ if (strlen(idstring) + strlen(hexdata) < 8000) >+ dict_put(scache_db, idstring, hexdata); >+ >+ myfree(hexdata); >+ myfree((char *)data); >+ return (1); >+} >+ >+ >+ /* >+ * pfixtls_exchange_seed: read bytes from the seed exchange-file (expect >+ * 1024 bytes)and immediately write back random bytes. Do so with EXCLUSIVE >+ * lock, so * that each process will find a completely different (and >+ * reseeded) file. >+ */ >+static void pfixtls_exchange_seed(void) >+{ >+ unsigned char buffer[1024]; >+ >+ if (rand_exch_fd == -1) >+ return; >+ >+ if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) != 0) >+ msg_info("Could not lock random exchange file: %s", >+ strerror(errno)); >+ >+ lseek(rand_exch_fd, 0, SEEK_SET); >+ if (read(rand_exch_fd, buffer, 1024) < 0) >+ msg_fatal("reading exchange file failed"); >+ RAND_seed(buffer, 1024); >+ >+ RAND_bytes(buffer, 1024); >+ lseek(rand_exch_fd, 0, SEEK_SET); >+ if (write(rand_exch_fd, buffer, 1024) != 1024) >+ msg_fatal("Writing exchange file failed"); >+ >+ if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) != 0) >+ msg_fatal("Could not unlock random exchange file: %s", >+ strerror(errno)); >+} >+ >+ /* >+ * This is the setup routine for the SSL server. As smtpd might be called >+ * more than once, we only want to do the initialization one time. >+ * >+ * The skeleton of this function is taken from OpenSSL apps/s_server.c. >+ */ >+ >+int pfixtls_init_serverengine(int verifydepth, int askcert) >+{ >+ int off = 0; >+ int verify_flags = SSL_VERIFY_NONE; >+ int rand_bytes; >+ int rand_source_dev_fd; >+ int rand_source_socket_fd; >+ unsigned char buffer[255]; >+ char *CApath; >+ char *CAfile; >+ char *s_cert_file; >+ char *s_key_file; >+ char *s_dcert_file; >+ char *s_dkey_file; >+ FILE *paramfile; >+ >+ if (pfixtls_serverengine) >+ return (0); /* already running */ >+ >+ if (var_smtpd_tls_loglevel >= 2) >+ msg_info("starting TLS engine"); >+ >+ /* >+ * Initialize the OpenSSL library by the book! >+ * To start with, we must initialize the algorithms. >+ * We want cleartext error messages instead of just error codes, so we >+ * load the error_strings. >+ */ >+ SSL_load_error_strings(); >+ OpenSSL_add_ssl_algorithms(); >+ >+ /* >+ * Side effect, call a non-existing function to disable TLS usage with an >+ * outdated OpenSSL version. There is a security reason (verify_result >+ * is not stored with the session data). >+ */ >+#if (OPENSSL_VERSION_NUMBER < 0x00905100L) >+ needs_openssl_095_or_later(); >+#endif >+ >+ /* >+ * Initialize the PRNG Pseudo Random Number Generator with some seed. >+ */ >+ randseed.pid = getpid(); >+ GETTIMEOFDAY(&randseed.tv); >+ RAND_seed(&randseed, sizeof(randseed_t)); >+ >+ /* >+ * Access the external sources for random seed. We will only query them >+ * once, this should be sufficient and we will stir our entropy by using >+ * the prng-exchange file anyway. >+ * For reliability, we don't consider failure to access the additional >+ * source fatal, as we can run happily without it (considering that we >+ * still have the exchange-file). We also don't care how much entropy >+ * we get back, as we must run anyway. We simply stir in the buffer >+ * regardless how many bytes are actually in it. >+ */ >+ if (*var_tls_daemon_rand_source) { >+ if (!strncmp(var_tls_daemon_rand_source, "dev:", 4)) { >+ /* >+ * Source is a random device >+ */ >+ rand_source_dev_fd = open(var_tls_daemon_rand_source + 4, 0, 0); >+ if (rand_source_dev_fd == -1) >+ msg_info("Could not open entropy device %s", >+ var_tls_daemon_rand_source); >+ else { >+ if (var_tls_daemon_rand_bytes > 255) >+ var_tls_daemon_rand_bytes = 255; >+ read(rand_source_dev_fd, buffer, var_tls_daemon_rand_bytes); >+ RAND_seed(buffer, var_tls_daemon_rand_bytes); >+ close(rand_source_dev_fd); >+ } >+ } else if (!strncmp(var_tls_daemon_rand_source, "egd:", 4)) { >+ /* >+ * Source is a EGD compatible socket >+ */ >+ rand_source_socket_fd = unix_connect(var_tls_daemon_rand_source +4, >+ BLOCKING, 10); >+ if (rand_source_socket_fd == -1) >+ msg_info("Could not connect to %s", var_tls_daemon_rand_source); >+ else { >+ if (var_tls_daemon_rand_bytes > 255) >+ var_tls_daemon_rand_bytes = 255; >+ buffer[0] = 1; >+ buffer[1] = var_tls_daemon_rand_bytes; >+ if (write(rand_source_socket_fd, buffer, 2) != 2) >+ msg_info("Could not talk to %s", >+ var_tls_daemon_rand_source); >+ else if (read(rand_source_socket_fd, buffer, 1) != 1) >+ msg_info("Could not read info from %s", >+ var_tls_daemon_rand_source); >+ else { >+ rand_bytes = buffer[0]; >+ read(rand_source_socket_fd, buffer, rand_bytes); >+ RAND_seed(buffer, rand_bytes); >+ } >+ close(rand_source_socket_fd); >+ } >+ } else { >+ RAND_load_file(var_tls_daemon_rand_source, >+ var_tls_daemon_rand_bytes); >+ } >+ } >+ >+ if (*var_tls_rand_exch_name) { >+ rand_exch_fd = open(var_tls_rand_exch_name, O_RDWR | O_CREAT, 0600); >+ if (rand_exch_fd != -1) >+ pfixtls_exchange_seed(); >+ } >+ >+ randseed.pid = getpid(); >+ GETTIMEOFDAY(&randseed.tv); >+ RAND_seed(&randseed, sizeof(randseed_t)); >+ >+ /* >+ * The SSL/TLS speficications require the client to send a message in >+ * the oldest specification it understands with the highest level it >+ * understands in the message. >+ * Netscape communicator can still communicate with SSLv2 servers, so it >+ * sends out a SSLv2 client hello. To deal with it, our server must be >+ * SSLv2 aware (even if we don't like SSLv2), so we need to have the >+ * SSLv23 server here. If we want to limit the protocol level, we can >+ * add an option to not use SSLv2/v3/TLSv1 later. >+ */ >+ ctx = SSL_CTX_new(SSLv23_server_method()); >+ if (ctx == NULL) { >+ pfixtls_print_errors(); >+ return (-1); >+ }; >+ >+ /* >+ * Here we might set SSL_OP_NO_SSLv2, SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1. >+ * Of course, the last one would not make sense, since RFC2487 is only >+ * defined for TLS, but we also want to accept Netscape communicator >+ * requests, and it only supports SSLv3. >+ */ >+ off |= SSL_OP_ALL; /* Work around all known bugs */ >+ SSL_CTX_set_options(ctx, off); >+ >+ /* >+ * Set the info_callback, that will print out messages during >+ * communication on demand. >+ */ >+ if (var_smtpd_tls_loglevel >= 2) >+ SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); >+ >+ /* >+ * Set the list of ciphers, if explicitely given; otherwise the >+ * (reasonable) default list is kept. >+ */ >+ if (strlen(var_smtpd_tls_cipherlist) != 0) >+ if (SSL_CTX_set_cipher_list(ctx, var_smtpd_tls_cipherlist) == 0) { >+ pfixtls_print_errors(); >+ return (-1); >+ } >+ >+ /* >+ * Now we must add the necessary certificate stuff: A server key, a >+ * server certificate, and the CA certificates for both the server >+ * cert and the verification of client certificates. >+ * As provided by OpenSSL we support two types of CA certificate handling: >+ * One possibility is to add all CA certificates to one large CAfile, >+ * the other possibility is a directory pointed to by CApath, containing >+ * seperate files for each CA pointed on by softlinks named by the hash >+ * values of the certificate. >+ * The first alternative has the advantage, that the file is opened and >+ * read at startup time, so that you don't have the hassle to maintain >+ * another copy of the CApath directory for chroot-jail. On the other >+ * hand, the file is not really readable. >+ */ >+ if (strlen(var_smtpd_tls_CAfile) == 0) >+ CAfile = NULL; >+ else >+ CAfile = var_smtpd_tls_CAfile; >+ if (strlen(var_smtpd_tls_CApath) == 0) >+ CApath = NULL; >+ else >+ CApath = var_smtpd_tls_CApath; >+ >+ if (CAfile || CApath) { >+ if (!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) { >+ msg_info("TLS engine: cannot load CA data"); >+ pfixtls_print_errors(); >+ return (-1); >+ } >+ if (!SSL_CTX_set_default_verify_paths(ctx)) { >+ msg_info("TLS engine: cannot set verify paths"); >+ pfixtls_print_errors(); >+ return (-1); >+ } >+ } >+ >+ /* >+ * Now we load the certificate and key from the files and check, >+ * whether the cert matches the key (internally done by set_cert_stuff(). >+ * We cannot run without (we do not support ADH anonymous Diffie-Hellman >+ * ciphers as of now). >+ * We can use RSA certificates ("cert") and DSA certificates ("dcert"), >+ * both can be made available at the same time. The CA certificates for >+ * both are handled in the same setup already finished. >+ * Which one is used depends on the cipher negotiated (that is: the first >+ * cipher listed by the client which does match the server). A client with >+ * RSA only (e.g. Netscape) will use the RSA certificate only. >+ * A client with openssl-library will use RSA first if not especially >+ * changed in the cipher setup. >+ */ >+ if (strlen(var_smtpd_tls_cert_file) == 0) >+ s_cert_file = NULL; >+ else >+ s_cert_file = var_smtpd_tls_cert_file; >+ if (strlen(var_smtpd_tls_key_file) == 0) >+ s_key_file = NULL; >+ else >+ s_key_file = var_smtpd_tls_key_file; >+ >+ if (strlen(var_smtpd_tls_dcert_file) == 0) >+ s_dcert_file = NULL; >+ else >+ s_dcert_file = var_smtpd_tls_dcert_file; >+ if (strlen(var_smtpd_tls_dkey_file) == 0) >+ s_dkey_file = NULL; >+ else >+ s_dkey_file = var_smtpd_tls_dkey_file; >+ >+ if (s_cert_file) { >+ if (!set_cert_stuff(ctx, s_cert_file, s_key_file)) { >+ msg_info("TLS engine: cannot load RSA cert/key data"); >+ pfixtls_print_errors(); >+ return (-1); >+ } >+ } >+ if (s_dcert_file) { >+ if (!set_cert_stuff(ctx, s_dcert_file, s_dkey_file)) { >+ msg_info("TLS engine: cannot load DSA cert/key data"); >+ pfixtls_print_errors(); >+ return (-1); >+ } >+ } >+ if (!s_cert_file && !s_dcert_file) { >+ msg_info("TLS engine: do need at least RSA _or_ DSA cert/key data"); >+ return (-1); >+ } >+ >+ /* >+ * Sometimes a temporary RSA key might be needed by the OpenSSL >+ * library. The OpenSSL doc indicates, that this might happen when >+ * export ciphers are in use. We have to provide one, so well, we >+ * just do it. >+ */ >+ SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb); >+ >+ /* >+ * We might also need dh parameters, which can either be loaded from >+ * file (preferred) or we simply take the compiled in values. >+ * First, set the callback that will select the values when requested, >+ * then load the (possibly) available DH parameters from files. >+ * We are generous with the error handling, since we do have default >+ * values compiled in, so we will not abort but just log the error message. >+ */ >+ SSL_CTX_set_tmp_dh_callback(ctx, tmp_dh_cb); >+ if (strlen(var_smtpd_tls_dh1024_param_file) != 0) { >+ if ((paramfile = fopen(var_smtpd_tls_dh1024_param_file, "r")) != NULL) { >+ dh_1024 = PEM_read_DHparams(paramfile, NULL, NULL, NULL); >+ if (dh_1024 == NULL) { >+ msg_info("TLS engine: cannot load 1024bit DH parameters"); >+ pfixtls_print_errors(); >+ } >+ } >+ else { >+ msg_info("TLS engine: cannot load 1024bit DH parameters: %s: %s", >+ var_smtpd_tls_dh1024_param_file, strerror(errno)); >+ } >+ } >+ if (strlen(var_smtpd_tls_dh512_param_file) != 0) { >+ if ((paramfile = fopen(var_smtpd_tls_dh512_param_file, "r")) != NULL) { >+ dh_512 = PEM_read_DHparams(paramfile, NULL, NULL, NULL); >+ if (dh_512 == NULL) { >+ msg_info("TLS engine: cannot load 512bit DH parameters"); >+ pfixtls_print_errors(); >+ } >+ } >+ else { >+ msg_info("TLS engine: cannot load 512bit DH parameters: %s: %s", >+ var_smtpd_tls_dh512_param_file, strerror(errno)); >+ } >+ } >+ >+ /* >+ * If we want to check client certificates, we have to indicate it >+ * in advance. By now we only allow to decide on a global basis. >+ * If we want to allow certificate based relaying, we must ask the >+ * client to provide one with SSL_VERIFY_PEER. The client now can >+ * decide, whether it provides one or not. We can enforce a failure >+ * of the negotiation with SSL_VERIFY_FAIL_IF_NO_PEER_CERT, if we >+ * do not allow a connection without one. >+ * In the "server hello" following the initialization by the "client hello" >+ * the server must provide a list of CAs it is willing to accept. >+ * Some clever clients will then select one from the list of available >+ * certificates matching these CAs. Netscape Communicator will present >+ * the list of certificates for selecting the one to be sent, or it will >+ * issue a warning, if there is no certificate matching the available >+ * CAs. >+ * >+ * With regard to the purpose of the certificate for relaying, we might >+ * like a later negotiation, maybe relaying would already be allowed >+ * for other reasons, but this would involve severe changes in the >+ * internal postfix logic, so we have to live with it the way it is. >+ */ >+ if (askcert) >+ verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; >+ SSL_CTX_set_verify(ctx, verify_flags, verify_callback); >+ SSL_CTX_set_client_CA_list(ctx, SSL_load_client_CA_file(CAfile)); >+ >+ /* >+ * Initialize the session cache. We only want external caching to >+ * synchronize between server sessions, so we set it to a minimum value >+ * of 1. If the external cache is disabled, we won't cache at all. >+ * The recall of old sessions "get" and save to disk of just created >+ * sessions "new" is handled by the appropriate callback functions. >+ * >+ * We must not forget to set a session id context to identify to which >+ * kind of server process the session was related. In our case, the >+ * context is just the name of the patchkit: "Postfix/TLS". >+ */ >+ SSL_CTX_sess_set_cache_size(ctx, 1); >+ SSL_CTX_set_timeout(ctx, var_smtpd_tls_scache_timeout); >+ SSL_CTX_set_session_id_context(ctx, (void*)&server_session_id_context, >+ sizeof(server_session_id_context)); >+ >+ /* >+ * The session cache is realized by an external database file, that >+ * must be opened before going to chroot jail. Since the session cache >+ * data can become quite large, "[n]dbm" cannot be used as it has a >+ * size limit that is by far to small. >+ */ >+ if (*var_smtpd_tls_scache_db) { >+ /* >+ * Insert a test against other dbms here, otherwise while writing >+ * a session (content to large), we will receive a fatal error! >+ */ >+ if (strncmp(var_smtpd_tls_scache_db, "sdbm:", 5)) >+ msg_warn("Only sdbm: type allowed for %s", >+ var_smtpd_tls_scache_db); >+ else >+ scache_db = dict_open(var_smtpd_tls_scache_db, O_RDWR, >+ DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE); >+ if (scache_db) { >+ SSL_CTX_set_session_cache_mode(ctx, >+ SSL_SESS_CACHE_SERVER|SSL_SESS_CACHE_NO_AUTO_CLEAR); >+ SSL_CTX_sess_set_get_cb(ctx, get_session_cb); >+ SSL_CTX_sess_set_new_cb(ctx, new_session_cb); >+ SSL_CTX_sess_set_remove_cb(ctx, remove_session_cb); >+ } >+ else >+ msg_warn("Could not open session cache %s", >+ var_smtpd_tls_scache_db); >+ } >+ >+ /* >+ * Finally create the global index to access TLScontext information >+ * inside verify_callback. >+ */ >+ TLScontext_index = SSL_get_ex_new_index(0, "TLScontext ex_data index", >+ NULL, NULL, NULL); >+ >+ pfixtls_serverengine = 1; >+ return (0); >+} >+ >+ /* >+ * This is the actual startup routine for the connection. We expect >+ * that the buffers are flushed and the "220 Ready to start TLS" was >+ * send to the client, so that we can immediately can start the TLS >+ * handshake process. >+ */ >+int pfixtls_start_servertls(VSTREAM *stream, int timeout, >+ const char *peername, const char *peeraddr, >+ tls_info_t *tls_info, int requirecert) >+{ >+ int sts; >+ int j; >+ int verify_flags; >+ unsigned int n; >+ TLScontext_t *TLScontext; >+ SSL_SESSION *session; >+ SSL_CIPHER *cipher; >+ X509 *peer; >+ >+ if (!pfixtls_serverengine) { /* should never happen */ >+ msg_info("tls_engine not running"); >+ return (-1); >+ } >+ if (var_smtpd_tls_loglevel >= 1) >+ msg_info("setting up TLS connection from %s[%s]", peername, peeraddr); >+ >+ /* >+ * Allocate a new TLScontext for the new connection and get an SSL >+ * structure. Add the location of TLScontext to the SSL to later >+ * retrieve the information inside the verify_callback(). >+ */ >+ TLScontext = (TLScontext_t *)mymalloc(sizeof(TLScontext_t)); >+ if (!TLScontext) { >+ msg_fatal("Could not allocate 'TLScontext' with mymalloc"); >+ } >+ if ((TLScontext->con = (SSL *) SSL_new(ctx)) == NULL) { >+ msg_info("Could not allocate 'TLScontext->con' with SSL_new()"); >+ pfixtls_print_errors(); >+ myfree((char *)TLScontext); >+ return (-1); >+ } >+ if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { >+ msg_info("Could not set application data for 'TLScontext->con'"); >+ pfixtls_print_errors(); >+ SSL_free(TLScontext->con); >+ myfree((char *)TLScontext); >+ return (-1); >+ } >+ >+ /* >+ * Set the verification parameters to be checked in verify_callback(). >+ */ >+ if (requirecert) { >+ verify_flags = SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE; >+ verify_flags |= SSL_VERIFY_FAIL_IF_NO_PEER_CERT; >+ TLScontext->enforce_verify_errors = 1; >+ SSL_set_verify(TLScontext->con, verify_flags, verify_callback); >+ } >+ else { >+ TLScontext->enforce_verify_errors = 0; >+ } >+ TLScontext->enforce_CN = 0; >+ >+ /* >+ * The TLS connection is realized by a BIO_pair, so obtain the pair. >+ */ >+ if (!BIO_new_bio_pair(&TLScontext->internal_bio, BIO_bufsiz, >+ &TLScontext->network_bio, BIO_bufsiz)) { >+ msg_info("Could not obtain BIO_pair"); >+ pfixtls_print_errors(); >+ SSL_free(TLScontext->con); >+ myfree((char *)TLScontext); >+ return (-1); >+ } >+ >+ /* >+ * Before really starting anything, try to seed the PRNG a little bit >+ * more. >+ */ >+ pfixtls_stir_seed(); >+ pfixtls_exchange_seed(); >+ >+ /* >+ * Initialize the SSL connection to accept state. This should not be >+ * necessary anymore since 0.9.3, but the call is still in the library >+ * and maintaining compatibility never hurts. >+ */ >+ SSL_set_accept_state(TLScontext->con); >+ >+ /* >+ * Connect the SSL-connection with the postfix side of the BIO-pair for >+ * reading and writing. >+ */ >+ SSL_set_bio(TLScontext->con, TLScontext->internal_bio, >+ TLScontext->internal_bio); >+ >+ /* >+ * If the debug level selected is high enough, all of the data is >+ * dumped: 3 will dump the SSL negotiation, 4 will dump everything. >+ * >+ * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? >+ * Well there is a BIO below the SSL routines that is automatically >+ * created for us, so we can use it for debugging purposes. >+ */ >+ if (var_smtpd_tls_loglevel >= 3) >+ BIO_set_callback(SSL_get_rbio(TLScontext->con), bio_dump_cb); >+ >+ >+ /* Dump the negotiation for loglevels 3 and 4 */ >+ if (var_smtpd_tls_loglevel >= 3) >+ do_dump = 1; >+ >+ /* >+ * Now we expect the negotiation to begin. This whole process is like a >+ * black box for us. We totally have to rely on the routines build into >+ * the OpenSSL library. The only thing we can do we already have done >+ * by choosing our own callbacks for session caching and certificate >+ * verification. >+ * >+ * Error handling: >+ * If the SSL handhake fails, we print out an error message and remove >+ * everything that might be there. A session has to be removed anyway, >+ * because RFC2246 requires it. >+ */ >+ sts = do_tls_operation(vstream_fileno(stream), timeout, TLScontext, >+ SSL_accept, NULL, NULL, NULL, 0); >+ if (sts <= 0) { >+ msg_info("SSL_accept error from %s[%s]: %d", peername, peeraddr, sts); >+ pfixtls_print_errors(); >+ SSL_free(TLScontext->con); >+ myfree((char *)TLScontext); >+ return (-1); >+ } >+ >+ /* Only loglevel==4 dumps everything */ >+ if (var_smtpd_tls_loglevel < 4) >+ do_dump = 0; >+ >+ /* >+ * Lets see, whether a peer certificate is available and what is >+ * the actual information. We want to save it for later use. >+ */ >+ peer = SSL_get_peer_certificate(TLScontext->con); >+ if (peer != NULL) { >+ if (SSL_get_verify_result(TLScontext->con) == X509_V_OK) >+ tls_info->peer_verified = 1; >+ >+ X509_NAME_oneline(X509_get_subject_name(peer), >+ TLScontext->peer_subject, CCERT_BUFSIZ); >+ if (var_smtpd_tls_loglevel >= 2) >+ msg_info("subject=%s", TLScontext->peer_subject); >+ tls_info->peer_subject = TLScontext->peer_subject; >+ X509_NAME_oneline(X509_get_issuer_name(peer), >+ TLScontext->peer_issuer, CCERT_BUFSIZ); >+ if (var_smtpd_tls_loglevel >= 2) >+ msg_info("issuer=%s", TLScontext->peer_issuer); >+ tls_info->peer_issuer = TLScontext->peer_issuer; >+ if (X509_digest(peer, EVP_md5(), TLScontext->md, &n)) { >+ for (j = 0; j < (int) n; j++) { >+ TLScontext->fingerprint[j * 3] = >+ hexcodes[(TLScontext->md[j] & 0xf0) >> 4]; >+ TLScontext->fingerprint[(j * 3) + 1] = >+ hexcodes[(TLScontext->md[j] & 0x0f)]; >+ if (j + 1 != (int) n) >+ TLScontext->fingerprint[(j * 3) + 2] = ':'; >+ else >+ TLScontext->fingerprint[(j * 3) + 2] = '\0'; >+ } >+ if (var_smtpd_tls_loglevel >= 1) >+ msg_info("fingerprint=%s", TLScontext->fingerprint); >+ tls_info->peer_fingerprint = TLScontext->fingerprint; >+ } >+ >+ TLScontext->peer_CN[0] = '\0'; >+ if (!X509_NAME_get_text_by_NID(X509_get_subject_name(peer), >+ NID_commonName, TLScontext->peer_CN, CCERT_BUFSIZ)) { >+ msg_info("Could not parse client's subject CN"); >+ pfixtls_print_errors(); >+ } >+ tls_info->peer_CN = TLScontext->peer_CN; >+ >+ TLScontext->issuer_CN[0] = '\0'; >+ if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer), >+ NID_commonName, TLScontext->issuer_CN, CCERT_BUFSIZ)) { >+ msg_info("Could not parse client's issuer CN"); >+ pfixtls_print_errors(); >+ } >+ if (!TLScontext->issuer_CN[0]) { >+ /* No issuer CN field, use Organization instead */ >+ if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer), >+ NID_organizationName, TLScontext->issuer_CN, CCERT_BUFSIZ)) { >+ msg_info("Could not parse client's issuer Organization"); >+ pfixtls_print_errors(); >+ } >+ } >+ tls_info->issuer_CN = TLScontext->issuer_CN; >+ >+ if (var_smtpd_tls_loglevel >= 1) { >+ if (tls_info->peer_verified) >+ msg_info("Verified: subject_CN=%s, issuer=%s", >+ TLScontext->peer_CN, TLScontext->issuer_CN); >+ else >+ msg_info("Unverified: subject_CN=%s, issuer=%s", >+ TLScontext->peer_CN, TLScontext->issuer_CN); >+ } >+ >+ X509_free(peer); >+ } >+ >+ /* >+ * At this point we should have a certificate when required. >+ * We may however have a cached session, so the callback would never >+ * be called. We therefore double-check to make sure and remove the >+ * session, if applicable. >+ */ >+ if (requirecert) { >+ if (!tls_info->peer_verified || !tls_info->peer_CN) { >+ msg_info("Re-used session without peer certificate removed"); >+ session = SSL_get_session(TLScontext->con); >+ SSL_CTX_remove_session(ctx, session); >+ return (-1); >+ } >+ } >+ >+ /* >+ * Finally, collect information about protocol and cipher for logging >+ */ >+ tls_info->protocol = SSL_get_version(TLScontext->con); >+ cipher = SSL_get_current_cipher(TLScontext->con); >+ tls_info->cipher_name = SSL_CIPHER_get_name(cipher); >+ tls_info->cipher_usebits = SSL_CIPHER_get_bits(cipher, >+ &(tls_info->cipher_algbits)); >+ >+ pfixtls_serveractive = 1; >+ >+ /* >+ * The TLS engine is active, switch to the pfixtls_timed_read/write() >+ * functions and store the context. >+ */ >+ vstream_control(stream, >+ VSTREAM_CTL_READ_FN, pfixtls_timed_read, >+ VSTREAM_CTL_WRITE_FN, pfixtls_timed_write, >+ VSTREAM_CTL_CONTEXT, (void *)TLScontext, >+ VSTREAM_CTL_END); >+ >+ msg_info("TLS connection established from %s[%s]: %s with cipher %s (%d/%d bits)", >+ peername, peeraddr, >+ tls_info->protocol, tls_info->cipher_name, >+ tls_info->cipher_usebits, tls_info->cipher_algbits); >+ pfixtls_stir_seed(); >+ >+ return (0); >+} >+ >+ /* >+ * Shut down the TLS connection, that does mean: remove all the information >+ * and reset the flags! This is needed if the actual running smtpd is to >+ * be restarted. We do not give back any value, as there is nothing to >+ * be reported. >+ * Since our session cache is external, we will remove the session from >+ * memory in any case. The SSL_CTX_flush_sessions might be redundant here, >+ * I however want to make sure nothing is left. >+ * RFC2246 requires us to remove sessions if something went wrong, as >+ * indicated by the "failure" value, so we remove it from the external >+ * cache, too. >+ */ >+int pfixtls_stop_servertls(VSTREAM *stream, int timeout, int failure, >+ tls_info_t *tls_info) >+{ >+ TLScontext_t *TLScontext; >+ int retval; >+ >+ if (pfixtls_serveractive) { >+ TLScontext = (TLScontext_t *)vstream_context(stream); >+ /* >+ * Perform SSL_shutdown() twice, as the first attempt may return >+ * to early: it will only send out the shutdown alert but it will >+ * not wait for the peer's shutdown alert. Therefore, when we are >+ * the first party to send the alert, we must call SSL_shutdown() >+ * again. >+ * On failure we don't want to resume the session, so we will not >+ * perform SSL_shutdown() and the session will be removed as being >+ * bad. >+ */ >+ if (!failure) { >+ retval = do_tls_operation(vstream_fileno(stream), timeout, >+ TLScontext, SSL_shutdown, NULL, NULL, NULL, 0); >+ if (retval == 0) >+ do_tls_operation(vstream_fileno(stream), timeout, TLScontext, >+ SSL_shutdown, NULL, NULL, NULL, 0); >+ } >+ /* >+ * Free the SSL structure and the BIOs. Warning: the internal_bio is >+ * connected to the SSL structure and is automatically freed with >+ * it. Do not free it again (core dump)!! >+ * Only free the network_bio. >+ */ >+ SSL_free(TLScontext->con); >+ BIO_free(TLScontext->network_bio); >+ myfree((char *)TLScontext); >+ vstream_control(stream, >+ VSTREAM_CTL_READ_FN, (VSTREAM_FN) NULL, >+ VSTREAM_CTL_WRITE_FN, (VSTREAM_FN) NULL, >+ VSTREAM_CTL_CONTEXT, (void *) NULL, >+ VSTREAM_CTL_END); >+ SSL_CTX_flush_sessions(ctx, time(NULL)); >+ >+ pfixtls_stir_seed(); >+ pfixtls_exchange_seed(); >+ >+ *tls_info = tls_info_zero; >+ pfixtls_serveractive = 0; >+ >+ } >+ >+ return (0); >+} >+ >+ >+ /* >+ * This is the setup routine for the SSL client. As smtpd might be called >+ * more than once, we only want to do the initialization one time. >+ * >+ * The skeleton of this function is taken from OpenSSL apps/s_client.c. >+ */ >+ >+int pfixtls_init_clientengine(int verifydepth) >+{ >+ int off = 0; >+ int verify_flags = SSL_VERIFY_NONE; >+ int rand_bytes; >+ int rand_source_dev_fd; >+ int rand_source_socket_fd; >+ unsigned char buffer[255]; >+ char *CApath; >+ char *CAfile; >+ char *c_cert_file; >+ char *c_key_file; >+ >+ >+ if (pfixtls_clientengine) >+ return (0); /* already running */ >+ >+ if (var_smtp_tls_loglevel >= 2) >+ msg_info("starting TLS engine"); >+ >+ /* >+ * Initialize the OpenSSL library by the book! >+ * To start with, we must initialize the algorithms. >+ * We want cleartext error messages instead of just error codes, so we >+ * load the error_strings. >+ */ >+ SSL_load_error_strings(); >+ OpenSSL_add_ssl_algorithms(); >+ >+ /* >+ * Side effect, call a non-existing function to disable TLS usage with an >+ * outdated OpenSSL version. There is a security reason (verify_result >+ * is not stored with the session data). >+ */ >+#if (OPENSSL_VERSION_NUMBER < 0x00905100L) >+ needs_openssl_095_or_later(); >+#endif >+ >+ /* >+ * Initialize the PRNG Pseudo Random Number Generator with some seed. >+ */ >+ randseed.pid = getpid(); >+ GETTIMEOFDAY(&randseed.tv); >+ RAND_seed(&randseed, sizeof(randseed_t)); >+ >+ /* >+ * Access the external sources for random seed. We will only query them >+ * once, this should be sufficient and we will stir our entropy by using >+ * the prng-exchange file anyway. >+ * For reliability, we don't consider failure to access the additional >+ * source fatal, as we can run happily without it (considering that we >+ * still have the exchange-file). We also don't care how much entropy >+ * we get back, as we must run anyway. We simply stir in the buffer >+ * regardless how many bytes are actually in it. >+ */ >+ if (*var_tls_daemon_rand_source) { >+ if (!strncmp(var_tls_daemon_rand_source, "dev:", 4)) { >+ /* >+ * Source is a random device >+ */ >+ rand_source_dev_fd = open(var_tls_daemon_rand_source + 4, 0, 0); >+ if (rand_source_dev_fd == -1) >+ msg_info("Could not open entropy device %s", >+ var_tls_daemon_rand_source); >+ else { >+ if (var_tls_daemon_rand_bytes > 255) >+ var_tls_daemon_rand_bytes = 255; >+ read(rand_source_dev_fd, buffer, var_tls_daemon_rand_bytes); >+ RAND_seed(buffer, var_tls_daemon_rand_bytes); >+ close(rand_source_dev_fd); >+ } >+ } else if (!strncmp(var_tls_daemon_rand_source, "egd:", 4)) { >+ /* >+ * Source is a EGD compatible socket >+ */ >+ rand_source_socket_fd = unix_connect(var_tls_daemon_rand_source +4, >+ BLOCKING, 10); >+ if (rand_source_socket_fd == -1) >+ msg_info("Could not connect to %s", var_tls_daemon_rand_source); >+ else { >+ if (var_tls_daemon_rand_bytes > 255) >+ var_tls_daemon_rand_bytes = 255; >+ buffer[0] = 1; >+ buffer[1] = var_tls_daemon_rand_bytes; >+ if (write(rand_source_socket_fd, buffer, 2) != 2) >+ msg_info("Could not talk to %s", >+ var_tls_daemon_rand_source); >+ else if (read(rand_source_socket_fd, buffer, 1) != 1) >+ msg_info("Could not read info from %s", >+ var_tls_daemon_rand_source); >+ else { >+ rand_bytes = buffer[0]; >+ read(rand_source_socket_fd, buffer, rand_bytes); >+ RAND_seed(buffer, rand_bytes); >+ } >+ close(rand_source_socket_fd); >+ } >+ } else { >+ RAND_load_file(var_tls_daemon_rand_source, >+ var_tls_daemon_rand_bytes); >+ } >+ } >+ >+ if (*var_tls_rand_exch_name) { >+ rand_exch_fd = open(var_tls_rand_exch_name, O_RDWR | O_CREAT, 0600); >+ if (rand_exch_fd != -1) >+ pfixtls_exchange_seed(); >+ } >+ >+ randseed.pid = getpid(); >+ GETTIMEOFDAY(&randseed.tv); >+ RAND_seed(&randseed, sizeof(randseed_t)); >+ >+ /* >+ * The SSL/TLS speficications require the client to send a message in >+ * the oldest specification it understands with the highest level it >+ * understands in the message. >+ * RFC2487 is only specified for TLSv1, but we want to be as compatible >+ * as possible, so we will start off with a SSLv2 greeting allowing >+ * the best we can offer: TLSv1. >+ * We can restrict this with the options setting later, anyhow. >+ */ >+ ctx = SSL_CTX_new(SSLv23_client_method()); >+ if (ctx == NULL) { >+ pfixtls_print_errors(); >+ return (-1); >+ }; >+ >+ /* >+ * Here we might set SSL_OP_NO_SSLv2, SSL_OP_NO_SSLv3, SSL_OP_NO_TLSv1. >+ * Of course, the last one would not make sense, since RFC2487 is only >+ * defined for TLS, but we don't know what is out there. So leave things >+ * completely open, as of today. >+ */ >+ off |= SSL_OP_ALL; /* Work around all known bugs */ >+ SSL_CTX_set_options(ctx, off); >+ >+ /* >+ * Set the info_callback, that will print out messages during >+ * communication on demand. >+ */ >+ if (var_smtp_tls_loglevel >= 2) >+ SSL_CTX_set_info_callback(ctx, apps_ssl_info_callback); >+ >+ /* >+ * Set the list of ciphers, if explicitely given; otherwise the >+ * (reasonable) default list is kept. >+ */ >+ if (strlen(var_smtp_tls_cipherlist) != 0) >+ if (SSL_CTX_set_cipher_list(ctx, var_smtp_tls_cipherlist) == 0) { >+ pfixtls_print_errors(); >+ return (-1); >+ } >+ >+ /* >+ * Now we must add the necessary certificate stuff: A client key, a >+ * client certificate, and the CA certificates for both the client >+ * cert and the verification of server certificates. >+ * In fact, we do not need a client certificate, so the certificates >+ * are only loaded (and checked), if supplied. A clever client would >+ * handle multiple client certificates and decide based on the list >+ * of acceptable CAs, sent by the server, which certificate to submit. >+ * OpenSSL does however not do this and also has no callback hoods to >+ * easily realize it. >+ * >+ * As provided by OpenSSL we support two types of CA certificate handling: >+ * One possibility is to add all CA certificates to one large CAfile, >+ * the other possibility is a directory pointed to by CApath, containing >+ * seperate files for each CA pointed on by softlinks named by the hash >+ * values of the certificate. >+ * The first alternative has the advantage, that the file is opened and >+ * read at startup time, so that you don't have the hassle to maintain >+ * another copy of the CApath directory for chroot-jail. On the other >+ * hand, the file is not really readable. >+ */ >+ if (strlen(var_smtp_tls_CAfile) == 0) >+ CAfile = NULL; >+ else >+ CAfile = var_smtp_tls_CAfile; >+ if (strlen(var_smtp_tls_CApath) == 0) >+ CApath = NULL; >+ else >+ CApath = var_smtp_tls_CApath; >+ if (CAfile || CApath) { >+ if (!SSL_CTX_load_verify_locations(ctx, CAfile, CApath)) { >+ msg_info("TLS engine: cannot load CA data"); >+ pfixtls_print_errors(); >+ return (-1); >+ } >+ if (!SSL_CTX_set_default_verify_paths(ctx)) { >+ msg_info("TLS engine: cannot set verify paths"); >+ pfixtls_print_errors(); >+ return (-1); >+ } >+ } >+ >+ if (strlen(var_smtp_tls_cert_file) == 0) >+ c_cert_file = NULL; >+ else >+ c_cert_file = var_smtp_tls_cert_file; >+ if (strlen(var_smtp_tls_key_file) == 0) >+ c_key_file = NULL; >+ else >+ c_key_file = var_smtp_tls_key_file; >+ if (c_cert_file || c_key_file) >+ if (!set_cert_stuff(ctx, c_cert_file, c_key_file)) { >+ msg_info("TLS engine: cannot load cert/key data"); >+ pfixtls_print_errors(); >+ return (-1); >+ } >+ >+ /* >+ * Sometimes a temporary RSA key might be needed by the OpenSSL >+ * library. The OpenSSL doc indicates, that this might happen when >+ * export ciphers are in use. We have to provide one, so well, we >+ * just do it. >+ */ >+ SSL_CTX_set_tmp_rsa_callback(ctx, tmp_rsa_cb); >+ >+ /* >+ * Finally, the setup for the server certificate checking, done >+ * "by the book". >+ */ >+ SSL_CTX_set_verify(ctx, verify_flags, verify_callback); >+ >+ /* >+ * Initialize the session cache. We only want external caching to >+ * synchronize between server sessions, so we set it to a minimum value >+ * of 1. If the external cache is disabled, we won't cache at all. >+ * >+ * In case of the client, there is no callback used in OpenSSL, so >+ * we must call the session cache functions manually during the process. >+ */ >+ SSL_CTX_sess_set_cache_size(ctx, 1); >+ SSL_CTX_set_timeout(ctx, var_smtp_tls_scache_timeout); >+ >+ /* >+ * The session cache is realized by an external database file, that >+ * must be opened before going to chroot jail. Since the session cache >+ * data can become quite large, "[n]dbm" cannot be used as it has a >+ * size limit that is by far to small. >+ */ >+ if (*var_smtp_tls_scache_db) { >+ /* >+ * Insert a test against other dbms here, otherwise while writing >+ * a session (content to large), we will receive a fatal error! >+ */ >+ if (strncmp(var_smtp_tls_scache_db, "sdbm:", 5)) >+ msg_warn("Only sdbm: type allowed for %s", >+ var_smtp_tls_scache_db); >+ else >+ scache_db = dict_open(var_smtp_tls_scache_db, O_RDWR, >+ DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE); >+ if (!scache_db) >+ msg_warn("Could not open session cache %s", >+ var_smtp_tls_scache_db); >+ /* >+ * It is practical to have OpenSSL automatically save newly created >+ * sessions for us by callback. Therefore we have to enable the >+ * internal session cache for the client side. Disable automatic >+ * clearing, as smtp has limited lifetime anyway and we can call >+ * the cleanup routine at will. >+ */ >+ SSL_CTX_set_session_cache_mode(ctx, >+ SSL_SESS_CACHE_CLIENT|SSL_SESS_CACHE_NO_AUTO_CLEAR); >+ SSL_CTX_sess_set_new_cb(ctx, new_session_cb); >+ } >+ >+ /* >+ * Finally create the global index to access TLScontext information >+ * inside verify_callback. >+ */ >+ TLScontext_index = SSL_get_ex_new_index(0, "TLScontext ex_data index", >+ NULL, NULL, NULL); >+ TLSpeername_index = SSL_SESSION_get_ex_new_index(0, >+ "TLSpeername ex_data index", >+ new_peername_func, >+ dup_peername_func, >+ free_peername_func); >+ >+ pfixtls_clientengine = 1; >+ return (0); >+} >+ >+ /* >+ * This is the actual startup routine for the connection. We expect >+ * that the buffers are flushed and the "220 Ready to start TLS" was >+ * received by us, so that we can immediately can start the TLS >+ * handshake process. >+ */ >+int pfixtls_start_clienttls(VSTREAM *stream, int timeout, >+ int enforce_peername, >+ const char *peername, >+ tls_info_t *tls_info) >+{ >+ int sts; >+ SSL_SESSION *session, *old_session; >+ SSL_CIPHER *cipher; >+ X509 *peer; >+ int verify_flags; >+ TLScontext_t *TLScontext; >+ >+ if (!pfixtls_clientengine) { /* should never happen */ >+ msg_info("tls_engine not running"); >+ return (-1); >+ } >+ if (var_smtpd_tls_loglevel >= 1) >+ msg_info("setting up TLS connection to %s", peername); >+ >+ /* >+ * Allocate a new TLScontext for the new connection and get an SSL >+ * structure. Add the location of TLScontext to the SSL to later >+ * retrieve the information inside the verify_callback(). >+ */ >+ TLScontext = (TLScontext_t *)mymalloc(sizeof(TLScontext_t)); >+ if (!TLScontext) { >+ msg_fatal("Could not allocate 'TLScontext' with mymalloc"); >+ } >+ if ((TLScontext->con = (SSL *) SSL_new(ctx)) == NULL) { >+ msg_info("Could not allocate 'TLScontext->con' with SSL_new()"); >+ pfixtls_print_errors(); >+ myfree((char *)TLScontext); >+ return (-1); >+ } >+ if (!SSL_set_ex_data(TLScontext->con, TLScontext_index, TLScontext)) { >+ msg_info("Could not set application data for 'TLScontext->con'"); >+ pfixtls_print_errors(); >+ SSL_free(TLScontext->con); >+ myfree((char *)TLScontext); >+ return (-1); >+ } >+ >+ /* >+ * Set the verification parameters to be checked in verify_callback(). >+ */ >+ if (enforce_peername) { >+ verify_flags = SSL_VERIFY_PEER; >+ TLScontext->enforce_verify_errors = 1; >+ TLScontext->enforce_CN = 1; >+ SSL_set_verify(TLScontext->con, verify_flags, verify_callback); >+ } >+ else { >+ TLScontext->enforce_verify_errors = 0; >+ TLScontext->enforce_CN = 0; >+ } >+ >+ /* >+ * The TLS connection is realized by a BIO_pair, so obtain the pair. >+ */ >+ if (!BIO_new_bio_pair(&TLScontext->internal_bio, BIO_bufsiz, >+ &TLScontext->network_bio, BIO_bufsiz)) { >+ msg_info("Could not obtain BIO_pair"); >+ pfixtls_print_errors(); >+ SSL_free(TLScontext->con); >+ myfree((char *)TLScontext); >+ return (-1); >+ } >+ >+ old_session = NULL; >+ >+ /* >+ * Find out the hashed HostID for the client cache and try to >+ * load the session from the cache. >+ */ >+ strncpy(TLScontext->peername_save, peername, ID_MAXLENGTH + 1); >+ TLScontext->peername_save[ID_MAXLENGTH] = '\0'; /* just in case */ >+ (void)lowercase(TLScontext->peername_save); >+ if (scache_db) { >+ old_session = load_clnt_session(peername, enforce_peername); >+ if (old_session) { >+ SSL_set_session(TLScontext->con, old_session); >+#if (OPENSSL_VERSION_NUMBER < 0x00906011L) || (OPENSSL_VERSION_NUMBER == 0x00907000L) >+ /* >+ * Ugly Hack: OpenSSL before 0.9.6a does not store the verify >+ * result in sessions for the client side. >+ * We modify the session directly which is version specific, >+ * but this bug is version specific, too. >+ * >+ * READ: 0-09-06-01-1 = 0-9-6-a-beta1: all versions before >+ * beta1 have this bug, it has been fixed during development >+ * of 0.9.6a. The development version of 0.9.7 can have this >+ * bug, too. It has been fixed on 2000/11/29. >+ */ >+ SSL_set_verify_result(TLScontext->con, old_session->verify_result); >+#endif >+ >+ } >+ } >+ >+ /* >+ * Before really starting anything, try to seed the PRNG a little bit >+ * more. >+ */ >+ pfixtls_stir_seed(); >+ pfixtls_exchange_seed(); >+ >+ /* >+ * Initialize the SSL connection to connect state. This should not be >+ * necessary anymore since 0.9.3, but the call is still in the library >+ * and maintaining compatibility never hurts. >+ */ >+ SSL_set_connect_state(TLScontext->con); >+ >+ /* >+ * Connect the SSL-connection with the postfix side of the BIO-pair for >+ * reading and writing. >+ */ >+ SSL_set_bio(TLScontext->con, TLScontext->internal_bio, >+ TLScontext->internal_bio); >+ >+ /* >+ * If the debug level selected is high enough, all of the data is >+ * dumped: 3 will dump the SSL negotiation, 4 will dump everything. >+ * >+ * We do have an SSL_set_fd() and now suddenly a BIO_ routine is called? >+ * Well there is a BIO below the SSL routines that is automatically >+ * created for us, so we can use it for debugging purposes. >+ */ >+ if (var_smtp_tls_loglevel >= 3) >+ BIO_set_callback(SSL_get_rbio(TLScontext->con), bio_dump_cb); >+ >+ >+ /* Dump the negotiation for loglevels 3 and 4 */ >+ if (var_smtp_tls_loglevel >= 3) >+ do_dump = 1; >+ >+ /* >+ * Now we expect the negotiation to begin. This whole process is like a >+ * black box for us. We totally have to rely on the routines build into >+ * the OpenSSL library. The only thing we can do we already have done >+ * by choosing our own callback certificate verification. >+ * >+ * Error handling: >+ * If the SSL handhake fails, we print out an error message and remove >+ * everything that might be there. A session has to be removed anyway, >+ * because RFC2246 requires it. >+ */ >+ sts = do_tls_operation(vstream_fileno(stream), timeout, TLScontext, >+ SSL_connect, NULL, NULL, NULL, 0); >+ if (sts <= 0) { >+ msg_info("SSL_connect error to %s: %d", peername, sts); >+ pfixtls_print_errors(); >+ session = SSL_get_session(TLScontext->con); >+ if (session) { >+ SSL_CTX_remove_session(ctx, session); >+ if (var_smtp_tls_loglevel >= 2) >+ msg_info("SSL session removed"); >+ } >+ if ((old_session) && (!SSL_session_reused(TLScontext->con))) >+ SSL_SESSION_free(old_session); /* Must also be removed */ >+ SSL_free(TLScontext->con); >+ myfree((char *)TLScontext); >+ return (-1); >+ } >+ >+ if (!SSL_session_reused(TLScontext->con)) { >+ SSL_SESSION_free(old_session); /* Remove unused session */ >+ } >+ else if (var_smtp_tls_loglevel >= 3) >+ msg_info("Reusing old session"); >+ >+ /* Only loglevel==4 dumps everything */ >+ if (var_smtp_tls_loglevel < 4) >+ do_dump = 0; >+ >+ /* >+ * Lets see, whether a peer certificate is available and what is >+ * the actual information. We want to save it for later use. >+ */ >+ peer = SSL_get_peer_certificate(TLScontext->con); >+ if (peer != NULL) { >+ if (SSL_get_verify_result(TLScontext->con) == X509_V_OK) >+ tls_info->peer_verified = 1; >+ >+ TLScontext->peer_CN[0] = '\0'; >+ if (!X509_NAME_get_text_by_NID(X509_get_subject_name(peer), >+ NID_commonName, TLScontext->peer_CN, CCERT_BUFSIZ)) { >+ msg_info("Could not parse server's subject CN"); >+ pfixtls_print_errors(); >+ } >+ tls_info->peer_CN = TLScontext->peer_CN; >+ >+ TLScontext->issuer_CN[0] = '\0'; >+ if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer), >+ NID_commonName, TLScontext->issuer_CN, CCERT_BUFSIZ)) { >+ msg_info("Could not parse server's issuer CN"); >+ pfixtls_print_errors(); >+ } >+ if (!TLScontext->issuer_CN[0]) { >+ /* No issuer CN field, use Organization instead */ >+ if (!X509_NAME_get_text_by_NID(X509_get_issuer_name(peer), >+ NID_organizationName, TLScontext->issuer_CN, CCERT_BUFSIZ)) { >+ msg_info("Could not parse server's issuer Organization"); >+ pfixtls_print_errors(); >+ } >+ } >+ tls_info->issuer_CN = TLScontext->issuer_CN; >+ >+ if (var_smtp_tls_loglevel >= 1) { >+ if (tls_info->peer_verified) >+ msg_info("Verified: subject_CN=%s, issuer=%s", >+ TLScontext->peer_CN, TLScontext->issuer_CN); >+ else >+ msg_info("Unverified: subject_CN=%s, issuer=%s", >+ TLScontext->peer_CN, TLScontext->issuer_CN); >+ } >+ X509_free(peer); >+ } >+ >+ /* >+ * Finally, collect information about protocol and cipher for logging >+ */ >+ tls_info->protocol = SSL_get_version(TLScontext->con); >+ cipher = SSL_get_current_cipher(TLScontext->con); >+ tls_info->cipher_name = SSL_CIPHER_get_name(cipher); >+ tls_info->cipher_usebits = SSL_CIPHER_get_bits(cipher, >+ &(tls_info->cipher_algbits)); >+ >+ pfixtls_clientactive = 1; >+ >+ /* >+ * The TLS engine is active, switch to the pfixtls_timed_read/write() >+ * functions. >+ */ >+ vstream_control(stream, >+ VSTREAM_CTL_READ_FN, pfixtls_timed_read, >+ VSTREAM_CTL_WRITE_FN, pfixtls_timed_write, >+ VSTREAM_CTL_CONTEXT, (void *)TLScontext, >+ VSTREAM_CTL_END); >+ >+ msg_info("TLS connection established to %s: %s with cipher %s (%d/%d bits)", >+ peername, >+ tls_info->protocol, tls_info->cipher_name, >+ tls_info->cipher_usebits, tls_info->cipher_algbits); >+ >+ pfixtls_stir_seed(); >+ >+ return (0); >+} >+ >+ /* >+ * Shut down the TLS connection, that does mean: remove all the information >+ * and reset the flags! This is needed if the actual running smtp is to >+ * be restarted. We do not give back any value, as there is nothing to >+ * be reported. >+ * Since our session cache is external, we will remove the session from >+ * memory in any case. The SSL_CTX_flush_sessions might be redundant here, >+ * I however want to make sure nothing is left. >+ * RFC2246 requires us to remove sessions if something went wrong, as >+ * indicated by the "failure" value,so we remove it from the external >+ * cache, too. >+ */ >+int pfixtls_stop_clienttls(VSTREAM *stream, int timeout, int failure, >+ tls_info_t *tls_info) >+{ >+ TLScontext_t *TLScontext; >+ int retval; >+ >+ if (pfixtls_clientactive) { >+ TLScontext = (TLScontext_t *)vstream_context(stream); >+ /* >+ * Perform SSL_shutdown() twice, as the first attempt may return >+ * to early: it will only send out the shutdown alert but it will >+ * not wait for the peer's shutdown alert. Therefore, when we are >+ * the first party to send the alert, we must call SSL_shutdown() >+ * again. >+ * On failure we don't want to resume the session, so we will not >+ * perform SSL_shutdown() and the session will be removed as being >+ * bad. >+ */ >+ if (!failure) { >+ retval = do_tls_operation(vstream_fileno(stream), timeout, >+ TLScontext, SSL_shutdown, NULL, NULL, NULL, 0); >+ if (retval == 0) >+ do_tls_operation(vstream_fileno(stream), timeout, TLScontext, >+ SSL_shutdown, NULL, NULL, NULL, 0); >+ } >+ /* >+ * Free the SSL structure and the BIOs. Warning: the internal_bio is >+ * connected to the SSL structure and is automatically freed with >+ * it. Do not free it again (core dump)!! >+ * Only free the network_bio. >+ */ >+ SSL_free(TLScontext->con); >+ BIO_free(TLScontext->network_bio); >+ myfree((char *)TLScontext); >+ vstream_control(stream, >+ VSTREAM_CTL_READ_FN, (VSTREAM_FN) NULL, >+ VSTREAM_CTL_WRITE_FN, (VSTREAM_FN) NULL, >+ VSTREAM_CTL_CONTEXT, (void *) NULL, >+ VSTREAM_CTL_END); >+ SSL_CTX_flush_sessions(ctx, time(NULL)); >+ >+ pfixtls_stir_seed(); >+ pfixtls_exchange_seed(); >+ >+ *tls_info = tls_info_zero; >+ pfixtls_clientactive = 0; >+ >+ } >+ >+ return (0); >+} >+ >+ >+#endif /* HAS_SSL */ >diff -Pur postfix-1.1.11-20020613-orig/src/global/pfixtls.h postfix-1.1.11-20020613/src/global/pfixtls.h >--- postfix-1.1.11-20020613-orig/src/global/pfixtls.h Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/global/pfixtls.h Wed Jun 26 15:26:48 2002 >@@ -0,0 +1,76 @@ >+/*++ >+/* NAME >+/* pfixtls 3h >+/* SUMMARY >+/* TLS routines >+/* SYNOPSIS >+/* include "pfixtls.h" >+/* DESCRIPTION >+/* .nf >+/*--*/ >+ >+#ifndef PFIXTLS_H_INCLUDED >+#define PFIXTLS_H_INCLUDED >+ >+typedef struct { >+ int peer_verified; >+ char *peer_subject; >+ char *peer_issuer; >+ char *peer_fingerprint; >+ char *peer_CN; >+ char *issuer_CN; >+ const char *protocol; >+ const char *cipher_name; >+ int cipher_usebits; >+ int cipher_algbits; >+} tls_info_t; >+ >+extern const tls_info_t tls_info_zero; >+ >+#ifdef HAS_SSL >+ >+typedef struct { >+ long scache_db_version; >+ long openssl_version; >+ time_t timestamp; /* We could add other info here... */ >+ int enforce_peername; >+} pfixtls_scache_info_t; >+ >+extern const long scache_db_version; >+extern const long openssl_version; >+ >+int pfixtls_timed_read(int fd, void *buf, unsigned len, int timout, >+ void *unused_timeout); >+int pfixtls_timed_write(int fd, void *buf, unsigned len, int timeout, >+ void *unused_timeout); >+ >+extern int pfixtls_serverengine; >+int pfixtls_init_serverengine(int verifydepth, int askcert); >+int pfixtls_start_servertls(VSTREAM *stream, int timeout, >+ const char *peername, const char *peeraddr, >+ tls_info_t *tls_info, int require_cert); >+int pfixtls_stop_servertls(VSTREAM *stream, int timeout, int failure, >+ tls_info_t *tls_info); >+ >+extern int pfixtls_clientengine; >+int pfixtls_init_clientengine(int verifydepth); >+int pfixtls_start_clienttls(VSTREAM *stream, int timeout, >+ int enforce_peername, >+ const char *peername, >+ tls_info_t *tls_info); >+int pfixtls_stop_clienttls(VSTREAM *stream, int timeout, int failure, >+ tls_info_t *tls_info); >+ >+#endif /* PFIXTLS_H_INCLUDED */ >+#endif >+ >+/* LICENSE >+/* .ad >+/* .fi >+/* AUTHOR(S) >+/* Lutz Jaenicke >+/* BTU Cottbus >+/* Allgemeine Elektrotechnik >+/* Universitaetsplatz 3-4 >+/* D-03044 Cottbus, Germany >+/*--*/ >diff -Pur postfix-1.1.11-20020613-orig/src/global/resolve_local.c postfix-1.1.11-20020613/src/global/resolve_local.c >--- postfix-1.1.11-20020613-orig/src/global/resolve_local.c Thu Jan 31 20:56:29 2002 >+++ postfix-1.1.11-20020613/src/global/resolve_local.c Wed Jun 26 15:26:48 2002 >@@ -42,6 +42,7 @@ > #include <netinet/in.h> > #include <arpa/inet.h> > #include <string.h> >+#include <netdb.h> > > #ifndef INADDR_NONE > #define INADDR_NONE 0xffffffff >@@ -79,7 +80,12 @@ > { > char *saved_addr = mystrdup(addr); > char *dest; >+#ifdef INET6 >+ struct addrinfo hints, *res, *res0; >+ int error; >+#else > struct in_addr ipaddr; >+#endif > int len; > > #define RETURN(x) { myfree(saved_addr); return(x); } >@@ -111,9 +117,25 @@ > if (*dest == '[' && dest[len - 1] == ']') { > dest++; > dest[len -= 2] = 0; >+#ifdef INET6 >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = PF_UNSPEC; >+ hints.ai_socktype = SOCK_DGRAM; >+ error = getaddrinfo(dest, NULL, &hints, &res0); >+ if (!error) { >+ for (res = res0; res; res = res->ai_next) { >+ if (own_inet_addr(res->ai_addr)) { >+ freeaddrinfo(res0); >+ RETURN(1); >+ } >+ } >+ freeaddrinfo(res0); >+ } >+#else > if ((ipaddr.s_addr = inet_addr(dest)) != INADDR_NONE > && own_inet_addr(&ipaddr)) > RETURN(1); >+#endif > } > > /* >diff -Pur postfix-1.1.11-20020613-orig/src/global/wildcard_inet_addr.c postfix-1.1.11-20020613/src/global/wildcard_inet_addr.c >--- postfix-1.1.11-20020613-orig/src/global/wildcard_inet_addr.c Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/global/wildcard_inet_addr.c Wed Jun 26 15:26:48 2002 >@@ -0,0 +1,82 @@ >+/* System library. */ >+ >+#include <sys_defs.h> >+#include <netinet/in.h> >+#include <arpa/inet.h> >+#include <string.h> >+#ifdef INET6 >+#include <sys/socket.h> >+#endif >+#include <netdb.h> >+ >+#ifdef STRCASECMP_IN_STRINGS_H >+#include <strings.h> >+#endif >+ >+/* Utility library. */ >+ >+#include <msg.h> >+#include <mymalloc.h> >+#include <inet_addr_list.h> >+#include <inet_addr_local.h> >+#include <inet_addr_host.h> >+#include <stringops.h> >+ >+/* Global library. */ >+ >+#include <mail_params.h> >+#include <wildcard_inet_addr.h> >+ >+/* Application-specific. */ >+static INET_ADDR_LIST addr_list; >+ >+/* wildcard_inet_addr_init - initialize my own address list */ >+ >+static void wildcard_inet_addr_init(INET_ADDR_LIST *addr_list) >+{ >+#ifdef INET6 >+ struct addrinfo hints, *res, *res0; >+ char hbuf[NI_MAXHOST]; >+ int error; >+#ifdef NI_WITHSCOPEID >+ const int niflags = NI_NUMERICHOST | NI_WITHSCOPEID; >+#else >+ const int niflags = NI_NUMERICHOST; >+#endif >+ >+ inet_addr_list_init(addr_list); >+ >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = PF_UNSPEC; >+ hints.ai_socktype = SOCK_STREAM; >+ hints.ai_flags = AI_PASSIVE; >+ error = getaddrinfo(NULL, "0", &hints, &res0); >+ if (error) >+ msg_fatal("could not get list of wildcard addresses"); >+ for (res = res0; res; res = res->ai_next) { >+ if (res->ai_family != AF_INET && res->ai_family != AF_INET6) >+ continue; >+ if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), >+ NULL, 0, niflags) != 0) >+ continue; >+ if (inet_addr_host(addr_list, hbuf) == 0) >+ continue; /* msg_fatal("config variable %s: host not found: %s", >+ VAR_INET_INTERFACES, hbuf); */ >+ } >+ freeaddrinfo(res0); >+#else >+ if (inet_addr_host(addr_list, "0.0.0.0") == 0) >+ msg_fatal("config variable %s: host not found: %s", >+ VAR_INET_INTERFACES, "0.0.0.0"); >+#endif >+} >+ >+/* wildcard_inet_addr_list - return list of addresses */ >+ >+INET_ADDR_LIST *wildcard_inet_addr_list(void) >+{ >+ if (addr_list.used == 0) >+ wildcard_inet_addr_init(&addr_list); >+ >+ return (&addr_list); >+} >diff -Pur postfix-1.1.11-20020613-orig/src/global/wildcard_inet_addr.h postfix-1.1.11-20020613/src/global/wildcard_inet_addr.h >--- postfix-1.1.11-20020613-orig/src/global/wildcard_inet_addr.h Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/global/wildcard_inet_addr.h Wed Jun 26 15:26:48 2002 >@@ -0,0 +1,36 @@ >+#ifndef _WILDCARD_INET_ADDR_H_INCLUDED_ >+#define _WILDCARD_INET_ADDR_H_INCLUDED_ >+ >+/*++ >+/* NAME >+/* wildcard_inet_addr_list 3h >+/* SUMMARY >+/* grab the list of wildcard IP addresses. >+/* SYNOPSIS >+/* #include <own_inet_addr.h> >+/* DESCRIPTION >+/* .nf >+/*--*/ >+ >+ /* >+ * System library. >+ */ >+#include <netinet/in.h> >+#ifdef INET6 >+#include <sys/socket.h> >+#endif >+ >+ /* >+ * External interface. >+ */ >+extern struct INET_ADDR_LIST *wildcard_inet_addr_list(void); >+ >+/* LICENSE >+/* .ad >+/* .fi >+/* foo >+/* AUTHOR(S) >+/* Jun-ichiro itojun Hagino >+/*--*/ >+ >+#endif >diff -Pur postfix-1.1.11-20020613-orig/src/lmtp/lmtp.c postfix-1.1.11-20020613/src/lmtp/lmtp.c >--- postfix-1.1.11-20020613-orig/src/lmtp/lmtp.c Sat May 11 02:07:05 2002 >+++ postfix-1.1.11-20020613/src/lmtp/lmtp.c Wed Jun 26 15:26:48 2002 >@@ -190,6 +190,12 @@ > /* .IP \fBlmtp_quit_timeout\fR > /* Timeout for sending the \fBQUIT\fR command, and for > /* receiving the server response. >+/* .IP \fBlmtp_bind_address\fR >+/* Numerical source network address (IPv4) to bind to when making >+/* a connection. >+/* .IP \fBlmtp_bind_address6\fR >+/* Numerical source network address (IPv6) to bind to when making >+/* a connection. > /* SEE ALSO > /* bounce(8) non-delivery status reports > /* local(8) local mail delivery >@@ -276,6 +282,8 @@ > char *var_lmtp_sasl_opts; > char *var_lmtp_sasl_passwd; > bool var_lmtp_sasl_enable; >+char *var_lmtp_bind_addr; >+char *var_lmtp_bind_addr6; > > /* > * Global variables. >@@ -514,6 +522,10 @@ > VAR_ERROR_RCPT, DEF_ERROR_RCPT, &var_error_rcpt, 1, 0, > VAR_LMTP_SASL_PASSWD, DEF_LMTP_SASL_PASSWD, &var_lmtp_sasl_passwd, 0, 0, > VAR_LMTP_SASL_OPTS, DEF_LMTP_SASL_OPTS, &var_lmtp_sasl_opts, 0, 0, >+ VAR_LMTP_BIND_ADDR, DEF_LMTP_BIND_ADDR, &var_lmtp_bind_addr, 0, 0, >+#ifdef INET6 >+ VAR_LMTP_BIND_ADDR6, DEF_LMTP_BIND_ADDR6, &var_lmtp_bind_addr6, 0, 0, >+#endif > 0, > }; > static CONFIG_INT_TABLE int_table[] = { >diff -Pur postfix-1.1.11-20020613-orig/src/lmtp/lmtp_connect.c postfix-1.1.11-20020613/src/lmtp/lmtp_connect.c >--- postfix-1.1.11-20020613-orig/src/lmtp/lmtp_connect.c Thu Mar 22 02:01:46 2001 >+++ postfix-1.1.11-20020613/src/lmtp/lmtp_connect.c Wed Jun 26 15:26:48 2002 >@@ -92,11 +92,13 @@ > #include <iostuff.h> > #include <timed_connect.h> > #include <stringops.h> >+#include <inet_addr_list.h> > > /* Global library. */ > > #include <mail_params.h> > #include <mail_proto.h> >+#include <own_inet_addr.h> > > /* DNS library. */ > >@@ -166,13 +168,42 @@ > const char *destination, VSTRING *why) > { > char *myname = "lmtp_connect_addr"; >- struct sockaddr_in sin; >- int sock; >+#ifdef INET6 >+ struct sockaddr_storage ss; >+#else >+ struct sockaddr ss; >+#endif >+ struct sockaddr *sa; >+ struct sockaddr_in *sin; >+#ifdef INET6 >+ struct sockaddr_in6 *sin6; >+#endif >+ SOCKADDR_SIZE salen; >+#ifdef INET6 >+ char hbuf[NI_MAXHOST]; >+#else >+ char hbuf[sizeof("255.255.255.255") + 1]; >+#endif >+ int sock = -1; >+ INET_ADDR_LIST *addr_list; >+ char *bind_addr; >+ >+ sa = (struct sockaddr *)&ss; >+ sin = (struct sockaddr_in *)&ss; >+#ifdef INET6 >+ sin6 = (struct sockaddr_in6 *)&ss; >+#endif > > /* > * Sanity checks. > */ >- if (addr->data_len > sizeof(sin.sin_addr)) { >+#ifdef INET6 >+ if (((addr->type==T_A) && (addr->data_len > sizeof(sin->sin_addr))) || >+ ((addr->type==T_AAAA) && (addr->data_len > sizeof(sin6->sin6_addr)))) >+#else >+ if (addr->data_len > sizeof(sin->sin_addr)) >+#endif >+ { > msg_warn("%s: skip address with length %d", myname, addr->data_len); > lmtp_errno = LMTP_RETRY; > return (0); >@@ -181,25 +212,168 @@ > /* > * Initialize. > */ >- memset((char *) &sin, 0, sizeof(sin)); >- sin.sin_family = AF_INET; >+ switch (addr->type) { >+#ifdef INET6 >+ case T_AAAA: >+ bind_addr = var_lmtp_bind_addr6; >+ memset(sin6, 0, sizeof(*sin6)); >+ sin6->sin6_family = AF_INET6; >+ salen = sizeof(*sin6); >+ break; >+#endif >+ default: /* T_A: */ >+ bind_addr = var_lmtp_bind_addr; >+ memset(sin, 0, sizeof(*sin)); >+ sin->sin_family = AF_INET; >+ salen = sizeof(*sin); >+ break; >+ }; >+#ifdef HAS_SALEN >+ sa->sa_len = salen; >+#endif > >- if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) >+ if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) > msg_fatal("%s: socket: %m", myname); > > /* >+ * Allow the sysadmin to specify the source address >+ */ >+ >+ if (*bind_addr) { >+#ifndef INET6 >+ struct sockaddr_in sin; >+ >+ memset(&sin, 0, sizeof(sin)); >+ sin.sin_family = AF_INET; >+#ifdef HAS_SA_LEN >+ sin.sin_len = sizeof(sin); >+#endif >+ sin.sin_addr.s_addr = inet_addr(bind_addr); >+ if (sin.sin_addr.s_addr == INADDR_NONE) >+ msg_fatal("%s: bad %s parameter: %s", >+ myname, VAR_LMTP_BIND_ADDR, var_smtp_bind_addr); >+ if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) < 0) >+ msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); >+ if (msg_verbose) >+ msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); >+#else >+ char hbufl[NI_MAXHOST]; >+ struct addrinfo hints, *res; >+ >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = sa->sa_family; >+ hints.ai_socktype = SOCK_STREAM; >+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST; >+ snprintf(hbufl, sizeof(hbufl)-1, "%s", bind_addr); >+ if (getaddrinfo(hbufl, NULL, &hints, &res) == 0) { >+ (void)getnameinfo(res->ai_addr, res->ai_addrlen, hbufl, >+ sizeof(hbufl), NULL, 0, NI_NUMERICHOST); >+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) >+ msg_warn("%s: bind %s: %m", myname, hbufl); >+ freeaddrinfo(res); >+ if (msg_verbose) >+ msg_info("%s: bind %s", myname, hbufl); >+ } >+#endif >+ } >+ >+ /* >+ * If running on a virtual host, start connections from the >+ * right address. >+ */ >+ >+ else if ((addr_list = own_inet_addr_list())->used == 1) { >+#ifndef INET6 >+ struct sockaddr_in sin; >+ unsigned long inaddr; /* XXX BAD!*/ >+ >+ memset(&sin, 0, sizeof(sin)); >+ sin.sin_family = AF_INET; >+#ifdef HAS_SA_LEN >+ sin.sin_len = sizeof(sin); >+#endif >+ memcpy((char *)&sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr)); >+ inaddr = (unsigned long)ntohl(sin.sin_addr.s_addr); >+ if (!IN_CLASSA(inaddr) >+ /* XXX Are the two following lines correct? */ >+ || !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == >+ IN_LOOPBACKNET)) { >+ if (bind(sock, (struct sockaddr *)&sin, sizeof(sin)) < 0) >+ msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); >+ if (msg_verbose) >+ msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); >+ } >+#else >+ char hbufl[NI_MAXHOST]; >+ struct addrinfo hints, *res = NULL, *loopback = NULL; >+ >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = sa->sa_family; >+ hints.ai_socktype = SOCK_STREAM; >+ if (getaddrinfo(NULL, "0", &hints, &loopback) != 0) >+ loopback = NULL; >+ >+ /* >+ * getnameinfo -> getaddrinfo loop is here so that we can >+ * get rid of port >+ */ >+ (void)getnameinfo((struct sockaddr *)addr_list->addrs, >+ SA_LEN((struct sockaddr *)addr_list->addrs), >+ hbufl, sizeof(hbufl), NULL, 0, NI_NUMERICHOST); >+ hbufl[sizeof(hbufl) - 1] = 0; >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = sa->sa_family; >+ hints.ai_socktype = SOCK_STREAM; >+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST; >+ if (getaddrinfo(hbufl, NULL, &hints, &res) == 0 && >+ !(res->ai_addrlen == loopback->ai_addrlen && >+ memcmp(res->ai_addr, loopback->ai_addr, res->ai_addrlen) == 0)) { >+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) >+ msg_warn("%s: bind %s: %m", myname, hbufl); >+ if (msg_verbose) >+ msg_info("%s: bind %s", myname, hbufl); >+ } >+ if (res) >+ freeaddrinfo(res); >+ if (loopback) >+ freeaddrinfo(loopback); >+#endif >+ } >+ >+ /* > * Connect to the LMTP server. > */ >- sin.sin_port = port; >- memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr)); >+ switch (addr->type) { >+#ifdef INET6 >+ case T_AAAA: >+ /* XXX scope-unfriendly */ >+ memset(sin6, 0, sizeof(*sin6)); >+ sin6->sin6_port = port; >+ sin6->sin6_family = AF_INET6; >+ salen = sizeof(*sin6); >+ memcpy(&sin6->sin6_addr, addr->data, sizeof(sin6->sin6_addr)); >+ inet_ntop(AF_INET6, &sin6->sin6_addr, hbuf, sizeof(hbuf)); >+ break; >+#endif >+ default: /* T_A: */ >+ memset(sin, 0, sizeof(*sin)); >+ sin->sin_port = port; >+ sin->sin_family = AF_INET; >+ salen = sizeof(*sin6); >+ memcpy(&sin->sin_addr, addr->data, sizeof(sin->sin_addr)); >+ inet_ntop(AF_INET, &sin->sin_addr, hbuf, sizeof(hbuf)); >+ break; >+ } >+#ifdef HAS_SA_LEN >+ sa->sa_len = salen; >+#endif > > if (msg_verbose) > msg_info("%s: trying: %s[%s] port %d...", >- myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port)); >+ myname, addr->name, hbuf, ntohs(port)); > >- return (lmtp_connect_sock(sock, (struct sockaddr *) & sin, sizeof(sin), >- addr->name, inet_ntoa(sin.sin_addr), >- destination, why)); >+ return (lmtp_connect_sock(sock, (struct sockaddr *)sa, salen, >+ addr->name, hbuf, destination, why)); > } > > /* lmtp_connect_sock - connect a socket over some transport */ >diff -Pur postfix-1.1.11-20020613-orig/src/master/master_ent.c postfix-1.1.11-20020613/src/master/master_ent.c >--- postfix-1.1.11-20020613-orig/src/master/master_ent.c Sun Dec 23 20:08:58 2001 >+++ postfix-1.1.11-20020613/src/master/master_ent.c Wed Jun 26 15:26:48 2002 >@@ -284,8 +284,13 @@ > inet_addr_host(MASTER_INET_ADDRLIST(serv), host); > serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; > } else if (strcasecmp(var_inet_interfaces, DEF_INET_INTERFACES) == 0) { >+#ifdef INET6 >+ MASTER_INET_ADDRLIST(serv) = wildcard_inet_addr_list(); >+ serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; >+#else > MASTER_INET_ADDRLIST(serv) = 0; /* wild-card */ > serv->listen_fd_count = 1; >+#endif > } else { > MASTER_INET_ADDRLIST(serv) = own_inet_addr_list(); /* virtual */ > serv->listen_fd_count = MASTER_INET_ADDRLIST(serv)->used; >diff -Pur postfix-1.1.11-20020613-orig/src/master/master_listen.c postfix-1.1.11-20020613/src/master/master_listen.c >--- postfix-1.1.11-20020613-orig/src/master/master_listen.c Tue May 1 00:47:57 2001 >+++ postfix-1.1.11-20020613/src/master/master_listen.c Wed Jun 26 15:26:48 2002 >@@ -64,13 +64,22 @@ > > #include "master.h" > >+#ifdef INET6 >+#include <netdb.h> >+#include <stdio.h> >+#endif >+ > /* master_listen_init - enable connection requests */ > > void master_listen_init(MASTER_SERV *serv) > { > char *myname = "master_listen_init"; > char *end_point; >- int n; >+ int n,m,tmpfd; >+#ifdef INET6 >+ char hbuf[NI_MAXHOST]; >+ SOCKADDR_SIZE salen; >+#endif > > /* > * Find out what transport we should use, then create one or more >@@ -111,18 +120,31 @@ > serv->listen_fd[0] = > inet_listen(MASTER_INET_PORT(serv), > serv->max_proc > var_proc_limit ? >- serv->max_proc : var_proc_limit, NON_BLOCKING); >+ serv->max_proc : var_proc_limit, NON_BLOCKING, 1); > close_on_exec(serv->listen_fd[0], CLOSE_ON_EXEC); > } else { /* virtual or host:port */ >- for (n = 0; n < serv->listen_fd_count; n++) { >+ for (m = n = 0; n < serv->listen_fd_count; n++) { >+#ifdef INET6 >+ if (getnameinfo((struct sockaddr *)&MASTER_INET_ADDRLIST(serv)->addrs[n], >+ SA_LEN((struct sockaddr *)&MASTER_INET_ADDRLIST(serv)->addrs[n]), >+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST)) { >+ strncpy(hbuf, "?????", sizeof(hbuf)); >+ } >+ end_point = concatenate(hbuf, ":", MASTER_INET_PORT(serv), (char *) 0); >+#else > end_point = concatenate(inet_ntoa(MASTER_INET_ADDRLIST(serv)->addrs[n]), > ":", MASTER_INET_PORT(serv), (char *) 0); >- serv->listen_fd[n] >+#endif >+ tmpfd > = inet_listen(end_point, serv->max_proc > var_proc_limit ? >- serv->max_proc : var_proc_limit, NON_BLOCKING); >- close_on_exec(serv->listen_fd[n], CLOSE_ON_EXEC); >+ serv->max_proc : var_proc_limit, NON_BLOCKING, 0); >+ if (tmpfd >= 0) { >+ serv->listen_fd[m] = tmpfd; >+ close_on_exec(serv->listen_fd[m++], CLOSE_ON_EXEC); >+ } > myfree(end_point); > } >+ serv->listen_fd_count=m; > } > break; > default: >diff -Pur postfix-1.1.11-20020613-orig/src/qmgr/qmgr_message.c postfix-1.1.11-20020613/src/qmgr/qmgr_message.c >--- postfix-1.1.11-20020613-orig/src/qmgr/qmgr_message.c Tue Jun 11 01:55:20 2002 >+++ postfix-1.1.11-20020613/src/qmgr/qmgr_message.c Wed Jun 26 15:26:48 2002 >@@ -507,7 +507,11 @@ > * every front-ent program. > */ > if ((at = strrchr(recipient->address, '@')) != 0 >+#ifdef INET6 >+ && (at + 1)[strspn(at + 1, "[]0123456789.:abcdef")] != 0 >+#else > && (at + 1)[strspn(at + 1, "[]0123456789.")] != 0 >+#endif > && valid_hostname(at + 1, DONT_GRIPE) == 0) { > qmgr_bounce_recipient(message, recipient, > "bad host/domain syntax: \"%s\"", at + 1); >diff -Pur postfix-1.1.11-20020613-orig/src/qmqpd/qmqpd_peer.c postfix-1.1.11-20020613/src/qmqpd/qmqpd_peer.c >--- postfix-1.1.11-20020613-orig/src/qmqpd/qmqpd_peer.c Thu Jul 5 22:09:35 2001 >+++ postfix-1.1.11-20020613/src/qmqpd/qmqpd_peer.c Wed Jun 26 15:29:19 2002 >@@ -70,6 +70,11 @@ > ) > #endif > >+#ifdef INET6 >+#define GAI_STRERROR(error) \ >+ ((error = EAI_SYSTEM) ? gai_strerror(error) : strerror(errno)) >+#endif >+ > /* Utility library. */ > > #include <msg.h> >@@ -79,7 +84,6 @@ > > /* Global library. */ > >- > /* Application-specific. */ > > #include "qmqpd.h" >@@ -88,16 +92,23 @@ > > void qmqpd_peer_init(QMQPD_STATE *state) > { >- struct sockaddr_in sin; >- SOCKADDR_SIZE len = sizeof(sin); >+#ifdef INET6 >+ struct sockaddr_storage ss; >+#else >+ struct sockaddr ss; >+ struct in_addr *in; > struct hostent *hp; >- int i; >+#endif >+ struct sockaddr *sa; >+ SOCKADDR_SIZE len; >+ >+ sa = (struct sockaddr *)&ss; >+ len = sizeof(ss); > > /* > * Look up the peer address information. > */ >- if (getpeername(vstream_fileno(state->client), >- (struct sockaddr *) & sin, &len) >= 0) { >+ if (getpeername(vstream_fileno(state->client), sa, &len) >= 0) { > errno = 0; > } > >@@ -112,16 +123,50 @@ > /* > * Look up and "verify" the client hostname. > */ >- else if (errno == 0 && sin.sin_family == AF_INET) { >- state->addr = mystrdup(inet_ntoa(sin.sin_addr)); >- hp = gethostbyaddr((char *) &(sin.sin_addr), >- sizeof(sin.sin_addr), AF_INET); >- if (hp == 0) { >+ else if (errno == 0 && (sa->sa_family == AF_INET >+#ifdef INET6 >+ || sa->sa_family == AF_INET6 >+#endif >+ )) { >+#ifdef INET6 >+ char hbuf[NI_MAXHOST]; >+ char abuf[NI_MAXHOST]; >+ struct addrinfo hints, *rnull = NULL; >+#else >+ char abuf[sizeof("255.255.255.255") + 1]; >+ char *hbuf; >+#endif >+ int error = -1; >+ >+#ifdef INET6 >+ (void)getnameinfo(sa, len, abuf, sizeof(abuf), NULL, 0, >+ NI_NUMERICHOST); >+#else >+ in = &((struct sockaddr_in *)sa)->sin_addr; >+ inet_ntop(AF_INET, in, abuf, sizeof(abuf)); >+#endif >+ >+ state->addr = mystrdup(abuf); >+#ifdef INET6 >+ error = getnameinfo(sa, len, hbuf, sizeof(hbuf), NULL, 0, >+ NI_NAMEREQD); >+#else >+ hbuf = NULL; >+ hp = gethostbyaddr((char *)in, sizeof(*in), AF_INET); >+ if (hp) { >+ error = 0; >+ hbuf = mystrdup(hp->h_name); >+ state->name = mystrdup("unknown"); >+ } else { >+ error = 1; >+ } >+#endif >+ if (error) { > state->name = mystrdup("unknown"); >- } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) { >+ } else if (!valid_hostname(hbuf, DONT_GRIPE)) { > state->name = mystrdup("unknown"); > } else { >- state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */ >+ state->name = mystrdup(hbuf); /* hp->name is clobbered!! */ > > /* > * Reject the hostname if it does not list the peer address. >@@ -131,16 +176,31 @@ > state->name = mystrdup("unknown"); \ > } > >+#ifdef INET6 >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = AF_UNSPEC; >+ hints.ai_socktype = SOCK_STREAM; >+ error = getaddrinfo(state->name, NULL, &hints, &rnull); >+ if (error) { >+ msg_warn("%s: hostname %s verification failed: %s", >+ state->addr, state->name, GAI_STRERROR(error)); >+ REJECT_PEER_NAME(state); >+ } >+ /* memcmp() isn't needed if we use getaddrinfo */ >+ if (rnull) >+ freeaddrinfo(rnull); >+#else > hp = gethostbyname(state->name); /* clobbers hp->name!! */ > if (hp == 0) { > msg_warn("%s: hostname %s verification failed: %s", > state->addr, state->name, HSTRERROR(h_errno)); > REJECT_PEER_NAME(state); >- } else if (hp->h_length != sizeof(sin.sin_addr)) { >+ } else if (hp->h_length != sizeof(*in)) { > msg_warn("%s: hostname %s verification failed: bad address size %d", > state->addr, state->name, hp->h_length); > REJECT_PEER_NAME(state); > } else { >+ int i; > for (i = 0; /* void */ ; i++) { > if (hp->h_addr_list[i] == 0) { > msg_warn("%s: address not listed for hostname %s", >@@ -148,12 +208,12 @@ > REJECT_PEER_NAME(state); > break; > } >- if (memcmp(hp->h_addr_list[i], >- (char *) &sin.sin_addr, >- sizeof(sin.sin_addr)) == 0) >+ if (memcmp(hp->h_addr_list[i], (char *)in, >+ sizeof(*in)) == 0) > break; /* keep peer name */ > } > } >+#endif > } > } > >diff -Pur postfix-1.1.11-20020613-orig/src/smtp/Makefile.in postfix-1.1.11-20020613/src/smtp/Makefile.in >--- postfix-1.1.11-20020613-orig/src/smtp/Makefile.in Tue Jun 11 03:14:03 2002 >+++ postfix-1.1.11-20020613/src/smtp/Makefile.in Wed Jun 26 15:26:48 2002 >@@ -84,6 +84,7 @@ > smtp.o: ../../include/iostuff.h > smtp.o: ../../include/attr.h > smtp.o: ../../include/mail_server.h >+smtp.o: ../../include/pfixtls.h > smtp.o: smtp.h > smtp.o: smtp_sasl.h > smtp_addr.o: smtp_addr.c >@@ -103,6 +104,7 @@ > smtp_addr.o: ../../include/argv.h > smtp_addr.o: ../../include/deliver_request.h > smtp_addr.o: ../../include/recipient_list.h >+smtp_addr.o: ../../include/pfixtls.h > smtp_addr.o: smtp_addr.h > smtp_chat.o: smtp_chat.c > smtp_chat.o: ../../include/sys_defs.h >@@ -123,6 +125,7 @@ > smtp_chat.o: ../../include/cleanup_user.h > smtp_chat.o: ../../include/mail_error.h > smtp_chat.o: ../../include/name_mask.h >+smtp_chat.o: ../../include/pfixtls.h > smtp_chat.o: smtp.h > smtp_connect.o: smtp_connect.c > smtp_connect.o: ../../include/sys_defs.h >@@ -139,10 +142,12 @@ > smtp_connect.o: ../../include/mail_params.h > smtp_connect.o: ../../include/own_inet_addr.h > smtp_connect.o: ../../include/dns.h >+smtp_connect.o: ../../include/get_port.h > smtp_connect.o: smtp.h > smtp_connect.o: ../../include/argv.h > smtp_connect.o: ../../include/deliver_request.h > smtp_connect.o: ../../include/recipient_list.h >+smtp_connetc.o: ../../include/pfixtls.h > smtp_connect.o: smtp_addr.h > smtp_proto.o: smtp_proto.c > smtp_proto.o: ../../include/sys_defs.h >@@ -174,6 +179,7 @@ > smtp_proto.o: ../../include/attr.h > smtp_proto.o: ../../include/mime_state.h > smtp_proto.o: ../../include/header_opts.h >+smtp_proto.o: ../../include/pfixtls.h > smtp_proto.o: smtp.h > smtp_proto.o: ../../include/argv.h > smtp_proto.o: smtp_sasl.h >@@ -219,9 +225,12 @@ > smtp_session.o: ../../include/stringops.h > smtp_session.o: ../../include/vstring.h > smtp_session.o: smtp.h >+smtp_session.o: ../../include/mail_params.h >+smtp_session.o: ../../include/pfixtls.h > smtp_session.o: ../../include/argv.h > smtp_session.o: ../../include/deliver_request.h > smtp_session.o: ../../include/recipient_list.h >+smtp_session.o: ../../include/maps.h > smtp_state.o: smtp_state.c > smtp_state.o: ../../include/sys_defs.h > smtp_state.o: ../../include/mymalloc.h >@@ -235,6 +244,7 @@ > smtp_state.o: ../../include/argv.h > smtp_state.o: ../../include/deliver_request.h > smtp_state.o: ../../include/recipient_list.h >+smtp_state.o: ../../include/pfixtls.h > smtp_state.o: smtp_sasl.h > smtp_trouble.o: smtp_trouble.c > smtp_trouble.o: ../../include/sys_defs.h >@@ -254,6 +264,7 @@ > smtp_trouble.o: ../../include/name_mask.h > smtp_trouble.o: smtp.h > smtp_trouble.o: ../../include/argv.h >+smtp_trouble.o: ../../include/pfixtls.h > smtp_unalias.o: smtp_unalias.c > smtp_unalias.o: ../../include/sys_defs.h > smtp_unalias.o: ../../include/htable.h >@@ -266,3 +277,4 @@ > smtp_unalias.o: ../../include/argv.h > smtp_unalias.o: ../../include/deliver_request.h > smtp_unalias.o: ../../include/recipient_list.h >+smtp_unalias.o: ../../include/pfixtls.h >diff -Pur postfix-1.1.11-20020613-orig/src/smtp/sasl_problem_diff postfix-1.1.11-20020613/src/smtp/sasl_problem_diff >--- postfix-1.1.11-20020613-orig/src/smtp/sasl_problem_diff Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/smtp/sasl_problem_diff Wed Jun 26 15:26:48 2002 >@@ -0,0 +1,17 @@ >+--- smtp_proto.c.old Wed May 15 14:01:56 2002 >++++ smtp_proto.c Fri May 24 21:13:50 2002 >+@@ -372,8 +372,13 @@ >+ else if (strcasecmp(word, "STARTTLS") == 0) >+ state->features |= SMTP_FEATURE_STARTTLS; >+ #ifdef USE_SASL_AUTH >+- else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0) >++ else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0) { >++ if (state->sasl_mechanism_list) { >++ myfree(state->sasl_mechanism_list); >++ state->sasl_mechanism_list = 0; >++ } >+ smtp_sasl_helo_auth(state, words); >++ } >+ #endif >+ } >+ } >diff -Pur postfix-1.1.11-20020613-orig/src/smtp/smtp.c postfix-1.1.11-20020613/src/smtp/smtp.c >--- postfix-1.1.11-20020613-orig/src/smtp/smtp.c Mon May 27 01:07:04 2002 >+++ postfix-1.1.11-20020613/src/smtp/smtp.c Wed Jun 26 15:26:48 2002 >@@ -100,7 +100,11 @@ > /* .IP \fBsmtp_never_send_ehlo\fR > /* Never send EHLO at the start of a connection. > /* .IP \fBsmtp_bind_address\fR >-/* Numerical source network address to bind to when making a connection. >+/* Numerical source network address (IPv4) to bind to when making >+/* a connection. >+/* .IP \fBsmtp_bind_address6\fR >+/* Numerical source network address (IPv6) to bind to when making >+/* a connection. > /* .IP \fBsmtp_line_length_limit\fR > /* Length limit for SMTP message content lines. Zero means no limit. > /* Some SMTP servers misbehave on long lines. >@@ -240,6 +244,7 @@ > #include <debug_peer.h> > #include <mail_error.h> > #include <deliver_pass.h> >+#include <pfixtls.h> > > /* Single server skeleton. */ > >@@ -256,6 +261,7 @@ > */ > int var_smtp_conn_tmout; > int var_smtp_helo_tmout; >+int var_smtp_starttls_tmout; > int var_smtp_mail_tmout; > int var_smtp_rcpt_tmout; > int var_smtp_data0_tmout; >@@ -277,11 +283,20 @@ > char *var_smtp_sasl_passwd; > bool var_smtp_sasl_enable; > char *var_smtp_bind_addr; >+#ifdef INET6 >+char *var_smtp_bind_addr6; >+#endif > bool var_smtp_rand_addr; > int var_smtp_pix_thresh; > int var_smtp_pix_delay; > int var_smtp_line_limit; > char *var_smtp_helo_name; >+int var_smtp_use_tls; >+int var_smtp_enforce_tls; >+int var_smtp_tls_enforce_peername; >+char *var_smtp_tls_per_site; >+int var_smtp_tls_scert_vd; >+int var_smtp_tls_note_starttls_offer; > > /* > * Global variables. smtp_errno is set by the address lookup routines and by >@@ -391,6 +406,7 @@ > > static void pre_init(char *unused_name, char **unused_argv) > { >+ > debug_peer_init(); > > if (var_smtp_sasl_enable) >@@ -400,6 +416,14 @@ > msg_warn("%s is true, but SASL support is not compiled in", > VAR_SMTP_SASL_ENABLE); > #endif >+ /* >+ * Initialize the TLS data before entering the chroot jail >+ */ >+#ifdef HAS_SSL >+ if (var_smtp_use_tls || var_smtp_enforce_tls || var_smtp_tls_per_site[0]) >+ pfixtls_init_clientengine(var_smtp_tls_scert_vd); >+ smtp_tls_list_init(); >+#endif > } > > /* pre_accept - see if tables have changed */ >@@ -434,7 +458,11 @@ > 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_BIND_ADDR, DEF_SMTP_BIND_ADDR, &var_smtp_bind_addr, 0, 0, >+#ifdef INET6 >+ VAR_SMTP_BIND_ADDR6, DEF_SMTP_BIND_ADDR6, &var_smtp_bind_addr6, 0, 0, >+#endif > VAR_SMTP_HELO_NAME, DEF_SMTP_HELO_NAME, &var_smtp_helo_name, 1, 0, >+ VAR_SMTP_TLS_PER_SITE, DEF_SMTP_TLS_PER_SITE, &var_smtp_tls_per_site, 0, 0, > 0, > }; > static CONFIG_TIME_TABLE time_table[] = { >@@ -448,6 +476,7 @@ > VAR_SMTP_QUIT_TMOUT, DEF_SMTP_QUIT_TMOUT, &var_smtp_quit_tmout, 1, 0, > VAR_SMTP_PIX_THRESH, DEF_SMTP_PIX_THRESH, &var_smtp_pix_thresh, 0, 0, > VAR_SMTP_PIX_DELAY, DEF_SMTP_PIX_DELAY, &var_smtp_pix_delay, 1, 0, >+ VAR_SMTP_STARTTLS_TMOUT, DEF_SMTP_STARTTLS_TMOUT, &var_smtp_starttls_tmout, 1, 0, > 0, > }; > static CONFIG_INT_TABLE int_table[] = { >@@ -463,6 +492,10 @@ > VAR_SMTP_NEVER_EHLO, DEF_SMTP_NEVER_EHLO, &var_smtp_never_ehlo, > VAR_SMTP_SASL_ENABLE, DEF_SMTP_SASL_ENABLE, &var_smtp_sasl_enable, > VAR_SMTP_RAND_ADDR, DEF_SMTP_RAND_ADDR, &var_smtp_rand_addr, >+ VAR_SMTP_USE_TLS, DEF_SMTP_USE_TLS, &var_smtp_use_tls, >+ VAR_SMTP_ENFORCE_TLS, DEF_SMTP_ENFORCE_TLS, &var_smtp_enforce_tls, >+ VAR_SMTP_TLS_ENFORCE_PN, DEF_SMTP_TLS_ENFORCE_PN, &var_smtp_tls_enforce_peername, >+ VAR_SMTP_TLS_NOTEOFFER, DEF_SMTP_TLS_NOTEOFFER, &var_smtp_tls_note_starttls_offer, > 0, > }; > >diff -Pur postfix-1.1.11-20020613-orig/src/smtp/smtp.h postfix-1.1.11-20020613/src/smtp/smtp.h >--- postfix-1.1.11-20020613-orig/src/smtp/smtp.h Thu May 23 21:18:02 2002 >+++ postfix-1.1.11-20020613/src/smtp/smtp.h Wed Jun 26 15:26:48 2002 >@@ -27,6 +27,7 @@ > * Global library. > */ > #include <deliver_request.h> >+#include <pfixtls.h> > > /* > * State information associated with each SMTP delivery. We're bundling the >@@ -79,9 +80,14 @@ > char *addr; /* mail exchanger */ > char *namaddr; /* mail exchanger */ > int best; /* most preferred host */ >+ int tls_use_tls; /* can do TLS */ >+ int tls_enforce_tls; /* must do TLS */ >+ int tls_enforce_peername; /* cert must match */ >+ tls_info_t tls_info; /* TLS connection state */ > } SMTP_SESSION; > >-extern SMTP_SESSION *smtp_session_alloc(VSTREAM *, char *, char *); >+extern void smtp_tls_list_init(void); >+extern SMTP_SESSION *smtp_session_alloc(char *, VSTREAM *, char *, char *); > extern void smtp_session_free(SMTP_SESSION *); > > /* >diff -Pur postfix-1.1.11-20020613-orig/src/smtp/smtp_addr.c postfix-1.1.11-20020613/src/smtp/smtp_addr.c >--- postfix-1.1.11-20020613-orig/src/smtp/smtp_addr.c Sun Jul 8 17:05:26 2001 >+++ postfix-1.1.11-20020613/src/smtp/smtp_addr.c Wed Jun 26 15:26:48 2002 >@@ -134,18 +134,68 @@ > static void smtp_print_addr(char *what, DNS_RR *addr_list) > { > DNS_RR *addr; >- struct in_addr in_addr; >+#ifdef INET6 >+ struct sockaddr_storage ss; >+#else >+ struct sockaddr ss; >+#endif >+ struct sockaddr_in *sin; >+#ifdef INET6 >+ struct sockaddr_in6 *sin6; >+ char hbuf[NI_MAXHOST]; >+#else >+ char hbuf[sizeof("255.255.255.255") + 1]; >+#endif > > msg_info("begin %s address list", what); > for (addr = addr_list; addr; addr = addr->next) { >- if (addr->data_len > sizeof(addr)) { >- msg_warn("skipping address length %d", addr->data_len); >- } else { >- memcpy((char *) &in_addr, addr->data, sizeof(in_addr)); >- msg_info("pref %4d host %s/%s", >- addr->pref, addr->name, >- inet_ntoa(in_addr)); >+ if (addr->class != C_IN) { >+ msg_warn("skipping unsupported address (class=%u)", addr->class); >+ continue; > } >+ switch (addr->type) { >+ case T_A: >+ if (addr->data_len != sizeof(sin->sin_addr)) { >+ msg_warn("skipping invalid address (AAAA, len=%u)", >+ addr->data_len); >+ continue; >+ } >+ sin = (struct sockaddr_in *)&ss; >+ memset(sin, 0, sizeof(*sin)); >+ sin->sin_family = AF_INET; >+#ifdef HAS_SA_LEN >+ sin->sin_len = sizeof(*sin); >+#endif >+ memcpy(&sin->sin_addr, addr->data, sizeof(sin->sin_addr)); >+ break; >+#ifdef INET6 >+ case T_AAAA: >+ if (addr->data_len != sizeof(sin6->sin6_addr)) { >+ msg_warn("skipping invalid address (AAAA, len=%u)", >+ addr->data_len); >+ continue; >+ } >+ sin6 = (struct sockaddr_in6 *)&ss; >+ memset(sin6, 0, sizeof(*sin6)); >+ sin6->sin6_family = AF_INET6; >+#ifdef HAS_SA_LEN >+ sin6->sin6_len = sizeof(*sin6); >+#endif >+ memcpy(&sin6->sin6_addr, addr->data, sizeof(sin6->sin6_addr)); >+ break; >+#endif >+ default: >+ msg_warn("skipping unsupported address (type=%u)", addr->type); >+ continue; >+ } >+ >+#ifdef INET6 >+ (void)getnameinfo((struct sockaddr *)&ss, SS_LEN(ss), >+ hbuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); >+#else >+ (void)inet_ntop(AF_INET, &sin->sin_addr, hbuf, sizeof(hbuf)); >+#endif >+ msg_info("pref %4d host %s/%s", addr->pref, addr->name, hbuf); > } > msg_info("end %s address list", what); > } >@@ -155,15 +205,23 @@ > static DNS_RR *smtp_addr_one(DNS_RR *addr_list, char *host, unsigned pref, VSTRING *why) > { > char *myname = "smtp_addr_one"; >+#ifndef INET6 > struct in_addr inaddr; >- DNS_FIXED fixed; > DNS_RR *addr = 0; > DNS_RR *rr; > struct hostent *hp; >+#else >+ struct addrinfo hints, *res0, *res; >+ int error = -1; >+ char *addr; >+ size_t addrlen; >+#endif >+ DNS_FIXED fixed; > > if (msg_verbose) > msg_info("%s: host %s", myname, host); > >+#ifndef INET6 > /* > * Interpret a numerical name as an address. > */ >@@ -216,6 +274,48 @@ > smtp_errno = SMTP_FAIL; > break; > } >+#else >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = PF_UNSPEC; >+ hints.ai_socktype = SOCK_STREAM; >+ error = getaddrinfo(host, NULL, &hints, &res0); >+ if (error) { >+ switch (error) { >+ case EAI_AGAIN: >+ smtp_errno = SMTP_RETRY; >+ break; >+ default: >+ vstring_sprintf(why, "[%s]: %s",host,gai_strerror(error)); >+ smtp_errno = SMTP_FAIL; >+ break; >+ } >+ return (addr_list); >+ } >+ for (res = res0; res; res = res->ai_next) { >+ memset((char *) &fixed, 0, sizeof(fixed)); >+ switch(res->ai_family) { >+ case AF_INET6: >+ /* XXX not scope friendly */ >+ fixed.type = T_AAAA; >+ addr = (char *)&((struct sockaddr_in6 *)res->ai_addr)->sin6_addr; >+ addrlen = sizeof(struct in6_addr); >+ break; >+ case AF_INET: >+ fixed.type = T_A; >+ addr = (char *)&((struct sockaddr_in *)res->ai_addr)->sin_addr; >+ addrlen = sizeof(struct in_addr); >+ break; >+ default: >+ msg_warn("%s: unknown address family %d for %s", >+ myname, res->ai_family, host); >+ continue; >+ } >+ addr_list = dns_rr_append(addr_list, >+ dns_rr_create(host, &fixed, pref, addr, addrlen)); >+ } >+ if (res0) >+ freeaddrinfo(res0); >+#endif > return (addr_list); > } > >@@ -251,6 +351,9 @@ > INET_ADDR_LIST *self; > DNS_RR *addr; > int i; >+#ifdef INET6 >+ struct sockaddr *sa; >+#endif > > /* > * Find the first address that lists any address that this mail system is >@@ -260,12 +363,36 @@ > > self = own_inet_addr_list(); > for (addr = addr_list; addr; addr = addr->next) { >- for (i = 0; i < self->used; i++) >+ for (i = 0; i < self->used; i++) { >+#ifdef INET6 >+ sa = (struct sockaddr *)&self->addrs[i]; >+ switch(addr->type) { >+ case T_AAAA: >+ /* XXX scope */ >+ if (sa->sa_family != AF_INET6) >+ break; >+ if (memcmp(&((struct sockaddr_in6 *)sa)->sin6_addr, >+ addr->data, sizeof(struct in6_addr)) == 0) { >+ return(addr); >+ } >+ break; >+ case T_A: >+ if (sa->sa_family != AF_INET) >+ break; >+ if (memcmp(&((struct sockaddr_in *)sa)->sin_addr, >+ addr->data, sizeof(struct in_addr)) == 0) { >+ return(addr); >+ } >+ break; >+ } >+#else > if (INADDRP(addr->data)->s_addr == self->addrs[i].s_addr) { > if (msg_verbose) > msg_info("%s: found at pref %d", myname, addr->pref); > return (addr); > } >+#endif >+ } > } > > /* >diff -Pur postfix-1.1.11-20020613-orig/src/smtp/smtp_connect.c postfix-1.1.11-20020613/src/smtp/smtp_connect.c >--- postfix-1.1.11-20020613-orig/src/smtp/smtp_connect.c Sun Jul 8 21:40:03 2001 >+++ postfix-1.1.11-20020613/src/smtp/smtp_connect.c Wed Jun 26 15:26:48 2002 >@@ -81,6 +81,7 @@ > /* System library. */ > > #include <sys_defs.h> >+#include <stdlib.h> > #include <sys/socket.h> > #include <netinet/in.h> > #include <arpa/inet.h> >@@ -110,12 +111,14 @@ > #include <inet_addr_list.h> > #include <iostuff.h> > #include <timed_connect.h> >+#include <get_port.h> > #include <stringops.h> > > /* Global library. */ > > #include <mail_params.h> > #include <own_inet_addr.h> >+#include <pfixtls.h> > > /* DNS library. */ > >@@ -128,23 +131,50 @@ > > /* smtp_connect_addr - connect to explicit address */ > >-static SMTP_SESSION *smtp_connect_addr(DNS_RR *addr, unsigned port, >+static SMTP_SESSION *smtp_connect_addr(char *dest, DNS_RR *addr, unsigned port, > VSTRING *why) > { > char *myname = "smtp_connect_addr"; >- struct sockaddr_in sin; >- int sock; >+#ifdef INET6 >+ struct sockaddr_storage ss; >+#else >+ struct sockaddr ss; >+#endif >+ struct sockaddr *sa; >+ struct sockaddr_in *sin; >+#ifdef INET6 >+ struct sockaddr_in6 *sin6; >+#endif >+ SOCKADDR_SIZE salen; >+#ifdef INET6 >+ char hbuf[NI_MAXHOST]; >+#else >+ char hbuf[sizeof("255.255.255.255") + 1]; >+#endif >+ int sock = -1; > INET_ADDR_LIST *addr_list; > int conn_stat; > int saved_errno; > VSTREAM *stream; > int ch; >- unsigned long inaddr; >+ char *bind_addr; >+ >+ sa = (struct sockaddr *)&ss; >+ sin = (struct sockaddr_in *)&ss; >+#ifdef INET6 >+ sin6 = (struct sockaddr_in6 *)&ss; >+#endif > > /* > * Sanity checks. > */ >- if (addr->data_len > sizeof(sin.sin_addr)) { >+#ifdef INET6 >+ if (((addr->type==T_A) && (addr->data_len > sizeof(sin->sin_addr))) || >+ ((addr->type==T_AAAA) && (addr->data_len > sizeof(sin6->sin6_addr)))) >+#else >+ if (addr->data_len > sizeof(sin->sin_addr)) >+#endif >+ { > msg_warn("%s: skip address with length %d", myname, addr->data_len); > smtp_errno = SMTP_RETRY; > return (0); >@@ -153,18 +183,42 @@ > /* > * Initialize. > */ >- memset((char *) &sin, 0, sizeof(sin)); >- sin.sin_family = AF_INET; >- >- if ((sock = socket(sin.sin_family, SOCK_STREAM, 0)) < 0) >- msg_fatal("%s: socket: %m", myname); >- >+ switch (addr->type) { >+#ifdef INET6 >+ case T_AAAA: >+ bind_addr = var_smtp_bind_addr6; >+ memset(sin6, 0, sizeof(*sin6)); >+ sin6->sin6_family = AF_INET6; >+ salen = sizeof(*sin6); >+ break; >+#endif >+ default: /* T_A: */ >+ bind_addr = var_smtp_bind_addr; >+ memset(sin, 0, sizeof(*sin)); >+ sin->sin_family = AF_INET; >+ salen = sizeof(*sin); >+ break; >+ } >+#ifdef HAS_SA_LEN >+ sa->sa_len = salen; >+#endif >+ if ((sock = socket(sa->sa_family, SOCK_STREAM, 0)) < 0) >+ msg_warn("%s: socket: %m", myname); >+ > /* > * Allow the sysadmin to specify the source address, for example, as "-o > * smtp_bind_address=x.x.x.x" in the master.cf file. > */ >- if (*var_smtp_bind_addr) { >- sin.sin_addr.s_addr = inet_addr(var_smtp_bind_addr); >+ if (*bind_addr) { >+#ifndef INET6 >+ struct sockaddr_in sin; >+ >+ memset(&sin, 0, sizeof(sin)); >+ sin.sin_family = AF_INET; >+#ifdef HAS_SA_LEN >+ sin.sin_len = sizeof(sin); >+#endif >+ sin.sin_addr.s_addr = inet_addr(bind_addr); > if (sin.sin_addr.s_addr == INADDR_NONE) > msg_fatal("%s: bad %s parameter: %s", > myname, VAR_SMTP_BIND_ADDR, var_smtp_bind_addr); >@@ -172,6 +226,25 @@ > msg_warn("%s: bind %s: %m", myname, inet_ntoa(sin.sin_addr)); > if (msg_verbose) > msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); >+#else >+ char hbufl[NI_MAXHOST]; >+ struct addrinfo hints, *res; >+ >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = sa->sa_family; >+ hints.ai_socktype = SOCK_STREAM; >+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST; >+ snprintf(hbufl, sizeof(hbufl)-1, "%s", bind_addr); >+ if (getaddrinfo(hbufl, NULL, &hints, &res) == 0) { >+ (void)getnameinfo(res->ai_addr, res->ai_addrlen, hbufl, >+ sizeof(hbufl), NULL, 0, NI_NUMERICHOST); >+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) >+ msg_warn("%s: bind %s: %m", myname, hbufl); >+ freeaddrinfo(res); >+ if (msg_verbose) >+ msg_info("%s: bind %s", myname, hbufl); >+ } >+#endif > } > > /* >@@ -179,8 +252,17 @@ > * the mail appears to come from the "right" machine address. > */ > else if ((addr_list = own_inet_addr_list())->used == 1) { >+#ifndef INET6 >+ struct sockaddr_in sin; >+ unsigned long inaddr; /*XXX BAD!*/ >+ >+ memset(&sin, 0, sizeof(sin)); >+ sin.sin_family = AF_INET; >+#ifdef HAS_SA_LEN >+ sin.sin_len = sizeof(sin); >+#endif > memcpy((char *) &sin.sin_addr, addr_list->addrs, sizeof(sin.sin_addr)); >- inaddr = ntohl(sin.sin_addr.s_addr); >+ inaddr = (unsigned long)ntohl(sin.sin_addr.s_addr); > if (!IN_CLASSA(inaddr) > || !(((inaddr & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET)) { > if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) >@@ -188,30 +270,85 @@ > if (msg_verbose) > msg_info("%s: bind %s", myname, inet_ntoa(sin.sin_addr)); > } >+#else >+ char hbufl[NI_MAXHOST]; >+ struct addrinfo hints, *res = NULL, *loopback = NULL; >+ >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = sa->sa_family; >+ hints.ai_socktype = SOCK_STREAM; >+ if (getaddrinfo(NULL, "0", &hints, &loopback) != 0) >+ loopback = NULL; >+ >+ /* >+ * getnameinfo -> getaddrinfo loop is here so that we can >+ * get rid of port. >+ */ >+ (void)getnameinfo((struct sockaddr *)addr_list->addrs, SA_LEN((struct sockaddr *)addr_list->addrs), >+ hbufl, sizeof(hbufl), NULL, 0, NI_NUMERICHOST); >+ hbufl[sizeof(hbufl)-1] = 0; >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = sa->sa_family; >+ hints.ai_socktype = SOCK_STREAM; >+ hints.ai_flags = AI_PASSIVE|AI_NUMERICHOST; >+ if (getaddrinfo(hbufl, NULL, &hints, &res) == 0 && >+ !(res->ai_addrlen == loopback->ai_addrlen && >+ memcmp(res->ai_addr, loopback->ai_addr, res->ai_addrlen) == 0)) { >+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) >+ msg_warn("%s: bind %s: %m", myname, hbufl); >+ if (msg_verbose) >+ msg_info("%s: bind %s", myname, hbufl); >+ } >+ if (res) >+ freeaddrinfo(res); >+ if (loopback) >+ freeaddrinfo(loopback); >+#endif > } > > /* > * Connect to the SMTP server. > */ >- sin.sin_port = port; >- memcpy((char *) &sin.sin_addr, addr->data, sizeof(sin.sin_addr)); >+ switch (addr->type) { >+#ifdef INET6 >+ case T_AAAA: >+ /* XXX scope unfriendly */ >+ memset(sin6, 0, sizeof(*sin6)); >+ sin6->sin6_port = port; >+ sin6->sin6_family = AF_INET6; >+ salen = sizeof(*sin6); >+ memcpy(&sin6->sin6_addr, addr->data, sizeof(sin6->sin6_addr)); >+ inet_ntop(AF_INET6, &sin6->sin6_addr, hbuf, sizeof(hbuf)); >+ break; >+#endif >+ default: /* T_A */ >+ memset(sin, 0, sizeof(*sin)); >+ sin->sin_port = port; >+ sin->sin_family = AF_INET; >+ salen = sizeof(*sin); >+ memcpy(&sin->sin_addr, addr->data, sizeof(sin->sin_addr)); >+ inet_ntop(AF_INET, &sin->sin_addr, hbuf, sizeof(hbuf)); >+ break; >+ } >+#ifdef HAS_SA_LEN >+ sa->sa_len = salen; >+#endif > > if (msg_verbose) > msg_info("%s: trying: %s[%s] port %d...", >- myname, addr->name, inet_ntoa(sin.sin_addr), ntohs(port)); >+ myname, addr->name, hbuf, ntohs(port)); > if (var_smtp_conn_tmout > 0) { > non_blocking(sock, NON_BLOCKING); >- conn_stat = timed_connect(sock, (struct sockaddr *) & sin, >- sizeof(sin), var_smtp_conn_tmout); >+ conn_stat = timed_connect(sock, sa, salen, var_smtp_conn_tmout); > saved_errno = errno; > non_blocking(sock, BLOCKING); > errno = saved_errno; > } else { >- conn_stat = connect(sock, (struct sockaddr *) & sin, sizeof(sin)); >+ conn_stat = connect(sock, sa, salen); > } > if (conn_stat < 0) { > vstring_sprintf(why, "connect to %s[%s]: %m", >- addr->name, inet_ntoa(sin.sin_addr)); >+ addr->name, hbuf); > smtp_errno = SMTP_RETRY; > close(sock); > return (0); >@@ -221,8 +358,8 @@ > * Skip this host if it takes no action within some time limit. > */ > if (read_wait(sock, var_smtp_helo_tmout) < 0) { >- vstring_sprintf(why, "connect to %s[%s]: read timeout", >- addr->name, inet_ntoa(sin.sin_addr)); >+ vstring_sprintf(why, "connect to %s [%s]: read timeout", >+ addr->name, hbuf); > smtp_errno = SMTP_RETRY; > close(sock); > return (0); >@@ -233,8 +370,8 @@ > */ > stream = vstream_fdopen(sock, O_RDWR); > if ((ch = VSTREAM_GETC(stream)) == VSTREAM_EOF) { >- vstring_sprintf(why, "connect to %s[%s]: server dropped connection", >- addr->name, inet_ntoa(sin.sin_addr)); >+ vstring_sprintf(why, "connect to %s [%s]: server dropped connection", >+ addr->name, hbuf); > smtp_errno = SMTP_RETRY; > vstream_fclose(stream); > return (0); >@@ -246,7 +383,7 @@ > */ > if (ch == '4' && var_smtp_skip_4xx_greeting) { > vstring_sprintf(why, "connect to %s[%s]: server refused mail service", >- addr->name, inet_ntoa(sin.sin_addr)); >+ addr->name, hbuf); > smtp_errno = SMTP_RETRY; > vstream_fclose(stream); > return (0); >@@ -257,12 +394,12 @@ > */ > if (ch == '5' && var_smtp_skip_5xx_greeting) { > vstring_sprintf(why, "connect to %s[%s]: server refused mail service", >- addr->name, inet_ntoa(sin.sin_addr)); >+ addr->name, hbuf); > smtp_errno = SMTP_RETRY; > vstream_fclose(stream); > return (0); > } >- return (smtp_session_alloc(stream, addr->name, inet_ntoa(sin.sin_addr))); >+ return (smtp_session_alloc(dest, stream, addr->name, hbuf)); > } > > /* smtp_connect_host - direct connection to host */ >@@ -272,7 +409,7 @@ > SMTP_SESSION *session = 0; > DNS_RR *addr_list; > DNS_RR *addr; >- >+ > /* > * Try each address in the specified order until we find one that works. > * The addresses belong to the same A record, so we have no information >@@ -280,7 +417,7 @@ > */ > addr_list = smtp_host_addr(host, why); > for (addr = addr_list; addr; addr = addr->next) { >- if ((session = smtp_connect_addr(addr, port, why)) != 0) { >+ if ((session = smtp_connect_addr(host, addr, port, why)) != 0) { > session->best = 1; > break; > } >@@ -309,7 +446,7 @@ > */ > addr_list = smtp_domain_addr(name, why, found_myself); > for (addr = addr_list; addr; addr = addr->next) { >- if ((session = smtp_connect_addr(addr, port, why)) != 0) { >+ if ((session = smtp_connect_addr(name, addr, port, why)) != 0) { > session->best = (addr->pref == addr_list->pref); > break; > } >@@ -379,6 +516,7 @@ > msg_fatal("unknown service: %s/%s", service, protocol); > *portp = sp->s_port; > } >+ > return (buf); > } > >diff -Pur postfix-1.1.11-20020613-orig/src/smtp/smtp_proto.c postfix-1.1.11-20020613/src/smtp/smtp_proto.c >--- postfix-1.1.11-20020613-orig/src/smtp/smtp_proto.c Sat Jun 1 15:07:27 2002 >+++ postfix-1.1.11-20020613/src/smtp/smtp_proto.c Wed Jun 26 15:26:48 2002 >@@ -103,6 +103,7 @@ > #include <quote_821_local.h> > #include <mail_proto.h> > #include <mime_state.h> >+#include <pfixtls.h> > > /* Application-specific. */ > >@@ -170,6 +171,8 @@ > char *words; > char *word; > int n; >+ int oldfeatures; >+ int rval; > > /* > * Prepare for disaster. >@@ -231,7 +234,8 @@ > session->namaddr, > translit(resp->str, "\n", " "))); > } >- >+ if (var_smtp_always_ehlo) >+ state->features |= SMTP_FEATURE_ESMTP; > /* > * Pick up some useful features offered by the SMTP server. XXX Until we > * have a portable routine to convert from string to off_t with proper >@@ -243,6 +247,7 @@ > * MicroSoft implemented AUTH based on an old draft. > */ > lines = resp->str; >+ oldfeatures = state->features; /* remember */ > while ((words = mystrtok(&lines, "\n")) != 0) { > if (mystrtok(&words, "- ") && (word = mystrtok(&words, " \t=")) != 0) { > if (strcasecmp(word, "8BITMIME") == 0) >@@ -259,6 +264,8 @@ > state->size_limit = off_cvt_string(word); > } > } >+ else if (strcasecmp(word, "STARTTLS") == 0) >+ state->features |= SMTP_FEATURE_STARTTLS; > #ifdef USE_SASL_AUTH > else if (var_smtp_sasl_enable && strcasecmp(word, "AUTH") == 0) > smtp_sasl_helo_auth(state, words); >@@ -276,6 +283,128 @@ > msg_info("server features: 0x%x size %.0f", > state->features, (double) state->size_limit); > >+#ifdef HAS_SSL >+ if ((state->features & SMTP_FEATURE_STARTTLS) && >+ (var_smtp_tls_note_starttls_offer) && >+ (!(session->tls_enforce_tls || session->tls_use_tls))) >+ msg_info("Host offered STARTTLS: [%s]", session->host); >+ if ((session->tls_enforce_tls) && >+ !(state->features & SMTP_FEATURE_STARTTLS)) >+ { >+ /* >+ * We are enforced to use TLS but it is not offered, so we will give >+ * up on this host. We won't even try STARTTLS, because we could >+ * receive a "500 command unrecognized" which would bounce the >+ * message. We instead want to delay until STARTTLS becomes >+ * available. >+ */ >+ return (smtp_site_fail(state, 450, "Could not start TLS: not offered")); >+ } >+ if ((session->tls_enforce_tls) && !pfixtls_clientengine) { >+ /* >+ * We would like to start client TLS, but our own TLS-engine is >+ * not running. >+ */ >+ return (smtp_site_fail(state, 450, >+ "Could not start TLS: our TLS-engine not running")); >+ } >+ if ((state->features & SMTP_FEATURE_STARTTLS) && >+ ((session->tls_use_tls && pfixtls_clientengine) || >+ (session->tls_enforce_tls))) { >+ /* >+ * Try to use the TLS feature >+ */ >+ smtp_chat_cmd(state, "STARTTLS"); >+ if ((resp = smtp_chat_resp(state))->code / 100 != 2) { >+ state->features &= ~SMTP_FEATURE_STARTTLS; >+ /* >+ * At this point a political decision is necessary. If we >+ * enforce usage of tls, we have to close the connection >+ * now. >+ */ >+ if (session->tls_enforce_tls) >+ return (smtp_site_fail(state, resp->code, >+ "host %s refused to start TLS: %s", >+ session->host, >+ translit(resp->str, "\n", " "))); >+ } else { >+ if (rval = pfixtls_start_clienttls(session->stream, >+ var_smtp_starttls_tmout, >+ session->tls_enforce_peername, >+ session->host, >+ &(session->tls_info))) >+ return (smtp_site_fail(state, 450, >+ "Could not start TLS: client failure")); >+ >+ >+ /* >+ * Now the connection is established and maybe we do have a >+ * validated cert with a CommonName in it. >+ * In enforce_peername state, the handshake would already have >+ * been terminated so the check here is for logging only! >+ */ >+ if (session->tls_info.peer_CN != NULL) { >+ if (!session->tls_info.peer_verified) { >+ msg_info("Peer certficate could not be verified"); >+ if (session->tls_enforce_tls) { >+ pfixtls_stop_clienttls(session->stream, >+ var_smtp_starttls_tmout, 1, >+ &(session->tls_info)); >+ return(smtp_site_fail(state, 450, "TLS-failure: Could not verify certificate")); >+ } >+ } >+ } else if (session->tls_enforce_tls) { >+ pfixtls_stop_clienttls(session->stream, >+ var_smtp_starttls_tmout, 1, >+ &(session->tls_info)); >+ return (smtp_site_fail(state, 450, "TLS-failure: Cannot verify hostname")); >+ } >+ >+ /* >+ * At this point we have to re-negotiate the "EHLO" to reget >+ * the feature-list >+ */ >+ state->features = oldfeatures; >+#ifdef USE_SASL_AUTH >+ if (state->sasl_mechanism_list) { >+ myfree(state->sasl_mechanism_list); >+ state->sasl_mechanism_list = 0; >+ } >+#endif >+ if (state->features & SMTP_FEATURE_ESMTP) { >+ smtp_chat_cmd(state, "EHLO %s", var_myhostname); >+ if ((resp = smtp_chat_resp(state))->code / 100 != 2) >+ state->features &= ~SMTP_FEATURE_ESMTP; >+ } >+ lines = resp->str; >+ (void) mystrtok(&lines, "\n"); >+ while ((words = mystrtok(&lines, "\n")) != 0) { >+ if (mystrtok(&words, "- ") && >+ (word = mystrtok(&words, " \t=")) != 0) { >+ if (strcasecmp(word, "8BITMIME") == 0) >+ state->features |= SMTP_FEATURE_8BITMIME; >+ else if (strcasecmp(word, "PIPELINING") == 0) >+ state->features |= SMTP_FEATURE_PIPELINING; >+ else if (strcasecmp(word, "SIZE") == 0) >+ state->features |= SMTP_FEATURE_SIZE; >+ else if (strcasecmp(word, "STARTTLS") == 0) >+ state->features |= SMTP_FEATURE_STARTTLS; >+#ifdef USE_SASL_AUTH >+ else if (var_smtp_sasl_enable && >+ strcasecmp(word, "AUTH") == 0) >+ smtp_sasl_helo_auth(state, words); >+#endif >+ } >+ } >+ /* >+ * Actually, at this point STARTTLS should not be offered >+ * anymore, so we could check for a protocol violation, but >+ * what should we do then? >+ */ >+ >+ } >+ } >+#endif > #ifdef USE_SASL_AUTH > if (var_smtp_sasl_enable && (state->features & SMTP_FEATURE_AUTH)) > return (smtp_sasl_helo_login(state)); >diff -Pur postfix-1.1.11-20020613-orig/src/smtp/smtp_session.c postfix-1.1.11-20020613/src/smtp/smtp_session.c >--- postfix-1.1.11-20020613-orig/src/smtp/smtp_session.c Mon Nov 20 19:06:05 2000 >+++ postfix-1.1.11-20020613/src/smtp/smtp_session.c Wed Jun 26 15:26:48 2002 >@@ -42,15 +42,42 @@ > #include <vstream.h> > #include <stringops.h> > >+#include <mail_params.h> >+#include <maps.h> >+#include <pfixtls.h> >+ > /* Application-specific. */ > > #include "smtp.h" > >+#ifdef HAS_SSL >+/* static lists */ >+static MAPS *tls_per_site; >+ >+/* smtp_tls_list_init - initialize lists */ >+ >+void smtp_tls_list_init(void) >+{ >+ tls_per_site = maps_create(VAR_SMTP_TLS_PER_SITE, var_smtp_tls_per_site, >+ DICT_FLAG_LOCK); >+} >+#endif >+ > /* smtp_session_alloc - allocate and initialize SMTP_SESSION structure */ > >-SMTP_SESSION *smtp_session_alloc(VSTREAM *stream, char *host, char *addr) >+SMTP_SESSION *smtp_session_alloc(char *dest, VSTREAM *stream, char *host, char *addr) > { > SMTP_SESSION *session; >+ const char *lookup; >+ char *lookup_key; >+ int host_dont_use = 0; >+ int host_use = 0; >+ int host_enforce = 0; >+ int host_enforce_peername = 0; >+ int recipient_dont_use = 0; >+ int recipient_use = 0; >+ int recipient_enforce = 0; >+ int recipient_enforce_peername = 0; > > session = (SMTP_SESSION *) mymalloc(sizeof(*session)); > session->stream = stream; >@@ -58,6 +85,61 @@ > session->addr = mystrdup(addr); > session->namaddr = concatenate(host, "[", addr, "]", (char *) 0); > session->best = 1; >+ session->tls_use_tls = session->tls_enforce_tls = 0; >+ session->tls_enforce_peername = 0; >+#ifdef HAS_SSL >+ lookup_key = lowercase(mystrdup(host)); >+ if (lookup = maps_find(tls_per_site, lookup_key, 0)) { >+ if (!strcasecmp(lookup, "NONE")) >+ host_dont_use = 1; >+ else if (!strcasecmp(lookup, "MAY")) >+ host_use = 1; >+ else if (!strcasecmp(lookup, "MUST")) >+ host_enforce = host_enforce_peername = 1; >+ else if (!strcasecmp(lookup, "MUST_NOPEERMATCH")) >+ host_enforce = 1; >+ else >+ msg_warn("Unknown TLS state for receiving host %s: '%s', using default policy", session->host, lookup); >+ } >+ myfree(lookup_key); >+ lookup_key = lowercase(mystrdup(dest)); >+ if (lookup = maps_find(tls_per_site, dest, 0)) { >+ if (!strcasecmp(lookup, "NONE")) >+ recipient_dont_use = 1; >+ else if (!strcasecmp(lookup, "MAY")) >+ recipient_use = 1; >+ else if (!strcasecmp(lookup, "MUST")) >+ recipient_enforce = recipient_enforce_peername = 1; >+ else if (!strcasecmp(lookup, "MUST_NOPEERMATCH")) >+ recipient_enforce = 1; >+ else >+ msg_warn("Unknown TLS state for recipient domain %s: '%s', using default policy", dest, lookup); >+ } >+ myfree(lookup_key); >+ >+ if ((var_smtp_enforce_tls && !host_dont_use && !recipient_dont_use) || host_enforce || >+ recipient_enforce) >+ session->tls_enforce_tls = session->tls_use_tls = 1; >+ >+ /* >+ * Set up peername checking. We want to make sure that a MUST* entry in >+ * the tls_per_site table always has precedence. MUST always must lead to >+ * a peername check, MUST_NOPEERMATCH must always disable it. Only when >+ * no explicit setting has been found, the default will be used. >+ * There is the case left, that both "host" and "recipient" settings >+ * conflict. In this case, the "host" setting wins. >+ */ >+ if (host_enforce && host_enforce_peername) >+ session->tls_enforce_peername = 1; >+ else if (recipient_enforce && recipient_enforce_peername) >+ session->tls_enforce_peername = 1; >+ else if (var_smtp_enforce_tls && var_smtp_tls_enforce_peername) >+ session->tls_enforce_peername = 1; >+ >+ else if ((var_smtp_use_tls && !host_dont_use && !recipient_dont_use) || host_use || recipient_use) >+ session->tls_use_tls = 1; >+#endif >+ session->tls_info = tls_info_zero; > return (session); > } > >@@ -65,6 +147,11 @@ > > void smtp_session_free(SMTP_SESSION *session) > { >+#ifdef HAS_SSL >+ vstream_fflush(session->stream); >+ pfixtls_stop_clienttls(session->stream, var_smtp_starttls_tmout, 0, >+ &(session->tls_info)); >+#endif > vstream_fclose(session->stream); > myfree(session->host); > myfree(session->addr); >diff -Pur postfix-1.1.11-20020613-orig/src/smtp/smtp_unalias.c postfix-1.1.11-20020613/src/smtp/smtp_unalias.c >--- postfix-1.1.11-20020613-orig/src/smtp/smtp_unalias.c Thu Sep 28 19:06:09 2000 >+++ postfix-1.1.11-20020613/src/smtp/smtp_unalias.c Wed Jun 26 15:26:48 2002 >@@ -86,7 +86,11 @@ > if ((result = htable_find(cache, name)) == 0) { > fqdn = vstring_alloc(10); > if (dns_lookup_types(name, smtp_unalias_flags, (DNS_RR **) 0, >- fqdn, (VSTRING *) 0, T_MX, T_A, 0) != DNS_OK) >+ fqdn, (VSTRING *) 0, T_MX, T_A, >+#ifdef INET6 >+ T_AAAA, >+#endif >+ 0) != DNS_OK) > vstring_strcpy(fqdn, name); > htable_enter(cache, name, result = vstring_export(fqdn)); > } >diff -Pur postfix-1.1.11-20020613-orig/src/smtpd/Makefile.in postfix-1.1.11-20020613/src/smtpd/Makefile.in >--- postfix-1.1.11-20020613-orig/src/smtpd/Makefile.in Tue Jun 11 03:13:44 2002 >+++ postfix-1.1.11-20020613/src/smtpd/Makefile.in Wed Jun 26 15:26:48 2002 >@@ -134,6 +134,7 @@ > smtpd.o: ../../include/quote_flags.h > smtpd.o: ../../include/lex_822.h > smtpd.o: ../../include/mail_server.h >+smtpd.o: ../../include/pfixtls.h > smtpd.o: smtpd_token.h > smtpd.o: smtpd.h > smtpd.o: smtpd_check.h >@@ -162,6 +163,7 @@ > smtpd_chat.o: ../../include/cleanup_user.h > smtpd_chat.o: ../../include/mail_error.h > smtpd_chat.o: ../../include/name_mask.h >+smtpd_chat.o: ../../include/pfixtls.h > smtpd_chat.o: smtpd.h > smtpd_chat.o: ../../include/mail_stream.h > smtpd_chat.o: smtpd_chat.h >@@ -197,6 +199,7 @@ > smtpd_check.o: ../../include/mail_addr_find.h > smtpd_check.o: ../../include/match_parent_style.h > smtpd_check.o: ../../include/strip_addr.h >+smtpd_check.o: ../../include/pfixtls.h > smtpd_check.o: smtpd.h > smtpd_check.o: ../../include/mail_stream.h > smtpd_check.o: smtpd_sasl_glue.h >@@ -213,6 +216,7 @@ > smtpd_peer.o: ../../include/vstream.h > smtpd_peer.o: ../../include/argv.h > smtpd_peer.o: ../../include/mail_stream.h >+smtpd_peer.o: ../../include/pfixtls.h > smtpd_sasl_glue.o: smtpd_sasl_glue.c > smtpd_sasl_glue.o: ../../include/sys_defs.h > smtpd_sasl_glue.o: ../../include/msg.h >@@ -266,6 +270,7 @@ > smtpd_state.o: ../../include/vstring.h > smtpd_state.o: ../../include/argv.h > smtpd_state.o: ../../include/mail_stream.h >+smtpd_state.o: ../../include/pfixtls.h > smtpd_state.o: smtpd_chat.h > smtpd_state.o: smtpd_sasl_glue.h > smtpd_token.o: smtpd_token.c >@@ -275,3 +280,4 @@ > smtpd_token.o: smtpd_token.h > smtpd_token.o: ../../include/vstring.h > smtpd_token.o: ../../include/vbuf.h >+smtpd_token.o: ../../include/pfixtls.h >diff -Pur postfix-1.1.11-20020613-orig/src/smtpd/smtpd.c postfix-1.1.11-20020613/src/smtpd/smtpd.c >--- postfix-1.1.11-20020613-orig/src/smtpd/smtpd.c Tue May 28 19:08:56 2002 >+++ postfix-1.1.11-20020613/src/smtpd/smtpd.c Wed Jun 26 15:26:48 2002 >@@ -314,6 +314,7 @@ > #include <string_list.h> > #include <quote_822_local.h> > #include <lex_822.h> >+#include <pfixtls.h> > > /* Single-threaded server skeleton. */ > >@@ -338,6 +339,7 @@ > */ > int var_smtpd_rcpt_limit; > int var_smtpd_tmout; >+char *var_relay_ccerts; > int var_smtpd_soft_erlim; > int var_smtpd_hard_erlim; > int var_queue_minfree; /* XXX use off_t */ >@@ -385,6 +387,15 @@ > char *var_smtpd_noop_cmds; > char *var_smtpd_null_key; > int var_smtpd_hist_thrsh; >+int var_smtpd_starttls_tmout; >+int var_smtpd_tls_wrappermode; >+int var_smtpd_use_tls; >+int var_smtpd_enforce_tls; >+int var_smtpd_tls_auth_only; >+int var_smtpd_tls_ask_ccert; >+int var_smtpd_tls_req_ccert; >+int var_smtpd_tls_ccert_vd; >+int var_smtpd_tls_received_header; > > /* > * Silly little macros. >@@ -489,11 +500,21 @@ > if (var_disable_vrfy_cmd == 0) > smtpd_chat_reply(state, "250-VRFY"); > smtpd_chat_reply(state, "250-ETRN"); >+#ifdef HAS_SSL >+ if ((state->tls_use_tls || state->tls_enforce_tls) && (!state->tls_active)) >+ smtpd_chat_reply(state, "250-STARTTLS"); >+#endif > #ifdef USE_SASL_AUTH > if (var_smtpd_sasl_enable) { >+#ifdef HAS_SSL >+ if (!state->tls_auth_only || state->tls_active) { >+#endif > smtpd_chat_reply(state, "250-AUTH %s", state->sasl_mechanism_list); > if (var_broken_auth_clients) > smtpd_chat_reply(state, "250-AUTH=%s", state->sasl_mechanism_list); >+#ifdef HAS_SSL >+ } >+#endif > } > #endif > smtpd_chat_reply(state, "250-%s", VERP_CMD); >@@ -918,11 +939,76 @@ > state->rcpt_count = 0; > } > >+/* CN_sanitize - make sure, the CN-string is well behaved */ >+ >+static void CN_sanitize(char *CNstring) >+{ >+ int i; >+ int len; >+ int parencount; >+ >+ /* >+ * The information included in the CN (CommonName) of the peer and its >+ * issuer can be included into the Received: header line. The characters >+ * allowed as well as comment nesting are limited by RFC822. >+ */ >+ >+ len = strlen(CNstring); >+ /* >+ * The Received: header can only contain characters. Make sure that only >+ * acceptable characters are printed. Maybe we could allow more, but >+ * not everything makes sense inside a CommonName. >+ */ >+ for (i = 0; i < len; i++) >+ if (!((CNstring[i] >= 'A') && (CNstring[i] <='Z')) && >+ !((CNstring[i] >= 'a') && (CNstring[i] <='z')) && >+ !((CNstring[i] >= '0') && (CNstring[i] <='9')) && >+ (CNstring[i] != '(') && (CNstring[i] != ')') && >+ (CNstring[i] != '[') && (CNstring[i] != ']') && >+ (CNstring[i] != '{') && (CNstring[i] != '}') && >+ (CNstring[i] != '<') && (CNstring[i] != '>') && >+ (CNstring[i] != '?') && (CNstring[i] != '!') && >+ (CNstring[i] != ';') && (CNstring[i] != ':') && >+ (CNstring[i] != '"') && (CNstring[i] != '\'') && >+ (CNstring[i] != '/') && (CNstring[i] != '|') && >+ (CNstring[i] != '+') && (CNstring[i] != '&') && >+ (CNstring[i] != '~') && (CNstring[i] != '@') && >+ (CNstring[i] != '#') && (CNstring[i] != '$') && >+ (CNstring[i] != '%') && (CNstring[i] != '&') && >+ (CNstring[i] != '^') && (CNstring[i] != '*') && >+ (CNstring[i] != '_') && (CNstring[i] != '-') && >+ (CNstring[i] != '.') && (CNstring[i] != ' ')) >+ CNstring[i] = '?'; >+ >+ /* >+ * This information will go into the Received: header inside a comment. >+ * Since comments can be nested, parentheses '(' and ')' must match. >+ */ >+ parencount = 0; >+ for (i = 0; i < len; i++) { >+ if (CNstring[i] == '(') >+ parencount++; >+ else if (CNstring[i] == ')') >+ parencount--; >+ } >+ /* >+ * The necessary condition is violated. Do YOU know, where to correct? >+ * I don't know, so I will practically remove all parentheses. >+ */ >+ if (parencount != 0) { >+ for (i = 0; i < len; i++) >+ if ((CNstring[i] == '(') || (CNstring[i] == ')')) >+ CNstring[i] = '/'; >+ } >+} >+ > /* data_cmd - process DATA command */ > > static int data_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *unused_argv) > { > char *start; >+ char *peer_CN; >+ char *issuer_CN; > int len; > int curr_rec_type; > int prev_rec_type; >@@ -961,6 +1047,35 @@ > "Received: from %s (%s [%s])", > state->helo_name ? state->helo_name : state->name, > state->name, state->addr); >+ if (var_smtpd_tls_received_header && state->tls_active) { >+ rec_fprintf(state->cleanup, REC_TYPE_NORM, >+ "\t(using %s with cipher %s (%d/%d bits))", >+ state->tls_info.protocol, state->tls_info.cipher_name, >+ state->tls_info.cipher_usebits, >+ state->tls_info.cipher_algbits); >+ if (state->tls_info.peer_CN) { >+ peer_CN = mystrdup(state->tls_info.peer_CN); >+ CN_sanitize(peer_CN); >+ issuer_CN = mystrdup(state->tls_info.issuer_CN); >+ CN_sanitize(issuer_CN); >+ if (state->tls_info.peer_verified) >+ rec_fprintf(state->cleanup, REC_TYPE_NORM, >+ "\t(Client CN \"%s\", Issuer \"%s\" (verified OK))", >+ peer_CN, issuer_CN); >+ else >+ rec_fprintf(state->cleanup, REC_TYPE_NORM, >+ "\t(Client CN \"%s\", Issuer \"%s\" (not verified))", >+ peer_CN, issuer_CN); >+ myfree(issuer_CN); >+ myfree(peer_CN); >+ } >+ else if (var_smtpd_tls_ask_ccert) >+ rec_fprintf(state->cleanup, REC_TYPE_NORM, >+ "\t(Client did not present a certificate)"); >+ else >+ rec_fprintf(state->cleanup, REC_TYPE_NORM, >+ "\t(No client certificate requested)"); >+ } > if (state->rcpt_count == 1 && state->recipient) { > rec_fprintf(state->cleanup, REC_TYPE_NORM, > "\tby %s (%s) with %s id %s", >@@ -1310,6 +1425,77 @@ > } > } > >+static int starttls_cmd(SMTPD_STATE *state, int argc, SMTPD_TOKEN *argv) >+{ >+ char *err; >+ >+#ifdef HAS_SSL >+ if (argc != 1) { >+ state->error_mask |= MAIL_ERROR_PROTOCOL; >+ smtpd_chat_reply(state, "501 Syntax: STARTTLS"); >+ return (-1); >+ } >+ if (state->tls_active != 0) { >+ state->error_mask |= MAIL_ERROR_PROTOCOL; >+ smtpd_chat_reply(state, "554 Error: TLS already active"); >+ return (-1); >+ } >+ if (state->tls_use_tls == 0) { >+ state->error_mask |= MAIL_ERROR_PROTOCOL; >+ smtpd_chat_reply(state, "502 Error: command not implemented"); >+ return (-1); >+ } >+ if (!pfixtls_serverengine) { >+ smtpd_chat_reply(state, "454 TLS not available due to temporary reason"); >+ return (0); >+ } >+ smtpd_chat_reply(state, "220 Ready to start TLS"); >+ vstream_fflush(state->client); >+ /* >+ * When deciding about continuing the handshake, we will stop when a >+ * client certificate was _required_ and none was presented or the >+ * verification failed. This however does only make sense when TLS is >+ * enforced. Otherwise we would happily perform perform the SMTP >+ * transaction without any STARTTLS at all! So only have the handshake >+ * fail when TLS is also enforced. >+ */ >+ if (pfixtls_start_servertls(state->client, var_smtpd_starttls_tmout, >+ state->name, state->addr, &(state->tls_info), >+ (var_smtpd_tls_req_ccert && state->tls_enforce_tls))) { >+ /* >+ * Typically the connection is hanging at this point, so >+ * we should try to shut it down by force! Unfortunately this >+ * problem is not addressed in postfix! >+ */ >+ return (-1); >+ } >+ state->tls_active = 1; >+ helo_reset(state); >+ mail_reset(state); >+ rcpt_reset(state); >+ return (0); >+#else >+ state->error_mask |= MAIL_ERROR_PROTOCOL; >+ smtpd_chat_reply(state, "502 Error: command not implemented"); >+ return (-1); >+#endif >+} >+ >+static void tls_reset(SMTPD_STATE *state) >+{ >+ int failure = 0; >+ >+ if (state->reason && state->where && strcmp(state->where, SMTPD_AFTER_DOT)) >+ failure = 1; >+#ifdef HAS_SSL >+ vstream_fflush(state->client); >+ if (state->tls_active) >+ pfixtls_stop_servertls(state->client, var_smtpd_starttls_tmout, >+ failure, &(state->tls_info)); >+#endif >+ state->tls_active = 0; >+} >+ > /* > * The table of all SMTP commands that we know. Set the junk limit flag on > * any command that can be repeated an arbitrary number of times without >@@ -1328,6 +1514,10 @@ > "HELO", helo_cmd, SMTPD_CMD_FLAG_LIMIT, > "EHLO", ehlo_cmd, SMTPD_CMD_FLAG_LIMIT, > >+#ifdef HAS_SSL >+ "STARTTLS", starttls_cmd, 0, >+#endif >+ > #ifdef USE_SASL_AUTH > "AUTH", smtpd_sasl_auth_cmd, 0, > #endif >@@ -1438,9 +1628,28 @@ > state->error_count++; > continue; > } >+ if (state->tls_enforce_tls && >+ !state->tls_active && >+ cmdp->action != starttls_cmd && >+ cmdp->action != noop_cmd && >+ cmdp->action != ehlo_cmd && >+ cmdp->action != quit_cmd) { >+ smtpd_chat_reply(state, >+ "530 Must issue a STARTTLS command first"); >+ state->error_count++; >+ continue; >+ } > state->where = cmdp->name; >- if (cmdp->action(state, argc, argv) != 0) >+ if (cmdp->action(state, argc, argv) != 0) { > state->error_count++; >+ /* >+ * Die after TLS negotiation failure, as there is no >+ * stable way to recover from a possible mixture of >+ * TLS and SMTP protocol from the client. >+ */ >+ if (cmdp->action == starttls_cmd) >+ break; >+ } > if ((cmdp->flags & SMTPD_CMD_FLAG_LIMIT) > && state->junk_cmds++ > var_smtpd_junk_cmd_limit) > state->error_count++; >@@ -1464,6 +1673,7 @@ > * Cleanup whatever information the client gave us during the SMTP > * dialog. > */ >+ tls_reset(state); > helo_reset(state); > #ifdef USE_SASL_AUTH > if (var_smtpd_sasl_enable) >@@ -1496,6 +1706,46 @@ > * machines. > */ > smtpd_state_init(&state, stream); >+#ifdef HAS_SSL >+ if (SMTPD_STAND_ALONE((&state))) { >+ state.tls_use_tls = 0; >+ state.tls_enforce_tls = 0; >+ state.tls_auth_only = 0; >+ } >+ else { >+ state.tls_use_tls = var_smtpd_use_tls | var_smtpd_enforce_tls; >+ state.tls_enforce_tls = var_smtpd_enforce_tls; >+ if (var_smtpd_tls_wrappermode) { >+ /* >+ * TLS has been set to wrapper mode, meaning that we run on a >+ * seperate port and we must switch to TLS layer before actually >+ * performing the SMTP protocol. This implies enforce-mode. >+ */ >+ state.tls_use_tls = state.tls_enforce_tls = 1; >+ if (pfixtls_start_servertls(state.client, var_smtpd_starttls_tmout, >+ state.name, state.addr, &state.tls_info, >+ var_smtpd_tls_req_ccert)) { >+ /* >+ * Typically the connection is hanging at this point, so >+ * we should try to shut it down by force! Unfortunately this >+ * problem is not addressed in postfix! >+ */ >+ return; >+ } >+ state.tls_active = 1; >+ } >+ if (var_smtpd_tls_auth_only || state.tls_enforce_tls) >+ state.tls_auth_only = 1; >+ } >+#else >+ state.tls_use_tls = 0; >+ state.tls_enforce_tls = 0; >+ state.tls_auth_only = 0; >+#endif >+ >+ /* >+ * Provide the SMTP service. >+ */ > > /* > * See if we need to turn on verbose logging for this client. >@@ -1513,10 +1763,6 @@ > smtpd_chat_reply(&state, "220 %s", var_smtpd_banner); > msg_info("connect from %s[%s]", state.name, state.addr); > } >- >- /* >- * Provide the SMTP service. >- */ > smtpd_proto(&state); > > /* >@@ -1542,7 +1788,6 @@ > > static void pre_jail_init(char *unused_name, char **unused_argv) > { >- > /* > * Initialize blacklist/etc. patterns before entering the chroot jail, in > * case they specify a filename pattern. >@@ -1558,6 +1803,12 @@ > msg_warn("%s is true, but SASL support is not compiled in", > VAR_SMTPD_SASL_ENABLE); > #endif >+ >+#ifdef HAS_SSL >+ if (var_smtpd_use_tls || var_smtpd_enforce_tls || var_smtpd_tls_wrappermode) >+ pfixtls_init_serverengine(var_smtpd_tls_ccert_vd, >+ var_smtpd_tls_ask_ccert); >+#endif > } > > /* main - the main program */ >@@ -1580,6 +1831,7 @@ > VAR_NON_FQDN_CODE, DEF_NON_FQDN_CODE, &var_non_fqdn_code, 0, 0, > VAR_SMTPD_JUNK_CMD, DEF_SMTPD_JUNK_CMD, &var_smtpd_junk_cmd_limit, 1, 0, > VAR_SMTPD_HIST_THRSH, DEF_SMTPD_HIST_THRSH, &var_smtpd_hist_thrsh, 1, 0, >+ VAR_SMTPD_TLS_CCERT_VD, DEF_SMTPD_TLS_CCERT_VD, &var_smtpd_tls_ccert_vd, 0, 0, > 0, > }; > static CONFIG_TIME_TABLE time_table[] = { >@@ -1595,6 +1847,13 @@ > VAR_ALLOW_UNTRUST_ROUTE, DEF_ALLOW_UNTRUST_ROUTE, &var_allow_untrust_route, > VAR_SMTPD_SASL_ENABLE, DEF_SMTPD_SASL_ENABLE, &var_smtpd_sasl_enable, > VAR_BROKEN_AUTH_CLNTS, DEF_BROKEN_AUTH_CLNTS, &var_broken_auth_clients, >+ VAR_SMTPD_TLS_WRAPPER, DEF_SMTPD_TLS_WRAPPER, &var_smtpd_tls_wrappermode, >+ VAR_SMTPD_USE_TLS, DEF_SMTPD_USE_TLS, &var_smtpd_use_tls, >+ VAR_SMTPD_ENFORCE_TLS, DEF_SMTPD_ENFORCE_TLS, &var_smtpd_enforce_tls, >+ VAR_SMTPD_TLS_AUTH_ONLY, DEF_SMTPD_TLS_AUTH_ONLY, &var_smtpd_tls_auth_only, >+ VAR_SMTPD_TLS_ACERT, DEF_SMTPD_TLS_ACERT, &var_smtpd_tls_ask_ccert, >+ VAR_SMTPD_TLS_RCERT, DEF_SMTPD_TLS_RCERT, &var_smtpd_tls_req_ccert, >+ VAR_SMTPD_TLS_RECHEAD, DEF_SMTPD_TLS_RECHEAD, &var_smtpd_tls_received_header, > 0, > }; > static CONFIG_STR_TABLE str_table[] = { >@@ -1623,6 +1882,7 @@ > VAR_SMTPD_SND_AUTH_MAPS, DEF_SMTPD_SND_AUTH_MAPS, &var_smtpd_snd_auth_maps, 0, 0, > VAR_SMTPD_NOOP_CMDS, DEF_SMTPD_NOOP_CMDS, &var_smtpd_noop_cmds, 0, 0, > VAR_SMTPD_NULL_KEY, DEF_SMTPD_NULL_KEY, &var_smtpd_null_key, 0, 0, >+ VAR_RELAY_CCERTS, DEF_RELAY_CCERTS, &var_relay_ccerts, 0, 0, > 0, > }; > >@@ -1638,3 +1898,4 @@ > MAIL_SERVER_PRE_ACCEPT, pre_accept, > 0); > } >+ >diff -Pur postfix-1.1.11-20020613-orig/src/smtpd/smtpd.h postfix-1.1.11-20020613/src/smtpd/smtpd.h >--- postfix-1.1.11-20020613-orig/src/smtpd/smtpd.h Fri Mar 29 22:10:13 2002 >+++ postfix-1.1.11-20020613/src/smtpd/smtpd.h Wed Jun 26 15:26:48 2002 >@@ -32,6 +32,7 @@ > * Global library. > */ > #include <mail_stream.h> >+#include <pfixtls.h> > > /* > * Variables that keep track of conversation state. There is only one SMTP >@@ -81,6 +82,11 @@ > VSTRING *sasl_decoded; > #endif > int warn_if_reject; >+ int tls_active; >+ int tls_use_tls; >+ int tls_enforce_tls; >+ int tls_auth_only; >+ tls_info_t tls_info; > } SMTPD_STATE; > > extern void smtpd_state_init(SMTPD_STATE *, VSTREAM *); >diff -Pur postfix-1.1.11-20020613-orig/src/smtpd/smtpd_check.c postfix-1.1.11-20020613/src/smtpd/smtpd_check.c >--- postfix-1.1.11-20020613-orig/src/smtpd/smtpd_check.c Mon Jun 10 22:14:39 2002 >+++ postfix-1.1.11-20020613/src/smtpd/smtpd_check.c Wed Jun 26 15:26:48 2002 >@@ -280,6 +280,7 @@ > > #include <namadr_list.h> > #include <domain_list.h> >+#include <string_list.h> > #include <mail_params.h> > #include <canon_addr.h> > #include <resolve_clnt.h> >@@ -345,6 +346,9 @@ > static DOMAIN_LIST *relay_domains; > static NAMADR_LIST *mynetworks; > static NAMADR_LIST *perm_mx_networks; >+#ifdef HAS_SSL >+static MAPS *relay_ccerts; >+#endif > > /* > * How to do parent domain wildcard matching, if any. >@@ -530,6 +534,10 @@ > perm_mx_networks = > namadr_list_init(match_parent_style(VAR_PERM_MX_NETWORKS), > var_perm_mx_networks); >+#ifdef HAS_SSL >+ relay_ccerts = maps_create(VAR_RELAY_CCERTS, var_relay_ccerts, >+ DICT_FLAG_LOCK); >+#endif > > /* > * Pre-parse and pre-open the recipient maps. >@@ -932,7 +940,11 @@ > msg_info("%s: %s", myname, name); > > dns_status = dns_lookup_types(name, 0, (DNS_RR **) 0, (VSTRING *) 0, >- (VSTRING *) 0, T_A, T_MX, 0); >+ (VSTRING *) 0, T_A, T_MX, >+#ifdef INET6 >+ T_AAAA, >+#endif >+ 0); > if (dns_status != DNS_OK) > return (smtpd_check_reject(state, MAIL_ERROR_POLICY, > "%d <%s>: %s rejected: Host not found", >@@ -954,7 +966,11 @@ > msg_info("%s: %s", myname, name); > > dns_status = dns_lookup_types(name, 0, (DNS_RR **) 0, (VSTRING *) 0, >- (VSTRING *) 0, T_A, T_MX, 0); >+ (VSTRING *) 0, T_A, T_MX, >+#ifdef INET6 >+ T_AAAA, >+#endif >+ 0); > if (dns_status != DNS_OK) > return (smtpd_check_reject(state, MAIL_ERROR_POLICY, > "%d <%s>: %s rejected: Domain not found", >@@ -966,6 +982,36 @@ > > static int permit_auth_destination(SMTPD_STATE *state, char *recipient); > >+/* permit_tls_clientcerts - OK/DUNNO for message relaying */ >+ >+#ifdef HAS_SSL >+static int permit_tls_clientcerts(SMTPD_STATE *state, int permit_all_certs) >+{ >+ char *low_name; >+ const char *found; >+ >+ if (state->tls_info.peer_verified && permit_all_certs) { >+ if (msg_verbose) >+ msg_info("Relaying allowed for all verified client certificates"); >+ return(SMTPD_CHECK_OK); >+ } >+ >+ if (state->tls_info.peer_verified && state->tls_info.peer_fingerprint) { >+ low_name = lowercase(mystrdup(state->tls_info.peer_fingerprint)); >+ found = maps_find(relay_ccerts, low_name, DICT_FLAG_FIXED); >+ myfree(low_name); >+ if (found) { >+ if (msg_verbose) >+ msg_info("Relaying allowed for certified client: %s", found); >+ return (SMTPD_CHECK_OK); >+ } else if (msg_verbose) >+ msg_info("relay_clientcerts: No match for fingerprint '%s'", >+ state->tls_info.peer_fingerprint); >+ } >+ return (SMTPD_CHECK_DUNNO); >+} >+#endif >+ > /* check_relay_domains - OK/FAIL for message relaying */ > > static int check_relay_domains(SMTPD_STATE *state, char *recipient, >@@ -1145,6 +1191,49 @@ > > static int has_my_addr(const char *host) > { >+#ifdef INET6 >+ char *myname = "has_my_addr"; >+ struct addrinfo hints, *res, *res0; >+ int error; >+ char hbuf[NI_MAXHOST]; >+ >+ if (msg_verbose) >+ msg_info("%s: host %s", myname, host); >+ >+ /* >+ * If we can't lookup the host, play safe and assume it is OK. >+ */ >+#define YUP 1 >+#define NOPE 0 >+ >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = PF_UNSPEC; >+ hints.ai_socktype = SOCK_DGRAM; >+ error = getaddrinfo(host, NULL, &hints, &res0); >+ if (error) { >+ if (msg_verbose) >+ msg_info("%s: host %s: %s", myname, host, gai_strerror(error)); >+ return (YUP); >+ } >+ for (res = res0; res; res = res->ai_next) { >+ if (msg_verbose) { >+ if (getnameinfo(res->ai_addr, res->ai_addrlen, hbuf, sizeof(hbuf), >+ NULL, 0, NI_NUMERICHOST)) { >+ strncpy(hbuf, "???", sizeof(hbuf)); >+ } >+ msg_info("%s: addr %s", myname, hbuf); >+ } >+ if (own_inet_addr(res->ai_addr)) { >+ freeaddrinfo(res0); >+ return (YUP); >+ } >+ } >+ freeaddrinfo(res0); >+ if (msg_verbose) >+ msg_info("%s: host %s: no match", myname, host); >+ >+ return (NOPE); >+#else > char *myname = "has_my_addr"; > struct in_addr addr; > char **cpp; >@@ -1180,6 +1269,7 @@ > msg_info("%s: host %s: no match", myname, host); > > return (NOPE); >+#endif > } > > /* i_am_mx - is this machine listed as MX relay */ >@@ -1834,7 +1924,7 @@ > static int reject_maps_rbl(SMTPD_STATE *state) > { > char *myname = "reject_maps_rbl"; >- ARGV *octets = argv_split(state->addr, "."); >+ ARGV *octets; > VSTRING *query = vstring_alloc(100); > char *saved_domains = mystrdup(var_maps_rbl_domains); > char *bp = saved_domains; >@@ -1846,17 +1936,29 @@ > int dns_status = DNS_FAIL; > int i; > int result; >+ struct in_addr a; > VSTRING *why; > > if (msg_verbose) > msg_info("%s: %s", myname, state->addr); > >- /* >- * IPv4 only for now >- */ >-#ifdef INET6 >+#ifndef INET6 >+ /* IPv4 only for now */ > if (inet_pton(AF_INET, state->addr, &a) != 1) > return SMTPD_CHECK_DUNNO; >+ octets = argv_split(state->addr, "."); >+#else >+ /* IPv4 and IPv6-mapped IPv4 only for now */ >+ if (inet_pton(AF_INET, state->addr, &a) == 1) >+ octets = argv_split(state->addr, "."); >+ else { >+ struct in6_addr a6; >+ if (inet_pton(AF_INET6, state->addr, &a6) != 1) >+ return SMTPD_CHECK_DUNNO; >+ if (!IN6_IS_ADDR_V4MAPPED(&a6) || (strrchr(state->addr,':') == NULL)) >+ return SMTPD_CHECK_DUNNO; >+ octets = argv_split(strrchr(state->addr,':')+1, "."); >+ } > #endif > > /* >@@ -2154,6 +2256,12 @@ > #else > msg_warn("restriction `%s' ignored: no SASL support", name); > #endif >+#ifdef HAS_SSL >+ } else if (strcasecmp(name, PERMIT_TLS_ALL_CLIENTCERTS) == 0) { >+ status = permit_tls_clientcerts(state, 1); >+ } else if (strcasecmp(name, PERMIT_TLS_CLIENTCERTS) == 0) { >+ status = permit_tls_clientcerts(state, 0); >+#endif > } else if (strcasecmp(name, REJECT_UNKNOWN_RCPTDOM) == 0) { > if (state->recipient) > status = reject_unknown_address(state, state->recipient, >@@ -2588,6 +2696,7 @@ > char *var_rcpt_checks = ""; > char *var_etrn_checks = ""; > char *var_relay_domains = ""; >+char *var_relay_ccerts = ""; > char *var_mynetworks = ""; > char *var_notify_classes = ""; > >diff -Pur postfix-1.1.11-20020613-orig/src/smtpd/smtpd_peer.c postfix-1.1.11-20020613/src/smtpd/smtpd_peer.c >--- postfix-1.1.11-20020613-orig/src/smtpd/smtpd_peer.c Thu Jul 5 22:09:47 2001 >+++ postfix-1.1.11-20020613/src/smtpd/smtpd_peer.c Wed Jun 26 15:26:48 2002 >@@ -63,6 +63,15 @@ > #include <netdb.h> > #include <string.h> > >+/* Utility library. */ >+ >+#include <msg.h> >+#include <mymalloc.h> >+#include <valid_hostname.h> >+#include <stringops.h> >+ >+/* Global library. */ >+ > /* > * Older systems don't have h_errno. Even modern systems don't have > * hstrerror(). >@@ -84,16 +93,11 @@ > ) > #endif > >-/* Utility library. */ >- >-#include <msg.h> >-#include <mymalloc.h> >-#include <valid_hostname.h> >-#include <stringops.h> >- >-/* Global library. */ >- >- >+#ifdef INET6 >+#define GAI_STRERROR(error) \ >+ ((error = EAI_SYSTEM) ? gai_strerror(error) : strerror(errno)) >+#endif >+ > /* Application-specific. */ > > #include "smtpd.h" >@@ -102,16 +106,23 @@ > > void smtpd_peer_init(SMTPD_STATE *state) > { >- struct sockaddr_in sin; >- SOCKADDR_SIZE len = sizeof(sin); >+#ifdef INET6 >+ struct sockaddr_storage ss; >+#else >+ struct sockaddr ss; >+ struct in_addr *in; > struct hostent *hp; >- int i; >+#endif >+ struct sockaddr *sa; >+ SOCKADDR_SIZE len; >+ >+ sa = (struct sockaddr *)&ss; >+ len = sizeof(ss); > > /* > * Look up the peer address information. > */ >- if (getpeername(vstream_fileno(state->client), >- (struct sockaddr *) & sin, &len) >= 0) { >+ if (getpeername(vstream_fileno(state->client), sa, &len) >= 0) { > errno = 0; > } > >@@ -127,18 +138,51 @@ > /* > * Look up and "verify" the client hostname. > */ >- else if (errno == 0 && sin.sin_family == AF_INET) { >- state->addr = mystrdup(inet_ntoa(sin.sin_addr)); >- hp = gethostbyaddr((char *) &(sin.sin_addr), >- sizeof(sin.sin_addr), AF_INET); >- if (hp == 0) { >+ else if (errno == 0 && (sa->sa_family == AF_INET >+#ifdef INET6 >+ || sa->sa_family == AF_INET6 >+#endif >+ )) { >+#ifdef INET6 >+ char hbuf[NI_MAXHOST]; >+ char abuf[NI_MAXHOST]; >+ struct addrinfo hints, *rnull = NULL; >+#else >+ char abuf[sizeof("255.255.255.255") + 1]; >+ char *hbuf; >+#endif >+ int error = -1; >+ >+#ifdef INET6 >+ (void)getnameinfo(sa, len, abuf, sizeof(hbuf), NULL, 0, NI_NUMERICHOST); >+#else >+ in = &((struct sockaddr_in *)sa)->sin_addr; >+ inet_ntop(AF_INET, in, abuf, sizeof(hbuf)); >+#endif >+ state->addr = mystrdup(abuf); >+#ifdef INET6 >+ error = getnameinfo(sa, len, hbuf, sizeof(hbuf), NULL, 0, NI_NAMEREQD); >+#else >+ hbuf = NULL; >+ hp = gethostbyaddr((char *)in, sizeof(*in), AF_INET); >+ if (hp) { >+ error = 0; >+ hbuf = mystrdup(hp->h_name); >+ } else >+ error = 1; >+#endif >+ if (error) { > state->name = mystrdup("unknown"); >+#ifdef INET6 >+ state->peer_code = (error == EAI_AGAIN ? 4 : 5); >+#else > state->peer_code = (h_errno == TRY_AGAIN ? 4 : 5); >- } else if (!valid_hostname(hp->h_name, DONT_GRIPE)) { >+#endif >+ } else if (!valid_hostname(hbuf, DONT_GRIPE)) { > state->name = mystrdup("unknown"); > state->peer_code = 5; > } else { >- state->name = mystrdup(hp->h_name); /* hp->name is clobbered!! */ >+ state->name = mystrdup(hbuf); /* hp->name is clobbered!! */ > state->peer_code = 2; > > /* >@@ -150,16 +194,31 @@ > state->peer_code = code; \ > } > >+#ifdef INET6 >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = AF_UNSPEC; >+ hints.ai_socktype = SOCK_STREAM; >+ error = getaddrinfo(state->name, NULL, &hints, &rnull); >+ if (error) { >+ msg_warn("%s: hostname %s verification failed: %s", >+ state->addr, state->name, GAI_STRERROR(error)); >+ REJECT_PEER_NAME(state, (error == EAI_AGAIN ? 4 : 5)); >+ } >+ /* memcmp() isn't needed if we use getaddrinfo */ >+ if (rnull) >+ freeaddrinfo(rnull); >+#else > hp = gethostbyname(state->name); /* clobbers hp->name!! */ > if (hp == 0) { > msg_warn("%s: hostname %s verification failed: %s", > state->addr, state->name, HSTRERROR(h_errno)); > REJECT_PEER_NAME(state, (h_errno == TRY_AGAIN ? 4 : 5)); >- } else if (hp->h_length != sizeof(sin.sin_addr)) { >+ } else if (hp->h_length != sizeof(*in)) { > msg_warn("%s: hostname %s verification failed: bad address size %d", > state->addr, state->name, hp->h_length); > REJECT_PEER_NAME(state, 5); > } else { >+ int i; > for (i = 0; /* void */ ; i++) { > if (hp->h_addr_list[i] == 0) { > msg_warn("%s: address not listed for hostname %s", >@@ -167,12 +226,11 @@ > REJECT_PEER_NAME(state, 5); > break; > } >- if (memcmp(hp->h_addr_list[i], >- (char *) &sin.sin_addr, >- sizeof(sin.sin_addr)) == 0) >+ if (memcmp(hp->h_addr_list[i], (char *)in, sizeof(*in)) == 0) > break; /* keep peer name */ > } > } >+#endif > } > } > >diff -Pur postfix-1.1.11-20020613-orig/src/smtpd/smtpd_sasl_proto.c postfix-1.1.11-20020613/src/smtpd/smtpd_sasl_proto.c >--- postfix-1.1.11-20020613-orig/src/smtpd/smtpd_sasl_proto.c Tue Sep 12 00:45:40 2000 >+++ postfix-1.1.11-20020613/src/smtpd/smtpd_sasl_proto.c Wed Jun 26 15:26:48 2002 >@@ -128,6 +128,13 @@ > smtpd_chat_reply(state, "503 Error: authentication not enabled"); > return (-1); > } >+#ifdef HAS_SSL >+ if (state->tls_auth_only && !state->tls_active) { >+ state->error_mask |= MAIL_ERROR_PROTOCOL; >+ smtpd_chat_reply(state, "538 Encryption required for requested authentication mechanism"); >+ return (-1); >+ } >+#endif > if (state->sasl_username) { > state->error_mask |= MAIL_ERROR_PROTOCOL; > smtpd_chat_reply(state, "503 Error: already authenticated"); >diff -Pur postfix-1.1.11-20020613-orig/src/smtpd/smtpd_state.c postfix-1.1.11-20020613/src/smtpd/smtpd_state.c >--- postfix-1.1.11-20020613-orig/src/smtpd/smtpd_state.c Tue Nov 6 18:35:40 2001 >+++ postfix-1.1.11-20020613/src/smtpd/smtpd_state.c Wed Jun 26 15:26:48 2002 >@@ -92,6 +92,11 @@ > state->msg_size = 0; > state->junk_cmds = 0; > state->warn_if_reject = 0; >+ state->tls_active = 0; >+ state->tls_use_tls = 0; >+ state->tls_enforce_tls = 0; >+ state->tls_info = tls_info_zero; >+ state->tls_auth_only = 0; > > #ifdef USE_SASL_AUTH > if (SMTPD_STAND_ALONE(state)) >diff -Pur postfix-1.1.11-20020613-orig/src/smtpstone/smtp-sink.c postfix-1.1.11-20020613/src/smtpstone/smtp-sink.c >--- postfix-1.1.11-20020613-orig/src/smtpstone/smtp-sink.c Sat Jun 8 20:21:41 2002 >+++ postfix-1.1.11-20020613/src/smtpstone/smtp-sink.c Wed Jun 26 15:26:48 2002 >@@ -518,7 +518,7 @@ > } else { > if (strncmp(argv[optind], "inet:", 5) == 0) > argv[optind] += 5; >- sock = inet_listen(argv[optind], backlog, BLOCKING); >+ sock = inet_listen(argv[optind], backlog, BLOCKING, 1); > } > > /* >diff -Pur postfix-1.1.11-20020613-orig/src/tlsmgr/Makefile.in postfix-1.1.11-20020613/src/tlsmgr/Makefile.in >--- postfix-1.1.11-20020613-orig/src/tlsmgr/Makefile.in Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/tlsmgr/Makefile.in Wed Jun 26 15:26:48 2002 >@@ -0,0 +1,75 @@ >+SHELL = /bin/sh >+SRCS = tlsmgr.c >+OBJS = tlsmgr.o >+HDRS = >+TESTSRC = >+WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ >+ -Wparentheses -Wstrict-prototypes -Wswitch -Wuninitialized \ >+ -Wunused >+DEFS = -I. -I$(INC_DIR) -D$(SYSTYPE) >+CFLAGS = $(DEBUG) $(OPT) $(DEFS) >+TESTPROG= >+PROG = tlsmgr >+INC_DIR = ../../include >+LIBS = ../../lib/libmaster.a ../../lib/libglobal.a ../../lib/libutil.a >+ >+.c.o:; $(CC) $(CFLAGS) -c $*.c >+ >+$(PROG): $(OBJS) $(LIBS) >+ $(CC) $(CFLAGS) -o $@ $(OBJS) $(LIBS) $(SYSLIBS) >+ >+Makefile: Makefile.in >+ (set -e; echo "# DO NOT EDIT"; $(OPTS) $(SHELL) ../../makedefs; cat $?) >$@ >+ >+test: $(TESTPROG) >+ >+update: ../../libexec/$(PROG) >+ >+../../libexec/$(PROG): $(PROG) >+ cp $(PROG) ../../libexec >+ >+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 *core $(PROG) $(TESTPROG) junk >+ rm -rf printfck >+ >+tidy: clean >+ >+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 | sed -n -e '/^# *1 *"\([^"]*\)".*/{' \ >+ -e 's//'`echo $$i|sed 's/c$$/o/'`': \1/' -e 'p' -e '}'; \ >+ done) | grep -v '[.][o][:][ ][/]' >$$$$ && mv $$$$ Makefile.in >+ @make -f Makefile.in Makefile >+ >+# do not edit below this line - it is generated by 'make depend' >+tlsmgr.o: tlsmgr.c >+tlsmgr.o: ../../include/sys_defs.h >+tlsmgr.o: ../../include/msg.h >+tlsmgr.o: ../../include/events.h >+tlsmgr.o: ../../include/vstream.h >+tlsmgr.o: ../../include/vbuf.h >+tlsmgr.o: ../../include/dict.h >+tlsmgr.o: ../../include/argv.h >+tlsmgr.o: ../../include/vstring.h >+tlsmgr.o: ../../include/stringops.h >+tlsmgr.o: ../../include/mymalloc.h >+tlsmgr.o: ../../include/connect.h >+tlsmgr.o: ../../include/myflock.h >+tlsmgr.o: ../../include/mail_conf.h >+tlsmgr.o: ../../include/mail_params.h >+tlsmgr.o: ../../include/iostuff.h >+tlsmgr.o: ../../include/master_proto.h >+tlsmgr.o: ../../include/mail_server.h >+tlsmgr.o: ../../include/pfixtls.h >diff -Pur postfix-1.1.11-20020613-orig/src/tlsmgr/tlsmgr.c postfix-1.1.11-20020613/src/tlsmgr/tlsmgr.c >--- postfix-1.1.11-20020613-orig/src/tlsmgr/tlsmgr.c Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/tlsmgr/tlsmgr.c Wed Jun 26 15:26:48 2002 >@@ -0,0 +1,598 @@ >+/*++ >+/* NAME >+/* tlsmgr 8 >+/* SUMMARY >+/* Postfix TLS session cache and PRNG handling manager >+/* SYNOPSIS >+/* \fBtlsmgr\fR [generic Postfix daemon options] >+/* DESCRIPTION >+/* The tlsmgr process does housekeeping on the session cache database >+/* files. It runs through the databases and removes expired entries >+/* and entries written by older (incompatible) versions. >+/* >+/* The tlsmgr is responsible for the PRNG handling. The used internal >+/* OpenSSL PRNG has a pool size of 8192 bits (= 1024 bytes). The pool >+/* is initially seeded at startup from an external source (EGD or >+/* /dev/urandom) and additional seed is obtained later during program >+/* run at a configurable period. The exact time of seed query is >+/* using random information and is equally distributed in the range of >+/* [0-\fBtls_random_reseed_period\fR] with a \fBtls_random_reseed_period\fR >+/* having a default of 1 hour. >+/* >+/* Tlsmgr can be run chrooted and with dropped privileges, as it will >+/* connect to the entropy source at startup. >+/* >+/* The PRNG is additionally seeded internally by the data found in the >+/* session cache and timevalues. >+/* >+/* Tlsmgr reads the old value of the exchange file at startup to keep >+/* entropy already collected during previous runs. >+/* >+/* From the PRNG random pool a cryptographically strong 1024 byte random >+/* sequence is written into the PRNG exchange file. The file is updated >+/* periodically with the time changing randomly from >+/* [0-\fBtls_random_prng_update_period\fR]. >+/* STANDARDS >+/* SECURITY >+/* .ad >+/* .fi >+/* Tlsmgr is not security-sensitive. It only deals with external data >+/* to be fed into the PRNG, the contents is never trusted. The session >+/* cache housekeeping will only remove entries if expired and will never >+/* touch the contents of the cached data. >+/* DIAGNOSTICS >+/* Problems and transactions are logged to the syslog daemon. >+/* BUGS >+/* There is no automatic means to limit the number of entries in the >+/* session caches and/or the size of the session cache files. >+/* CONFIGURATION PARAMETERS >+/* .ad >+/* .fi >+/* The following \fBmain.cf\fR parameters are especially relevant to >+/* this program. See the Postfix \fBmain.cf\fR file for syntax details >+/* and for default values. Use the \fBpostfix reload\fR command after >+/* a configuration change. >+/* .SH Session Cache >+/* .ad >+/* .fi >+/* .IP \fBsmtpd_tls_session_cache_database\fR >+/* Name of the SDBM file (type sdbm:) containing the SMTP server session >+/* cache. If the file does not exist, it is created. >+/* .IP \fBsmtpd_tls_session_cache_timeout\fR >+/* Expiry time of SMTP server session cache entries in seconds. Entries >+/* older than this are removed from the session cache. A cleanup-run is >+/* performed periodically every \fBsmtpd_tls_session_cache_timeout\fR >+/* seconds. Default is 3600 (= 1 hour). >+/* .IP \fBsmtp_tls_session_cache_database\fR >+/* Name of the SDBM file (type sdbm:) containing the SMTP client session >+/* cache. If the file does not exist, it is created. >+/* .IP \fBsmtp_tls_session_cache_timeout\fR >+/* Expiry time of SMTP client session cache entries in seconds. Entries >+/* older than this are removed from the session cache. A cleanup-run is >+/* performed periodically every \fBsmtp_tls_session_cache_timeout\fR >+/* seconds. Default is 3600 (= 1 hour). >+/* .SH Pseudo Random Number Generator >+/* .ad >+/* .fi >+/* .IP \fBtls_random_source\fR >+/* Name of the EGD socket or device or regular file to obtain entropy >+/* from. The type of entropy source must be specified by preceding the >+/* name with the appropriate type: egd:/path/to/egd_socket, >+/* dev:/path/to/devicefile, or /path/to/regular/file. >+/* tlsmgr opens \fBtls_random_source\fR and tries to read >+/* \fBtls_random_bytes\fR from it. >+/* .IP \fBtls_random_bytes\fR >+/* Number of bytes to be read from \fBtls_random_source\fR. >+/* Default value is 32 bytes. If using EGD, a maximum of 255 bytes is read. >+/* .IP \fBtls_random_exchange_name\fR >+/* Name of the file written by tlsmgr and read by smtp and smtpd at >+/* startup. The length is 1024 bytes. Default value is >+/* /etc/postfix/prng_exch. >+/* .IP \fBtls_random_reseed_period\fR >+/* Time in seconds until the next reseed from external sources is due. >+/* This is the maximum value. The actual point in time is calculated >+/* with a random factor equally distributed between 0 and this maximum >+/* value. Default is 3600 (= 60 minutes). >+/* .IP \fBtls_random_prng_update_period\fR >+/* Time in seconds until the PRNG exchange file is updated with new >+/* pseude random values. This is the maximum value. The actual point >+/* in time is calculated with a random factor equally distributed >+/* between 0 and this maximum value. Default is 60 (= 1 minute). >+/* SEE ALSO >+/* smtp(8) SMTP client >+/* smtpd(8) SMTP server >+/* LICENSE >+/* .ad >+/* .fi >+/* The Secure Mailer license must be distributed with this software. >+/* AUTHOR(S) >+/*--*/ >+ >+/* System library. */ >+ >+#include <sys_defs.h> >+#include <stdlib.h> >+#include <unistd.h> >+#include <ctype.h> >+#include <errno.h> >+#include <string.h> >+#include <sys/time.h> /* gettimeofday, not POSIX */ >+ >+/* OpenSSL library. */ >+#ifdef HAS_SSL >+#include <openssl/rand.h> /* For the PRNG */ >+#endif >+ >+/* Utility library. */ >+ >+#include <msg.h> >+#include <events.h> >+#include <dict.h> >+#include <stringops.h> >+#include <mymalloc.h> >+#include <connect.h> >+#include <myflock.h> >+ >+/* Global library. */ >+ >+#include <mail_conf.h> >+#include <mail_params.h> >+#include <pfixtls.h> >+ >+/* Master process interface */ >+ >+#include <master_proto.h> >+#include <mail_server.h> >+ >+/* Application-specific. */ >+ >+ /* >+ * Tunables. >+ */ >+char *var_tls_rand_source; >+int var_tls_rand_bytes; >+int var_tls_reseed_period; >+int var_tls_prng_upd_period; >+ >+static int rand_exch_fd; >+static int rand_source_dev_fd = -1; >+static int rand_source_socket_fd = -1; >+static int srvr_scache_db_active; >+static int clnt_scache_db_active; >+static DICT *srvr_scache_db = NULL; >+static DICT *clnt_scache_db = NULL; >+ >+static void tlsmgr_prng_upd_event(int unused_event, char *dummy) >+{ >+ struct timeval tv; >+ unsigned char buffer[1024]; >+ int next_period; >+ >+#ifdef HAS_SSL >+ /* >+ * It is time to update the PRNG exchange file. Since other processes might >+ * have added entropy, we do this in a read_stir-back_write cycle. >+ */ >+ GETTIMEOFDAY(&tv); >+ RAND_seed(&tv, sizeof(struct timeval)); >+ >+ if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) != 0) >+ msg_fatal("Could not lock random exchange file: %s", >+ strerror(errno)); >+ >+ lseek(rand_exch_fd, 0, SEEK_SET); >+ if (read(rand_exch_fd, buffer, 1024) < 0) >+ msg_fatal("reading exchange file failed"); >+ RAND_seed(buffer, 1024); >+ >+ RAND_bytes(buffer, 1024); >+ lseek(rand_exch_fd, 0, SEEK_SET); >+ if (write(rand_exch_fd, buffer, 1024) != 1024) >+ msg_fatal("Writing exchange file failed"); >+ >+ if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) != 0) >+ msg_fatal("Could not unlock random exchange file: %s", >+ strerror(errno)); >+ >+ /* >+ * Make prediction difficult for outsiders and calculate the time for the >+ * next execution randomly. >+ */ >+ next_period = (var_tls_prng_upd_period * buffer[0]) / 255; >+ event_request_timer(tlsmgr_prng_upd_event, dummy, next_period); >+#endif >+} >+ >+ >+static void tlsmgr_reseed_event(int unused_event, char *dummy) >+{ >+ int egd_success; >+ int next_period; >+ int rand_bytes; >+ char buffer[255]; >+ struct timeval tv; >+ unsigned char randbyte; >+ >+#ifdef HAS_SSL >+ /* >+ * It is time to reseed the PRNG. >+ */ >+ >+ GETTIMEOFDAY(&tv); >+ RAND_seed(&tv, sizeof(struct timeval)); >+ if (rand_source_dev_fd != -1) { >+ rand_bytes = read(rand_source_dev_fd, buffer, var_tls_rand_bytes); >+ if (rand_bytes > 0) >+ RAND_seed(buffer, rand_bytes); >+ else if (rand_bytes < 0) { >+ msg_fatal("Read from entropy device %s failed", >+ var_tls_rand_source); >+ } >+ } else if (rand_source_socket_fd != -1) { >+ egd_success = 0; >+ buffer[0] = 1; >+ buffer[1] = var_tls_rand_bytes; >+ if (write(rand_source_socket_fd, buffer, 2) != 2) >+ msg_info("Could not talk to %s", var_tls_rand_source); >+ else if (read(rand_source_socket_fd, buffer, 1) != 1) >+ msg_info("Could not read info from %s", var_tls_rand_source); >+ else { >+ rand_bytes = buffer[0]; >+ if (read(rand_source_socket_fd, buffer, rand_bytes) != rand_bytes) >+ msg_info("Could not read data from %s", var_tls_rand_source); >+ else { >+ egd_success = 1; >+ RAND_seed(buffer, rand_bytes); >+ } >+ } >+ if (!egd_success) { >+ msg_info("Lost connection to EGD-device, exiting to reconnect."); >+ exit(0); >+ } >+ } else if (*var_tls_rand_source) { >+ rand_bytes = RAND_load_file(var_tls_rand_source, var_tls_rand_bytes); >+ } >+ >+ /* >+ * Make prediction difficult for outsiders and calculate the time for the >+ * next execution randomly. >+ */ >+ RAND_bytes(&randbyte, 1); >+ next_period = (var_tls_reseed_period * randbyte) / 255; >+ event_request_timer(tlsmgr_reseed_event, dummy, next_period); >+#endif >+} >+ >+ >+static int tlsmgr_do_scache_check(DICT *scache_db, int scache_timeout, >+ int start) >+{ >+#ifdef HAS_SSL >+ int func; >+ int len; >+ int n; >+ int delete = 0; >+ int result; >+ struct timeval tv; >+ const char *member; >+ const char *value; >+ char *member_copy; >+ unsigned char nibble, *data; >+ pfixtls_scache_info_t scache_info; >+ >+ GETTIMEOFDAY(&tv); >+ RAND_seed(&tv, sizeof(struct timeval)); >+ >+ /* >+ * Run through the given dictionary and check the stored sessions. >+ * If "start" is set to 1, a new run is initiated, otherwise the next >+ * item is accessed. The state is internally kept in the DICT. >+ */ >+ if (start) >+ func = DICT_SEQ_FUN_FIRST; >+ else >+ func = DICT_SEQ_FUN_NEXT; >+ result = dict_seq(scache_db, func, &member, &value); >+ >+ if (result > 0) >+ return 0; /* End of list reached */ >+ else if (result < 0) >+ msg_fatal("Database fault, should already be caught."); >+ else { >+ member_copy = mystrdup(member); >+ len = strlen(value); >+ RAND_seed(value, len); /* Use it to increase entropy */ >+ if (len < 2 * sizeof(pfixtls_scache_info_t)) >+ delete = 1; /* Messed up, delete */ >+ else if (len > 2 * sizeof(pfixtls_scache_info_t)) >+ len = 2 * sizeof(pfixtls_scache_info_t); >+ if (!delete) { >+ data = (unsigned char *)(&scache_info); >+ memset(data, 0, len / 2); >+ for (n = 0; n < len; n++) { >+ if ((value[n] >= '0') && (value[n] <= '9')) >+ nibble = value[n] - '0'; >+ else >+ nibble = value[n] - 'A' + 10; >+ if (n % 2) >+ data[n / 2] |= nibble; >+ else >+ data[n / 2] |= (nibble << 4); >+ } >+ >+ if ((scache_info.scache_db_version != scache_db_version) || >+ (scache_info.openssl_version != openssl_version) || >+ (scache_info.timestamp + scache_timeout < time(NULL))) >+ delete = 1; >+ } >+ if (delete) >+ result = dict_del(scache_db, member_copy); >+ myfree(member_copy); >+ } >+ >+ if (delete && result) >+ msg_info("Could not delete %s", member); >+ return 1; >+ >+#else >+ return 0; >+#endif >+} >+ >+static void tlsmgr_clnt_cache_run_event(int unused_event, char *dummy) >+{ >+ >+ /* >+ * This routine runs when it is time for another tls session cache scan. >+ * Make sure this routine gets called again in the future. >+ */ >+ clnt_scache_db_active = tlsmgr_do_scache_check(clnt_scache_db, >+ var_smtp_tls_scache_timeout, 1); >+ event_request_timer(tlsmgr_clnt_cache_run_event, dummy, >+ var_smtp_tls_scache_timeout); >+} >+ >+ >+static void tlsmgr_srvr_cache_run_event(int unused_event, char *dummy) >+{ >+ >+ /* >+ * This routine runs when it is time for another tls session cache scan. >+ * Make sure this routine gets called again in the future. >+ */ >+ srvr_scache_db_active = tlsmgr_do_scache_check(srvr_scache_db, >+ var_smtpd_tls_scache_timeout, 1); >+ event_request_timer(tlsmgr_srvr_cache_run_event, dummy, >+ var_smtpd_tls_scache_timeout); >+} >+ >+ >+static DICT *tlsmgr_cache_open(const char *dbname) >+{ >+ DICT *retval; >+ char *dbpagname; >+ char *dbdirname; >+ >+ /* >+ * First, try to find out the real name of the database file, so that >+ * it can be removed. >+ */ >+ if (!strncmp(dbname, "sdbm:", 5)) { >+ dbpagname = concatenate(dbname + 5, ".pag", NULL); >+ REMOVE(dbpagname); >+ myfree(dbpagname); >+ dbdirname = concatenate(dbname + 5, ".dir", NULL); >+ REMOVE(dbdirname); >+ myfree(dbdirname); >+ } >+ else { >+ msg_warn("Only type sdbm: supported: %s", dbname); >+ return NULL; >+ } >+ >+ /* >+ * Now open the dictionary. Do it with O_EXCL, so that we only open a >+ * fresh file. If we cannot open it with a fresh file, then we won't >+ * touch it. >+ */ >+ retval = dict_open(dbname, O_RDWR | O_CREAT | O_EXCL, >+ DICT_FLAG_DUP_REPLACE | DICT_FLAG_LOCK | DICT_FLAG_SYNC_UPDATE); >+ if (!retval) >+ msg_warn("Could not create dictionary %s", dbname); >+ return retval; >+} >+ >+/* tlsmgr_trigger_event - respond to external trigger(s) */ >+ >+static void tlsmgr_trigger_event(char *buf, int len, >+ char *unused_service, char **argv) >+{ >+ /* >+ * Sanity check. This service takes no command-line arguments. >+ */ >+ if (argv[0]) >+ msg_fatal("unexpected command-line argument: %s", argv[0]); >+ >+} >+ >+/* tlsmgr_loop - queue manager main loop */ >+ >+static int tlsmgr_loop(char *unused_name, char **unused_argv) >+{ >+ /* >+ * This routine runs as part of the event handling loop, after the event >+ * manager has delivered a timer or I/O event (including the completion >+ * of a connection to a delivery process), or after it has waited for a >+ * specified amount of time. The result value of qmgr_loop() specifies >+ * how long the event manager should wait for the next event. >+ */ >+#define DONT_WAIT 0 >+#define WAIT_FOR_EVENT (-1) >+ >+ if (clnt_scache_db_active) >+ clnt_scache_db_active = tlsmgr_do_scache_check(clnt_scache_db, >+ var_smtp_tls_scache_timeout, 0); >+ if (srvr_scache_db_active) >+ srvr_scache_db_active = tlsmgr_do_scache_check(srvr_scache_db, >+ var_smtpd_tls_scache_timeout, 0); >+ if (clnt_scache_db_active || srvr_scache_db_active) >+ return (DONT_WAIT); >+ return (WAIT_FOR_EVENT); >+} >+ >+/* pre_accept - see if tables have changed */ >+ >+static void pre_accept(char *unused_name, char **unused_argv) >+{ >+ if (dict_changed()) { >+ msg_info("table has changed -- exiting"); >+ exit(0); >+ } >+} >+ >+/* tlsmgr_pre_init - pre-jail initialization */ >+ >+static void tlsmgr_pre_init(char *unused_name, char **unused_argv) >+{ >+ int rand_bytes; >+ unsigned char buffer[255]; >+ >+#ifdef HAS_SSL >+ /* >+ * Access the external sources for random seed. We may not be able to >+ * access them again if we are sent to chroot jail, so we must leave >+ * dev: and egd: type sources open. >+ */ >+ if (*var_tls_rand_source) { >+ if (!strncmp(var_tls_rand_source, "dev:", 4)) { >+ /* >+ * Source is a random device >+ */ >+ rand_source_dev_fd = open(var_tls_rand_source + 4, 0, 0); >+ if (rand_source_dev_fd == -1) >+ msg_fatal("Could not open entropy device %s", >+ var_tls_rand_source); >+ if (var_tls_rand_bytes > 255) >+ var_tls_rand_bytes = 255; >+ rand_bytes = read(rand_source_dev_fd, buffer, var_tls_rand_bytes); >+ RAND_seed(buffer, rand_bytes); >+ } else if (!strncmp(var_tls_rand_source, "egd:", 4)) { >+ /* >+ * Source is a EGD compatible socket >+ */ >+ rand_source_socket_fd = unix_connect(var_tls_rand_source +4, >+ BLOCKING, 10); >+ if (rand_source_socket_fd == -1) >+ msg_fatal("Could not connect to %s", var_tls_rand_source); >+ if (var_tls_rand_bytes > 255) >+ var_tls_rand_bytes = 255; >+ buffer[0] = 1; >+ buffer[1] = var_tls_rand_bytes; >+ if (write(rand_source_socket_fd, buffer, 2) != 2) >+ msg_fatal("Could not talk to %s", var_tls_rand_source); >+ if (read(rand_source_socket_fd, buffer, 1) != 1) >+ msg_fatal("Could not read info from %s", var_tls_rand_source); >+ rand_bytes = buffer[0]; >+ if (read(rand_source_socket_fd, buffer, rand_bytes) != rand_bytes) >+ msg_fatal("Could not read data from %s", var_tls_rand_source); >+ RAND_seed(buffer, rand_bytes); >+ } else { >+ rand_bytes = RAND_load_file(var_tls_rand_source, >+ var_tls_rand_bytes); >+ } >+ } >+#endif >+ >+ /* >+ * Now open the PRNG exchange file >+ */ >+ if (*var_tls_rand_exch_name) { >+ rand_exch_fd = open(var_tls_rand_exch_name, O_RDWR | O_CREAT, 0600); >+ } >+ >+ /* >+ * Finally, open the session cache files. Remove old files, if still there. >+ * If we could not remove the old files, something is pretty wrong and we >+ * won't touch it!! >+ */ >+ if (*var_smtp_tls_scache_db) >+ clnt_scache_db = tlsmgr_cache_open(var_smtp_tls_scache_db); >+ if (*var_smtpd_tls_scache_db) >+ srvr_scache_db = tlsmgr_cache_open(var_smtpd_tls_scache_db); >+} >+ >+/* qmgr_post_init - post-jail initialization */ >+ >+static void tlsmgr_post_init(char *unused_name, char **unused_argv) >+{ >+ unsigned char buffer[1024]; >+ >+ /* >+ * This routine runs after the skeleton code has entered the chroot jail. >+ * Prevent automatic process suicide after a limited number of client >+ * requests or after a limited amount of idle time. >+ */ >+ var_use_limit = 0; >+ var_idle_limit = 0; >+ >+#ifdef HAS_SSL >+ /* >+ * Complete thie initialization by reading the additional seed from the >+ * PRNG exchange file. Don't care how many bytes were actually read, just >+ * seed buffer into the PRNG, regardless of its contents. >+ */ >+ if (rand_exch_fd >= 0) { >+ if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) == -1) >+ msg_fatal("Could not lock random exchange file: %s", >+ strerror(errno)); >+ read(rand_exch_fd, buffer, 1024); >+ if (myflock(rand_exch_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) == -1) >+ msg_fatal("Could not unlock random exchange file: %s", >+ strerror(errno)); >+ RAND_seed(buffer, 1024); >+ tlsmgr_prng_upd_event(0, (char *) 0); >+ tlsmgr_reseed_event(0, (char *) 0); >+ } >+#endif >+ >+ clnt_scache_db_active = 0; >+ srvr_scache_db_active = 0; >+ if (clnt_scache_db) >+ tlsmgr_clnt_cache_run_event(0, (char *) 0); >+ if (srvr_scache_db) >+ tlsmgr_srvr_cache_run_event(0, (char *) 0); >+} >+ >+/* main - the main program */ >+ >+int main(int argc, char **argv) >+{ >+ static CONFIG_STR_TABLE str_table[] = { >+ VAR_TLS_RAND_SOURCE, DEF_TLS_RAND_SOURCE, &var_tls_rand_source, 0, 0, >+ 0, >+ }; >+ static CONFIG_TIME_TABLE time_table[] = { >+ VAR_TLS_RESEED_PERIOD, DEF_TLS_RESEED_PERIOD, &var_tls_reseed_period, 0, 0, >+ VAR_TLS_PRNG_UPD_PERIOD, DEF_TLS_PRNG_UPD_PERIOD, &var_tls_prng_upd_period, 0, 0, >+ 0, >+ }; >+ static CONFIG_INT_TABLE int_table[] = { >+ VAR_TLS_RAND_BYTES, DEF_TLS_RAND_BYTES, &var_tls_rand_bytes, 0, 0, >+ 0, >+ }; >+ >+ /* >+ * Use the trigger service skeleton, because no-one else should be >+ * monitoring our service port while this process runs, and because we do >+ * not talk back to the client. >+ */ >+ trigger_server_main(argc, argv, tlsmgr_trigger_event, >+ MAIL_SERVER_TIME_TABLE, time_table, >+ MAIL_SERVER_INT_TABLE, int_table, >+ MAIL_SERVER_STR_TABLE, str_table, >+ MAIL_SERVER_PRE_INIT, tlsmgr_pre_init, >+ MAIL_SERVER_POST_INIT, tlsmgr_post_init, >+ MAIL_SERVER_LOOP, tlsmgr_loop, >+ MAIL_SERVER_PRE_ACCEPT, pre_accept, >+ 0); >+} >diff -Pur postfix-1.1.11-20020613-orig/src/util/Makefile.in postfix-1.1.11-20020613/src/util/Makefile.in >--- postfix-1.1.11-20020613-orig/src/util/Makefile.in Tue Jun 11 03:12:45 2002 >+++ postfix-1.1.11-20020613/src/util/Makefile.in Wed Jun 26 15:26:48 2002 >@@ -8,7 +8,7 @@ > dict_tcp.c dict_unix.c dir_forest.c doze.c duplex_pipe.c \ > environ.c events.c exec_command.c fifo_listen.c fifo_trigger.c \ > file_limit.c find_inet.c fsspace.c fullname.c get_domainname.c \ >- get_hostname.c hex_quote.c htable.c inet_addr_host.c \ >+ get_hostname.c get_port.c hex_quote.c htable.c inet_addr_host.c \ > inet_addr_list.c inet_addr_local.c inet_connect.c inet_listen.c \ > inet_trigger.c inet_util.c intv.c line_wrap.c lowercase.c \ > lstat_as.c mac_expand.c mac_parse.c make_dirs.c match_list.c \ >@@ -26,7 +26,7 @@ > unix_connect.c unix_listen.c unix_trigger.c unsafe.c username.c \ > valid_hostname.c vbuf.c vbuf_print.c vstream.c vstream_popen.c \ > vstring.c vstring_vstream.c watchdog.c writable.c write_buf.c \ >- write_wait.c strcasecmp.c nvtable.c >+ write_wait.c strcasecmp.c nvtable.c dict_sdbm.c sdbm.c > OBJS = alldig.o argv.o argv_split.o attr_print0.o attr_print64.o \ > attr_scan0.o attr_scan64.o base64_code.o basename.o binhash.o \ > chroot_uid.o clean_env.o close_on_exec.o concatenate.o ctable.o \ >@@ -36,7 +36,7 @@ > dict_tcp.o dict_unix.o dir_forest.o doze.o duplex_pipe.o \ > environ.o events.o exec_command.o fifo_listen.o fifo_trigger.o \ > file_limit.o find_inet.o fsspace.o fullname.o get_domainname.o \ >- get_hostname.o hex_quote.o htable.o inet_addr_host.o \ >+ get_hostname.o get_port.o hex_quote.o htable.o inet_addr_host.o \ > inet_addr_list.o inet_addr_local.o inet_connect.o inet_listen.o \ > inet_trigger.o inet_util.o intv.o line_wrap.o lowercase.o \ > lstat_as.o mac_expand.o mac_parse.o make_dirs.o match_list.o \ >@@ -54,13 +54,13 @@ > unix_connect.o unix_listen.o unix_trigger.o unsafe.o username.o \ > valid_hostname.o vbuf.o vbuf_print.o vstream.o vstream_popen.o \ > vstring.o vstring_vstream.o watchdog.o writable.o write_buf.o \ >- write_wait.o nvtable.o $(STRCASE) >+ write_wait.o nvtable.o $(STRCASE) dict_sdbm.o sdbm.o > HDRS = argv.h attr.h base64_code.h binhash.h chroot_uid.h clean_env.h \ > connect.h ctable.h dict.h dict_db.h dict_dbm.h dict_env.h \ > dict_ht.h dict_ldap.h dict_mysql.h dict_ni.h dict_nis.h \ > dict_nisplus.h dict_pcre.h dict_regexp.h dict_static.h dict_tcp.h \ > dict_unix.h dir_forest.h events.h exec_command.h find_inet.h \ >- fsspace.h fullname.h get_domainname.h get_hostname.h hex_quote.h \ >+ fsspace.h fullname.h get_domainname.h get_hostname.h get_port.h hex_quote.h \ > htable.h inet_addr_host.h inet_addr_list.h inet_addr_local.h \ > inet_util.h intv.h iostuff.h line_wrap.h listen.h lstat_as.h \ > mac_expand.h mac_parse.h make_dirs.h match_list.h match_ops.h \ >@@ -72,7 +72,7 @@ > split_at.h stat_as.h stringops.h sys_defs.h timed_connect.h \ > timed_wait.h trigger.h username.h valid_hostname.h vbuf.h \ > vbuf_print.h vstream.h vstring.h vstring_vstream.h watchdog.h \ >- nvtable.h >+ nvtable.h dict_sdbm.h sdbm.h > TESTSRC = fifo_open.c fifo_rdwr_bug.c fifo_rdonly_bug.c select_bug.c \ > stream_test.c dup2_pass_on_exec.c > WARN = -W -Wformat -Wimplicit -Wmissing-prototypes \ >@@ -591,6 +591,7 @@ > dict_open.o: dict_unix.h > dict_open.o: dict_tcp.h > dict_open.o: dict_dbm.h >+dict_open.o: dict_sdbm.h > dict_open.o: dict_db.h > dict_open.o: dict_nis.h > dict_open.o: dict_nisplus.h >@@ -725,6 +726,7 @@ > get_domainname.o: mymalloc.h > get_domainname.o: get_hostname.h > get_domainname.o: get_domainname.h >+get_port.o: sys_defs.h > get_hostname.o: get_hostname.c > get_hostname.o: sys_defs.h > get_hostname.o: mymalloc.h >@@ -841,6 +843,7 @@ > match_list.o: stringops.h > match_list.o: argv.h > match_list.o: dict.h >+match_list.o: inet_util.h > match_list.o: match_ops.h > match_list.o: match_list.h > match_ops.o: match_ops.c >@@ -1225,3 +1228,9 @@ > write_wait.o: sys_defs.h > write_wait.o: msg.h > write_wait.o: iostuff.h >+sdbm.o: sdbm.c >+sdbm.o: sdbm.h >+dict_sdbm.o: sdbm.h >+dict_sdbm.o: dict_sdbm.c >+dict_sdbm.o: dict_sdbm.h >+dict_sdbm.o: sys_defs.h >diff -Pur postfix-1.1.11-20020613-orig/src/util/dict_open.c postfix-1.1.11-20020613/src/util/dict_open.c >--- postfix-1.1.11-20020613-orig/src/util/dict_open.c Fri Dec 21 23:18:07 2001 >+++ postfix-1.1.11-20020613/src/util/dict_open.c Wed Jun 26 15:26:48 2002 >@@ -159,6 +159,7 @@ > #include <dict_env.h> > #include <dict_unix.h> > #include <dict_tcp.h> >+#include <dict_sdbm.h> > #include <dict_dbm.h> > #include <dict_db.h> > #include <dict_nis.h> >@@ -187,6 +188,7 @@ > #if 0 > DICT_TYPE_TCP, dict_tcp_open, > #endif >+ "sdbm", dict_sdbm_open, > #ifdef HAS_DBM > DICT_TYPE_DBM, dict_dbm_open, > #endif >diff -Pur postfix-1.1.11-20020613-orig/src/util/dict_sdbm.c postfix-1.1.11-20020613/src/util/dict_sdbm.c >--- postfix-1.1.11-20020613-orig/src/util/dict_sdbm.c Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/util/dict_sdbm.c Wed Jun 26 15:26:48 2002 >@@ -0,0 +1,408 @@ >+/*++ >+/* NAME >+/* dict_sdbm 3 >+/* SUMMARY >+/* dictionary manager interface to SDBM files >+/* SYNOPSIS >+/* #include <dict_sdbm.h> >+/* >+/* DICT *dict_sdbm_open(path, open_flags, dict_flags) >+/* const char *name; >+/* const char *path; >+/* int open_flags; >+/* int dict_flags; >+/* DESCRIPTION >+/* dict_sdbm_open() opens the named SDBM database and makes it available >+/* via the generic interface described in dict_open(3). >+/* DIAGNOSTICS >+/* Fatal errors: cannot open file, file write error, out of memory. >+/* SEE ALSO >+/* dict(3) generic dictionary manager >+/* sdbm(3) data base subroutines >+/* 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 >+/*--*/ >+ >+#include "sys_defs.h" >+ >+/* System library. */ >+ >+#include <sys/stat.h> >+#include <string.h> >+#include <unistd.h> >+ >+/* Utility library. */ >+ >+#include "msg.h" >+#include "mymalloc.h" >+#include "htable.h" >+#include "iostuff.h" >+#include "vstring.h" >+#include "myflock.h" >+#include "stringops.h" >+#include "dict.h" >+#include "dict_sdbm.h" >+#include "sdbm.h" >+ >+/* Application-specific. */ >+ >+typedef struct { >+ DICT dict; /* generic members */ >+ SDBM *dbm; /* open database */ >+ char *path; /* pathname */ >+} DICT_SDBM; >+ >+/* dict_sdbm_lookup - find database entry */ >+ >+static const char *dict_sdbm_lookup(DICT *dict, const char *name) >+{ >+ DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; >+ datum dbm_key; >+ datum dbm_value; >+ static VSTRING *buf; >+ const char *result = 0; >+ >+ dict_errno = 0; >+ >+ /* >+ * Acquire an exclusive lock. >+ */ >+ if ((dict->flags & DICT_FLAG_LOCK) >+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0) >+ msg_fatal("%s: lock dictionary: %m", dict_sdbm->path); >+ >+ /* >+ * See if this DBM file was written with one null byte appended to key >+ * and value. >+ */ >+ if (dict->flags & DICT_FLAG_TRY1NULL) { >+ dbm_key.dptr = (void *) name; >+ dbm_key.dsize = strlen(name) + 1; >+ dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key); >+ if (dbm_value.dptr != 0) { >+ dict->flags &= ~DICT_FLAG_TRY0NULL; >+ result = dbm_value.dptr; >+ } >+ } >+ >+ /* >+ * See if this DBM file was written with no null byte appended to key and >+ * value. >+ */ >+ if (result == 0 && (dict->flags & DICT_FLAG_TRY0NULL)) { >+ dbm_key.dptr = (void *) name; >+ dbm_key.dsize = strlen(name); >+ dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key); >+ if (dbm_value.dptr != 0) { >+ if (buf == 0) >+ buf = vstring_alloc(10); >+ vstring_strncpy(buf, dbm_value.dptr, dbm_value.dsize); >+ dict->flags &= ~DICT_FLAG_TRY1NULL; >+ result = vstring_str(buf); >+ } >+ } >+ >+ /* >+ * Release the exclusive lock. >+ */ >+ if ((dict->flags & DICT_FLAG_LOCK) >+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) >+ msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path); >+ >+ return (result); >+} >+ >+/* dict_sdbm_update - add or update database entry */ >+ >+static void dict_sdbm_update(DICT *dict, const char *name, const char *value) >+{ >+ DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; >+ datum dbm_key; >+ datum dbm_value; >+ int status; >+ >+ dbm_key.dptr = (void *) name; >+ dbm_value.dptr = (void *) value; >+ dbm_key.dsize = strlen(name); >+ dbm_value.dsize = strlen(value); >+ >+ /* >+ * If undecided about appending a null byte to key and value, choose a >+ * default depending on the platform. >+ */ >+ if ((dict->flags & DICT_FLAG_TRY1NULL) >+ && (dict->flags & DICT_FLAG_TRY0NULL)) { >+#ifdef DBM_NO_TRAILING_NULL >+ dict->flags &= ~DICT_FLAG_TRY1NULL; >+#else >+ dict->flags &= ~DICT_FLAG_TRY0NULL; >+#endif >+ } >+ >+ /* >+ * Optionally append a null byte to key and value. >+ */ >+ if (dict->flags & DICT_FLAG_TRY1NULL) { >+ dbm_key.dsize++; >+ dbm_value.dsize++; >+ } >+ >+ /* >+ * Acquire an exclusive lock. >+ */ >+ if ((dict->flags & DICT_FLAG_LOCK) >+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) >+ msg_fatal("%s: lock dictionary: %m", dict_sdbm->path); >+ >+ /* >+ * Do the update. >+ */ >+ if ((status = sdbm_store(dict_sdbm->dbm, dbm_key, dbm_value, >+ (dict->flags & DICT_FLAG_DUP_REPLACE) ? DBM_REPLACE : DBM_INSERT)) < 0) >+ msg_fatal("error writing SDBM database %s: %m", dict_sdbm->path); >+ if (status) { >+ if (dict->flags & DICT_FLAG_DUP_IGNORE) >+ /* void */ ; >+ else if (dict->flags & DICT_FLAG_DUP_WARN) >+ msg_warn("%s: duplicate entry: \"%s\"", dict_sdbm->path, name); >+ else >+ msg_fatal("%s: duplicate entry: \"%s\"", dict_sdbm->path, name); >+ } >+ >+ /* >+ * Release the exclusive lock. >+ */ >+ if ((dict->flags & DICT_FLAG_LOCK) >+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) >+ msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path); >+} >+ >+ >+/* dict_sdbm_delete - delete one entry from the dictionary */ >+ >+static int dict_sdbm_delete(DICT *dict, const char *name) >+{ >+ DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; >+ datum dbm_key; >+ int status = 1; >+ int flags = 0; >+ >+ /* >+ * Acquire an exclusive lock. >+ */ >+ if ((dict->flags & DICT_FLAG_LOCK) >+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) >+ msg_fatal("%s: lock dictionary: %m", dict_sdbm->path); >+ >+ /* >+ * See if this DBM file was written with one null byte appended to key >+ * and value. >+ */ >+ if (dict->flags & DICT_FLAG_TRY1NULL) { >+ dbm_key.dptr = (void *) name; >+ dbm_key.dsize = strlen(name) + 1; >+ sdbm_clearerr(dict_sdbm->dbm); >+ if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) { >+ if (sdbm_error(dict_sdbm->dbm) != 0) /* fatal error */ >+ msg_fatal("error deleting from %s: %m", dict_sdbm->path); >+ status = 1; /* not found */ >+ } else { >+ dict->flags &= ~DICT_FLAG_TRY0NULL; /* found */ >+ } >+ } >+ >+ /* >+ * See if this DBM file was written with no null byte appended to key and >+ * value. >+ */ >+ if (status > 0 && (dict->flags & DICT_FLAG_TRY0NULL)) { >+ dbm_key.dptr = (void *) name; >+ dbm_key.dsize = strlen(name); >+ sdbm_clearerr(dict_sdbm->dbm); >+ if ((status = sdbm_delete(dict_sdbm->dbm, dbm_key)) < 0) { >+ if (sdbm_error(dict_sdbm->dbm) != 0) /* fatal error */ >+ msg_fatal("error deleting from %s: %m", dict_sdbm->path); >+ status = 1; /* not found */ >+ } else { >+ dict->flags &= ~DICT_FLAG_TRY1NULL; /* found */ >+ } >+ } >+ >+ /* >+ * Release the exclusive lock. >+ */ >+ if ((dict->flags & DICT_FLAG_LOCK) >+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) >+ msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path); >+ >+ return (status); >+} >+ >+/* traverse the dictionary */ >+ >+static int dict_sdbm_sequence(DICT *dict, const int function, >+ const char **key, const char **value) >+{ >+ char *myname = "dict_sdbm_sequence"; >+ DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; >+ datum dbm_key; >+ datum dbm_value; >+ int status = 0; >+ static VSTRING *key_buf; >+ static VSTRING *value_buf; >+ >+ /* >+ * Acquire an exclusive lock. >+ */ >+ if ((dict->flags & DICT_FLAG_LOCK) >+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_EXCLUSIVE) < 0) >+ msg_fatal("%s: lock dictionary: %m", dict_sdbm->path); >+ >+ /* >+ * Determine and execute the seek function. It returns the key. >+ */ >+ switch (function) { >+ case DICT_SEQ_FUN_FIRST: >+ dbm_key = sdbm_firstkey(dict_sdbm->dbm); >+ break; >+ case DICT_SEQ_FUN_NEXT: >+ dbm_key = sdbm_nextkey(dict_sdbm->dbm); >+ break; >+ default: >+ msg_panic("%s: invalid function: %d", myname, function); >+ } >+ >+ /* >+ * Release the exclusive lock. >+ */ >+ if ((dict->flags & DICT_FLAG_LOCK) >+ && myflock(dict->lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) >+ msg_fatal("%s: unlock dictionary: %m", dict_sdbm->path); >+ >+ if (dbm_key.dptr != 0 && dbm_key.dsize > 0) { >+ >+ /* >+ * See if this DB file was written with one null byte appended to key >+ * an d value or not. If necessary, copy the key. >+ */ >+ if (((char *) dbm_key.dptr)[dbm_key.dsize - 1] == 0) { >+ *key = dbm_key.dptr; >+ } else { >+ if (key_buf == 0) >+ key_buf = vstring_alloc(10); >+ vstring_strncpy(key_buf, dbm_key.dptr, dbm_key.dsize); >+ *key = vstring_str(key_buf); >+ } >+ >+ /* >+ * Fetch the corresponding value. >+ */ >+ dbm_value = sdbm_fetch(dict_sdbm->dbm, dbm_key); >+ >+ if (dbm_value.dptr != 0 && dbm_value.dsize > 0) { >+ >+ /* >+ * See if this DB file was written with one null byte appended to >+ * key and value or not. If necessary, copy the key. >+ */ >+ if (((char *) dbm_value.dptr)[dbm_value.dsize - 1] == 0) { >+ *value = dbm_value.dptr; >+ } else { >+ if (value_buf == 0) >+ value_buf = vstring_alloc(10); >+ vstring_strncpy(value_buf, dbm_value.dptr, dbm_value.dsize); >+ *value = vstring_str(value_buf); >+ } >+ } else { >+ >+ /* >+ * Determine if we have hit the last record or an error >+ * condition. >+ */ >+ if (sdbm_error(dict_sdbm->dbm)) >+ msg_fatal("error seeking %s: %m", dict_sdbm->path); >+ return (1); /* no error: eof/not found >+ * (should not happen!) */ >+ } >+ } else { >+ >+ /* >+ * Determine if we have hit the last record or an error condition. >+ */ >+ if (sdbm_error(dict_sdbm->dbm)) >+ msg_fatal("error seeking %s: %m", dict_sdbm->path); >+ return (1); /* no error: eof/not found */ >+ } >+ return (0); >+} >+ >+/* dict_sdbm_close - disassociate from data base */ >+ >+static void dict_sdbm_close(DICT *dict) >+{ >+ DICT_SDBM *dict_sdbm = (DICT_SDBM *) dict; >+ >+ sdbm_close(dict_sdbm->dbm); >+ myfree(dict_sdbm->path); >+ myfree((char *) dict_sdbm); >+} >+ >+/* dict_sdbm_open - open SDBM data base */ >+ >+DICT *dict_sdbm_open(const char *path, int open_flags, int dict_flags) >+{ >+ DICT_SDBM *dict_sdbm; >+ struct stat st; >+ SDBM *dbm; >+ char *dbm_path; >+ int lock_fd; >+ >+ if (dict_flags & DICT_FLAG_LOCK) { >+ dbm_path = concatenate(path, ".pag", (char *) 0); >+ if ((lock_fd = open(dbm_path, open_flags, 0644)) < 0) >+ msg_fatal("open database %s: %m", dbm_path); >+ if (myflock(lock_fd, INTERNAL_LOCK, MYFLOCK_OP_SHARED) < 0) >+ msg_fatal("shared-lock database %s for open: %m", dbm_path); >+ } >+ >+ /* >+ * XXX SunOS 5.x has no const in dbm_open() prototype. >+ */ >+ if ((dbm = sdbm_open((char *) path, open_flags, 0644)) == 0) >+ msg_fatal("open database %s.{dir,pag}: %m", path); >+ >+ if (dict_flags & DICT_FLAG_LOCK) { >+ if (myflock(lock_fd, INTERNAL_LOCK, MYFLOCK_OP_NONE) < 0) >+ msg_fatal("unlock database %s for open: %m", dbm_path); >+ if (close(lock_fd) < 0) >+ msg_fatal("close database %s: %m", dbm_path); >+ myfree(dbm_path); >+ } >+ dict_sdbm = (DICT_SDBM *) mymalloc(sizeof(*dict_sdbm)); >+ dict_sdbm->dict.lookup = dict_sdbm_lookup; >+ dict_sdbm->dict.update = dict_sdbm_update; >+ dict_sdbm->dict.delete = dict_sdbm_delete; >+ dict_sdbm->dict.sequence = dict_sdbm_sequence; >+ dict_sdbm->dict.close = dict_sdbm_close; >+ dict_sdbm->dict.lock_fd = sdbm_dirfno(dbm); >+ dict_sdbm->dict.stat_fd = sdbm_pagfno(dbm); >+ if (fstat(dict_sdbm->dict.stat_fd, &st) < 0) >+ msg_fatal("dict_sdbm_open: fstat: %m"); >+ dict_sdbm->dict.mtime = st.st_mtime; >+ close_on_exec(sdbm_pagfno(dbm), CLOSE_ON_EXEC); >+ close_on_exec(sdbm_dirfno(dbm), CLOSE_ON_EXEC); >+ dict_sdbm->dict.flags = dict_flags | DICT_FLAG_FIXED; >+ if ((dict_flags & (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL)) == 0) >+ dict_sdbm->dict.flags |= (DICT_FLAG_TRY0NULL | DICT_FLAG_TRY1NULL); >+ dict_sdbm->dbm = dbm; >+ dict_sdbm->path = mystrdup(path); >+ >+ return (&dict_sdbm->dict); >+} >diff -Pur postfix-1.1.11-20020613-orig/src/util/dict_sdbm.h postfix-1.1.11-20020613/src/util/dict_sdbm.h >--- postfix-1.1.11-20020613-orig/src/util/dict_sdbm.h Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/util/dict_sdbm.h Wed Jun 26 15:26:48 2002 >@@ -0,0 +1,35 @@ >+#ifndef _DICT_SDBM_H_INCLUDED_ >+#define _DICT_SDBM_H_INCLUDED_ >+ >+/*++ >+/* NAME >+/* dict_dbm 3h >+/* SUMMARY >+/* dictionary manager interface to DBM files >+/* SYNOPSIS >+/* #include <dict_dbm.h> >+/* DESCRIPTION >+/* .nf >+ >+ /* >+ * Utility library. >+ */ >+#include <dict.h> >+ >+ /* >+ * External interface. >+ */ >+extern DICT *dict_sdbm_open(const char *, int, int); >+ >+/* 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 >diff -Pur postfix-1.1.11-20020613-orig/src/util/get_port.c postfix-1.1.11-20020613/src/util/get_port.c >--- postfix-1.1.11-20020613-orig/src/util/get_port.c Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/util/get_port.c Wed Jun 26 15:26:49 2002 >@@ -0,0 +1,65 @@ >+/*++ >+/* NAME >+/* get_port 3 >+/* SUMMARY >+/* trivial host and port extracter >+/* SYNOPSIS >+/* #include <get_port.h> >+/* >+/* char *get_port(data) >+/* char *data; >+/* >+/* DESCRIPTION >+/* get_port() extract host name or ip address from >+/* strings such as [3ffe:902:12::10]:25, [::1] >+/* or 192.168.0.1:25, and null-terminates the >+/* \fIdata\fR at the first occurrence of port separator. >+/* DIAGNOSTICS >+/* If port not found return null pointer. >+/* LICENSE >+/* .ad >+/* .fi >+/* BSD Style (or BSD like) license. >+/* AUTHOR(S) >+/* Arkadiusz Mi¶kiewicz <misiek@pld.org.pl> >+/* Wroclaw, POLAND >+/*--*/ >+ >+/* System libraries */ >+ >+#include <sys_defs.h> >+#include <string.h> >+ >+/* Utility library. */ >+ >+#include "get_port.h" >+ >+/* get_port - extract port number from string */ >+ >+char *get_port(char *data) >+{ >+ const char *escl=strchr(data,'['); >+ const char *sepl=strchr(data,':'); >+ char *escr=strrchr(data,']'); >+ char *sepr=strrchr(data,':'); >+ >+ /* extract from "[address]:port" or "[address]"*/ >+ if (escl && escr) >+ { >+ memmove(data, data + 1, strlen(data) - strlen(escr)); >+ data[strlen(data) - strlen(escr) - 1] = 0; >+ *escr++ = 0; >+ if (*escr == ':') >+ escr++; >+ return (*escr ? escr : NULL); >+ } >+ /* extract from "address:port" or "address" */ >+ if ((sepl == sepr) && sepr && sepl) >+ { >+ *sepr++ = 0; >+ return sepr; >+ } >+ >+ /* return empty string */ >+ return NULL; >+} >diff -Pur postfix-1.1.11-20020613-orig/src/util/get_port.h postfix-1.1.11-20020613/src/util/get_port.h >--- postfix-1.1.11-20020613-orig/src/util/get_port.h Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/util/get_port.h Wed Jun 26 15:26:49 2002 >@@ -0,0 +1,28 @@ >+#ifndef _GET_PORT_H_INCLUDED_ >+#define _GET_PORT_H_INCLUDED_ >+ >+/*++ >+/* NAME >+/* get_port 3h >+/* SUMMARY >+/* trivial host and port extracter >+/* SYNOPSIS >+/* #include <get_port.h> >+/* DESCRIPTION >+/* .nf >+ >+ /* External interface. */ >+ >+extern char *get_port(char *); >+ >+ >+/* LICENSE >+/* .ad >+/* .fi >+/* BSD Style (or BSD like) license. >+/* AUTHOR(S) >+/* Arkadiusz Mi¶kiewicz <misiek@pld.org.pl> >+/* Wroclaw, POLAND >+/*--*/ >+ >+#endif >diff -Pur postfix-1.1.11-20020613-orig/src/util/inet_addr_host.c postfix-1.1.11-20020613/src/util/inet_addr_host.c >--- postfix-1.1.11-20020613-orig/src/util/inet_addr_host.c Fri Dec 11 19:55:35 1998 >+++ postfix-1.1.11-20020613/src/util/inet_addr_host.c Wed Jun 26 15:26:49 2002 >@@ -38,7 +38,10 @@ > #include <sys_defs.h> > #include <netinet/in.h> > #include <arpa/inet.h> >+#include <sys/socket.h> > #include <netdb.h> >+#include <stdlib.h> >+#include <string.h> > > #ifndef INADDR_NONE > #define INADDR_NONE 0xffffffff >@@ -48,15 +51,47 @@ > > #include <inet_addr_list.h> > #include <inet_addr_host.h> >+#ifdef TEST >+#include <msg.h> >+#endif > > /* inet_addr_host - look up address list for host */ > > int inet_addr_host(INET_ADDR_LIST *addr_list, const char *hostname) > { >+#ifdef INET6 >+ int s; >+ struct addrinfo hints, *res0, *res; >+#ifdef TEST >+ char buforhosta[1024]; >+#endif >+ int error; >+#else > struct hostent *hp; > struct in_addr addr; >+#endif > int initial_count = addr_list->used; > >+#ifdef INET6 >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = PF_UNSPEC; >+ hints.ai_socktype = SOCK_DGRAM; >+ error = getaddrinfo(hostname, NULL, &hints, &res0); >+ if (error == 0) { >+ for (res = res0; res; res = res->ai_next) { >+ if(res->ai_family != AF_INET && res->ai_family != AF_INET6) >+ continue; >+ /* filter out address families that are not supported */ >+ s = socket(res->ai_family, SOCK_DGRAM, 0); >+ if (s < 0) >+ continue; >+ close(s); >+ >+ inet_addr_list_append(addr_list, res->ai_addr); >+ } >+ freeaddrinfo(res0); >+ } >+#else > if ((addr.s_addr = inet_addr(hostname)) != INADDR_NONE) { > inet_addr_list_append(addr_list, &addr); > } else { >@@ -65,9 +100,12 @@ > inet_addr_list_append(addr_list, > (struct in_addr *) * hp->h_addr_list++); > } >+#endif >+ > return (addr_list->used - initial_count); > } > >+ > #ifdef TEST > > #include <msg.h> >@@ -78,6 +116,8 @@ > { > INET_ADDR_LIST addr_list; > int i; >+ struct sockaddr *sa; >+ char hbuf[NI_MAXHOST]; > > msg_vstream_init(argv[0], VSTREAM_ERR); > >@@ -89,8 +129,12 @@ > if (inet_addr_host(&addr_list, *argv) == 0) > msg_fatal("not found: %s", *argv); > >- for (i = 0; i < addr_list.used; i++) >- vstream_printf("%s\n", inet_ntoa(addr_list.addrs[i])); >+ for (i = 0; i < addr_list.used; i++) { >+ sa = (struct sockaddr *)&addr_list.addrs[i]; >+ getnameinfo(sa, SA_LEN(sa), hbuf, sizeof(hbuf), NULL, 0, >+ NI_NUMERICHOST); >+ vstream_printf("%s\n", hbuf); >+ } > vstream_fflush(VSTREAM_OUT); > } > inet_addr_list_free(&addr_list); >diff -Pur postfix-1.1.11-20020613-orig/src/util/inet_addr_list.c postfix-1.1.11-20020613/src/util/inet_addr_list.c >--- postfix-1.1.11-20020613-orig/src/util/inet_addr_list.c Tue Jul 31 20:13:41 2001 >+++ postfix-1.1.11-20020613/src/util/inet_addr_list.c Wed Jun 26 15:26:49 2002 >@@ -51,6 +51,13 @@ > #include <arpa/inet.h> > #include <stdlib.h> > >+#include <netdb.h> >+ >+#ifdef INET6 >+#include <string.h> >+#include <sys/socket.h> >+#endif >+ > /* Utility library. */ > > #include <msg.h> >@@ -63,12 +70,39 @@ > { > list->used = 0; > list->size = 2; >+#ifdef INET6 >+ list->addrs = (struct sockaddr_storage *) >+#else > list->addrs = (struct in_addr *) >+#endif > mymalloc(sizeof(*list->addrs) * list->size); > } > > /* inet_addr_list_append - append address to internet address list */ > >+#ifdef INET6 >+void inet_addr_list_append(INET_ADDR_LIST *list, >+ struct sockaddr * addr) >+{ >+ char *myname = "inet_addr_list_append"; >+ char hbuf[NI_MAXHOST]; >+ >+ if (msg_verbose > 1) { >+ if (getnameinfo(addr, SA_LEN(addr), hbuf, sizeof(hbuf), NULL, 0, >+ NI_NUMERICHOST)) { >+ strncpy(hbuf, "??????", sizeof(hbuf)); >+ } >+ msg_info("%s: %s", myname, hbuf); >+ } >+ >+ if (list->used >= list->size) >+ list->size *= 2; >+ list->addrs = (struct sockaddr_storage *) >+ myrealloc((char *) list->addrs, >+ sizeof(*list->addrs) * list->size); >+ memcpy(&list->addrs[list->used++], addr, SA_LEN(addr)); >+} >+#else > void inet_addr_list_append(INET_ADDR_LIST *list, struct in_addr * addr) > { > char *myname = "inet_addr_list_append"; >@@ -83,15 +117,22 @@ > sizeof(*list->addrs) * list->size); > list->addrs[list->used++] = *addr; > } >+#endif > > /* inet_addr_list_comp - compare addresses */ > > static int inet_addr_list_comp(const void *a, const void *b) > { >+#ifdef INET6 >+ if(((struct sockaddr*)a)->sa_family != ((struct sockaddr*)b)->sa_family) >+ return ( ((struct sockaddr*)a)->sa_family - ((struct sockaddr*)b)->sa_family ); >+ return memcmp(a,b,SA_LEN((struct sockaddr*)a)); >+#else > const struct in_addr *a_addr = (const struct in_addr *) a; > const struct in_addr *b_addr = (const struct in_addr *) b; > > return (a_addr->s_addr - b_addr->s_addr); >+#endif > } > > /* inet_addr_list_uniq - weed out duplicates */ >diff -Pur postfix-1.1.11-20020613-orig/src/util/inet_addr_list.h postfix-1.1.11-20020613/src/util/inet_addr_list.h >--- postfix-1.1.11-20020613-orig/src/util/inet_addr_list.h Tue Jul 31 19:56:47 2001 >+++ postfix-1.1.11-20020613/src/util/inet_addr_list.h Wed Jun 26 15:26:49 2002 >@@ -16,19 +16,42 @@ > */ > #include <netinet/in.h> > >+#ifndef SA_LEN >+# ifndef HAS_SA_LEN >+# define SA_LEN(x) (((x)->sa_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) >+# define SS_LEN(x) (((x).ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) >+# else >+# define SA_LEN(x) ((x)->sa_len) >+# define SS_LEN(x) ((x).ss_len) >+# endif >+#else >+# ifndef SS_LEN >+# define SS_LEN(x) (((x).ss_family == AF_INET6) ? sizeof(struct sockaddr_in6) : sizeof(struct sockaddr_in)) >+# endif >+#endif >+ > /* > * External interface. > */ > typedef struct INET_ADDR_LIST { > int used; /* nr of elements in use */ > int size; /* actual list size */ >+#ifdef INET6 >+ struct sockaddr_storage *addrs; /* payload */ >+#else > struct in_addr *addrs; /* payload */ >+#endif > } INET_ADDR_LIST; > > extern void inet_addr_list_init(INET_ADDR_LIST *); > extern void inet_addr_list_free(INET_ADDR_LIST *); > extern void inet_addr_list_uniq(INET_ADDR_LIST *); >+#ifdef INET6 >+struct sockaddr; >+extern void inet_addr_list_append(INET_ADDR_LIST *, struct sockaddr *); >+#else > extern void inet_addr_list_append(INET_ADDR_LIST *, struct in_addr *); >+#endif > > /* LICENSE > /* .ad >diff -Pur postfix-1.1.11-20020613-orig/src/util/inet_addr_local.c postfix-1.1.11-20020613/src/util/inet_addr_local.c >--- postfix-1.1.11-20020613-orig/src/util/inet_addr_local.c Sun Feb 25 19:20:19 2001 >+++ postfix-1.1.11-20020613/src/util/inet_addr_local.c Wed Jun 26 15:26:49 2002 >@@ -47,6 +47,13 @@ > #endif > #include <errno.h> > #include <string.h> >+#if defined(INET6) && (defined (LINUX) || defined (LINUX2)) >+#include <netdb.h> >+#include <stdio.h> >+#endif >+#ifdef HAVE_GETIFADDRS >+#include <ifaddrs.h> >+#endif > > /* Utility library. */ > >@@ -78,18 +85,104 @@ > > int inet_addr_local(INET_ADDR_LIST *addr_list, INET_ADDR_LIST *mask_list) > { >+#ifdef HAVE_GETIFADDRS >+ char *myname = "inet_addr_local"; >+ struct ifaddrs *ifap, *ifa; >+ int initial_count = addr_list->used; >+ struct sockaddr *sa, *sam; >+#ifdef INET6 >+#ifdef __KAME__ >+ struct sockaddr_in6 addr6; >+#endif >+#else >+ void *addr,*addrm; >+#endif >+ >+ if (getifaddrs(&ifap) < 0) >+ msg_fatal("%s: getifaddrs: %m", myname); >+ >+ for (ifa = ifap; ifa; ifa = ifa->ifa_next) { >+ if (! (ifa->ifa_flags & IFF_RUNNING) || ifa->ifa_addr==NULL) >+ continue; >+ sa = ifa->ifa_addr; >+ sam = ifa->ifa_netmask; >+ switch (ifa->ifa_addr->sa_family) { >+ case AF_INET: >+#ifndef INET6 >+ addr = (void *)&((struct sockaddr_in *)ifa->ifa_addr)->sin_addr; >+ addrm = (void *)&((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr; >+#endif >+ break; >+#ifdef INET6 >+ case AF_INET6: >+#ifdef __KAME__ >+ memcpy(&addr6, ifa->ifa_addr, ifa->ifa_addr->sa_len); >+ /* decode scoped address notation */ >+ if ((IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) || >+ IN6_IS_ADDR_SITELOCAL(&addr6.sin6_addr)) && >+ addr6.sin6_scope_id == 0) { >+ addr6.sin6_scope_id = ntohs(addr6.sin6_addr.s6_addr[3] | >+ (unsigned int)addr6.sin6_addr.s6_addr[2] << 8); >+ addr6.sin6_addr.s6_addr[2] = addr6.sin6_addr.s6_addr[3] = 0; >+ sa = (struct sockaddr *)&addr6; >+ } >+#endif >+ break; >+#endif >+ default: >+ continue; >+ } >+ >+#ifdef INET6 >+ inet_addr_list_append(addr_list, sa); >+ if (mask_list != NULL) >+ inet_addr_list_append(mask_list, sam); >+#else >+ inet_addr_list_append(addr_list, (struct in_addr *)addr); >+ if (mask_list != NULL) >+ inet_addr_list_append(mask_list, (struct in_addr *)addrm); >+#endif >+ } >+ >+ freeifaddrs(ifap); >+ return (addr_list->used - initial_count); >+#else > char *myname = "inet_addr_local"; > struct ifconf ifc; > struct ifreq *ifr; > struct ifreq *the_end; > int sock; >- VSTRING *buf = vstring_alloc(1024); >+ VSTRING *buf; > int initial_count = addr_list->used; > struct in_addr addr; > struct ifreq *ifr_mask; >+ int af = AF_INET; >+#ifdef INET6 >+#if defined (LINUX) || defined (LINUX2) >+#define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6" >+ FILE *f; >+ char addr6p[8][5], addr6res[40], devname[20]; >+ int plen, scope, dad_status, if_idx, gaierror; >+ struct addrinfo hints, *res, *res0; >+#endif >+ struct sockaddr_in6 addr6; > >- if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) >+other_socket_type: >+#endif >+ buf = vstring_alloc(1024); >+ >+ if ((sock = socket(af, SOCK_DGRAM, 0)) < 0) { >+#ifdef INET6 >+ if (af == AF_INET6) >+ { >+ if (msg_verbose) >+ msg_warn("%s: socket: %m", myname); >+ goto end; >+ } >+ else >+#endif > msg_fatal("%s: socket: %m", myname); >+ } > > /* > * Get the network interface list. XXX The socket API appears to have no >@@ -126,10 +219,15 @@ > */ > the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); > for (ifr = ifc.ifc_req; ifr < the_end;) { >- if (ifr->ifr_addr.sa_family == AF_INET) { /* IP interface */ >+ if ((ifr->ifr_addr.sa_family == AF_INET) && >+ (ifr->ifr_addr.sa_family == af)) { /* IP interface */ > addr = ((struct sockaddr_in *) & ifr->ifr_addr)->sin_addr; > if (addr.s_addr != INADDR_ANY) { /* has IP address */ >+#ifdef INET6 >+ inet_addr_list_append(addr_list, &ifr->ifr_addr); >+#else > inet_addr_list_append(addr_list, &addr); >+#endif > if (mask_list) { > ifr_mask = (struct ifreq *) mymalloc(IFREQ_SIZE(ifr)); > memcpy((char *) ifr_mask, (char *) ifr, IFREQ_SIZE(ifr)); >@@ -141,11 +239,61 @@ > } > } > } >+#ifdef INET6 >+ else if ((ifr->ifr_addr.sa_family == AF_INET6) && >+ (ifr->ifr_addr.sa_family == af)) { /* IPv6 interface */ >+ addr6 = *((struct sockaddr_in6 *) & ifr->ifr_addr); >+#ifdef __KAME__ >+ /* decode scoped address notation */ >+ if ((IN6_IS_ADDR_LINKLOCAL(&addr6.sin6_addr) || >+ IN6_IS_ADDR_SITELOCAL(&addr6.sin6_addr)) && >+ addr6.sin6_scope_id == 0) { >+ addr6.sin6_scope_id = ntohs(addr6.sin6_addr.s6_addr[3] | >+ (unsigned int)addr6.sin6_addr.s6_addr[2] << 8); >+ addr6.sin6_addr.s6_addr[2] = addr6.sin6_addr.s6_addr[3] = 0; >+ } >+#endif >+ if (!(IN6_IS_ADDR_UNSPECIFIED(&addr6.sin6_addr))) >+ inet_addr_list_append(addr_list, (struct sockaddr *)&addr6); >+ } >+#endif > ifr = NEXT_INTERFACE(ifr); > } > vstring_free(buf); > (void) close(sock); >+#ifdef INET6 >+end: >+ if (af != AF_INET6) { >+ af = AF_INET6; >+ goto other_socket_type; >+ } >+#if defined (LINUX) || defined (LINUX2) >+ if ((f = fopen(_PATH_PROCNET_IFINET6, "r")) != NULL) { >+ while (fscanf(f, "%4s%4s%4s%4s%4s%4s%4s%4s %02x %02x %02x %02x %20s\n", >+ addr6p[0], addr6p[1], addr6p[2], addr6p[3], addr6p[4], >+ addr6p[5], addr6p[6], addr6p[7], >+ &if_idx, &plen, &scope, &dad_status, devname) != EOF) { >+ sprintf(addr6res, "%s:%s:%s:%s:%s:%s:%s:%s", >+ addr6p[0], addr6p[1], addr6p[2], addr6p[3], >+ addr6p[4], addr6p[5], addr6p[6], addr6p[7]); >+ addr6res[sizeof(addr6res) - 1] = 0; >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_flags = AI_NUMERICHOST; >+ hints.ai_family = AF_UNSPEC; >+ hints.ai_socktype = SOCK_DGRAM; >+ gaierror = getaddrinfo(addr6res, NULL, &hints, &res0); >+ if (!gaierror) { >+ for (res = res0; res; res = res->ai_next) { >+ inet_addr_list_append(addr_list, res->ai_addr); >+ } >+ freeaddrinfo(res0); >+ } >+ } >+ } >+#endif /* linux */ >+#endif > return (addr_list->used - initial_count); >+#endif > } > > #ifdef TEST >@@ -158,6 +306,8 @@ > INET_ADDR_LIST addr_list; > INET_ADDR_LIST mask_list; > int i; >+ char abuf[NI_MAXHOST], mbuf[NI_MAXHOST]; >+ struct sockaddr *sa; > > msg_vstream_init(argv[0], VSTREAM_ERR); > >@@ -172,8 +322,17 @@ > msg_warn("found only one active network interface"); > > for (i = 0; i < addr_list.used; i++) { >- vstream_printf("%s/", inet_ntoa(addr_list.addrs[i])); >- vstream_printf("%s\n", inet_ntoa(mask_list.addrs[i])); >+ sa = (struct sockaddr *)&addr_list.addrs[i]; >+ if (getnameinfo(sa, SA_LEN(sa), abuf, sizeof(abuf), NULL, 0, >+ NI_NUMERICHOST)) { >+ strncpy(abuf, "???", sizeof(abuf)); >+ } >+ sa = (struct sockaddr *)&mask_list.addrs[i]; >+ if (getnameinfo(sa, SA_LEN(sa), mbuf, sizeof(mbuf), NULL, 0, >+ NI_NUMERICHOST)) { >+ strncpy(mbuf, "???", sizeof(mbuf)); >+ } >+ vstream_printf("%s/%s\n", abuf, mbuf); > } > vstream_fflush(VSTREAM_OUT); > inet_addr_list_free(&addr_list); >diff -Pur postfix-1.1.11-20020613-orig/src/util/inet_connect.c postfix-1.1.11-20020613/src/util/inet_connect.c >--- postfix-1.1.11-20020613-orig/src/util/inet_connect.c Mon Nov 20 19:06:31 2000 >+++ postfix-1.1.11-20020613/src/util/inet_connect.c Wed Jun 26 15:26:49 2002 >@@ -55,6 +55,9 @@ > #include <string.h> > #include <unistd.h> > #include <errno.h> >+#ifdef INET6 >+#include <netdb.h> >+#endif > > /* Utility library. */ > >@@ -73,7 +76,12 @@ > char *buf; > char *host; > char *port; >+#ifdef INET6 >+ struct addrinfo hints, *res, *res0; >+ int error; >+#else > struct sockaddr_in sin; >+#endif > int sock; > > /* >@@ -81,14 +89,58 @@ > * the local host. > */ > buf = inet_parse(addr, &host, &port); >+#ifdef INET6 >+ if (*host == 0) >+ host = NULL; >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = PF_UNSPEC; >+ hints.ai_socktype = SOCK_STREAM; >+ hints.ai_flags = AI_NUMERICHOST; /* find_inet_addr is numeric only */ >+ if (getaddrinfo(host, port, &hints, &res0)) >+ msg_fatal("host not found: %s", host); >+#else > if (*host == 0) > host = "localhost"; > memset((char *) &sin, 0, sizeof(sin)); > sin.sin_family = AF_INET; > sin.sin_addr.s_addr = find_inet_addr(host); > sin.sin_port = find_inet_port(port, "tcp"); >+#endif > myfree(buf); > >+#ifdef INET6 >+ sock = -1; >+ for (res = res0; res; res = res->ai_next) { >+ if ((res->ai_family != AF_INET) && (res->ai_family != AF_INET6)) >+ continue; >+ >+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol); >+ if (sock < 0) >+ continue; >+ if (timeout > 0) { >+ non_blocking(sock, NON_BLOCKING); >+ if (timed_connect(sock, res->ai_addr, res->ai_addrlen, timeout) < 0) { >+ close(sock); >+ sock = -1; >+ continue; >+ } >+ if (block_mode != NON_BLOCKING) >+ non_blocking(sock, block_mode); >+ break; >+ } else { >+ non_blocking(sock, block_mode); >+ if (connect(sock, res->ai_addr, res->ai_addrlen) < 0 >+ && errno != EINPROGRESS) { >+ close(sock); >+ sock = -1; >+ continue; >+ } >+ break; >+ } >+ } >+ freeaddrinfo(res0); >+ return sock; >+#else > /* > * Create a client socket. > */ >@@ -121,4 +173,5 @@ > } > return (sock); > } >+#endif > } >diff -Pur postfix-1.1.11-20020613-orig/src/util/inet_listen.c postfix-1.1.11-20020613/src/util/inet_listen.c >--- postfix-1.1.11-20020613-orig/src/util/inet_listen.c Mon Nov 20 19:06:32 2000 >+++ postfix-1.1.11-20020613/src/util/inet_listen.c Wed Jun 26 15:26:49 2002 >@@ -6,7 +6,7 @@ > /* SYNOPSIS > /* #include <listen.h> > /* >-/* int inet_listen(addr, backlog, block_mode) >+/* int inet_listen(addr, backlog, block_mode, addinuse_fatal) > /* const char *addr; > /* int backlog; > /* int block_mode; >@@ -51,11 +51,17 @@ > #include <sys_defs.h> > #include <sys/socket.h> > #include <netinet/in.h> >+#ifdef INET6 >+#if (! __GLIBC__ >= 2 && __GLIBC_MINOR__ >=1 ) >+#include <netinet6/in6.h> >+#endif >+#endif > #include <arpa/inet.h> > #include <netdb.h> > #ifndef MAXHOSTNAMELEN > #include <sys/param.h> > #endif >+#include <errno.h> > #include <string.h> > #include <unistd.h> > >@@ -77,35 +83,116 @@ > > /* inet_listen - create inet-domain listener */ > >-int inet_listen(const char *addr, int backlog, int block_mode) >+int inet_listen(const char *addr, int backlog, int block_mode, int addrinuse_fatal) > { >+#ifdef INET6 >+ struct addrinfo *res, *res0, hints; >+ int error; >+#else >+ struct ai { >+ int ai_family; >+ int ai_socktype; >+ int ai_protocol; >+ struct sockaddr *ai_addr; >+ SOCKADDR_SIZE ai_addrlen; >+ struct ai *ai_next; >+ } *res, *res0, resbody; > struct sockaddr_in sin; >+#endif > int sock; > int t = 1; >+ int addrinuse = 0; > char *buf; > char *host; > char *port; >+#ifdef INET6 >+ char hbuf[NI_MAXHOST], pbuf[NI_MAXSERV]; >+#else >+ char hbuf[sizeof("255.255.255.255") + 1]; >+ char pbuf[sizeof("255.255.255.255") + 1]; >+#endif >+ char *cause = "unknown"; > > /* > * Translate address information to internal form. > */ > buf = inet_parse(addr, &host, &port); >- memset((char *) &sin, 0, sizeof(sin)); >+#ifdef INET6 >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_flags = AI_PASSIVE; >+ hints.ai_family = AF_UNSPEC; >+ hints.ai_socktype = SOCK_STREAM; >+ error = getaddrinfo(*host ? host : NULL, *port ? port : "0", &hints, &res0); >+ if (error) { >+ msg_fatal("getaddrinfo: %s", gai_strerror(error)); >+ } >+ myfree(buf); >+#else >+ memset(&sin, 0, sizeof(sin)); > sin.sin_family = AF_INET; >+#ifdef HAS_SA_LEN >+ sin.sin_len = sizeof(sin); >+#endif > sin.sin_port = find_inet_port(port, "tcp"); > sin.sin_addr.s_addr = (*host ? find_inet_addr(host) : INADDR_ANY); >- myfree(buf); > >- /* >- * Create a listener socket. >- */ >- if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) >- msg_fatal("socket: %m"); >- if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) < 0) >- msg_fatal("setsockopt: %m"); >- if (bind(sock, (struct sockaddr *) & sin, sizeof(sin)) < 0) >- msg_fatal("bind %s port %d: %m", sin.sin_addr.s_addr == INADDR_ANY ? >- "INADDR_ANY" : inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); >+ memset(&resbody, 0, sizeof(resbody)); >+ resbody.ai_socktype = SOCK_STREAM; >+ resbody.ai_family = AF_INET; >+ resbody.ai_addr = (struct sockaddr *)&sin; >+ resbody.ai_addrlen = sizeof(sin); >+ >+ res0 = &resbody; >+#endif >+ >+ sock = -1; >+ for (res = res0; res; res = res->ai_next) { >+ if ((res->ai_family != AF_INET) && (res->ai_family != AF_INET6)) >+ continue; >+ >+ /* >+ * Create a listener socket. >+ */ >+ if ((sock = socket(res->ai_family, res->ai_socktype, 0)) < 0) { >+ cause = "socket"; >+ continue; >+ } >+#ifdef IPV6_V6ONLY >+ if (res->ai_family == AF_INET6 && >+ setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, (char *) &t, sizeof(t)) < 0) { >+ /* if kernel/libc don't support this simple ignore it >+ cause = "setsockopt(IPV6_V6ONLY)"; >+ close(sock); >+ sock = -1; >+ continue; >+ */ >+ ; >+ } >+#endif >+ if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *) &t, sizeof(t)) < 0) { >+ cause = "setsockopt(SO_REUSEADDR)"; >+ close(sock); >+ sock = -1; >+ continue; >+ } >+ >+ if (bind(sock, res->ai_addr, res->ai_addrlen) < 0) { >+ cause = "bind"; >+ if (errno == EADDRINUSE) >+ addrinuse = 1; >+ close(sock); >+ sock = -1; >+ continue; >+ } >+ break; >+ } >+ if (sock < 0 && (addrinuse_fatal || !addrinuse)) >+ msg_fatal("%s: %m", cause); >+#ifdef INET6 >+ freeaddrinfo(res0); >+#endif >+ if (sock < 0) >+ return -1; > non_blocking(sock, block_mode); > if (listen(sock, backlog) < 0) > msg_fatal("listen: %m"); >diff -Pur postfix-1.1.11-20020613-orig/src/util/listen.h postfix-1.1.11-20020613/src/util/listen.h >--- postfix-1.1.11-20020613-orig/src/util/listen.h Mon Mar 22 02:57:11 1999 >+++ postfix-1.1.11-20020613/src/util/listen.h Wed Jun 26 15:26:49 2002 >@@ -20,7 +20,7 @@ > * Listener external interface. > */ > extern int unix_listen(const char *, int, int); >-extern int inet_listen(const char *, int, int); >+extern int inet_listen(const char *, int, int, int); > extern int fifo_listen(const char *, int, int); > extern int stream_listen(const char *, int, int); > >diff -Pur postfix-1.1.11-20020613-orig/src/util/match_list.c postfix-1.1.11-20020613/src/util/match_list.c >--- postfix-1.1.11-20020613-orig/src/util/match_list.c Tue Nov 20 21:07:15 2001 >+++ postfix-1.1.11-20020613/src/util/match_list.c Wed Jun 26 15:26:49 2002 >@@ -118,7 +118,7 @@ > list = match_list_parse(list, vstring_str(buf)); > if (vstream_fclose(fp)) > msg_fatal("%s: read file %s: %m", myname, pattern); >- } else if (strchr(pattern, ':') != 0) { /* type:table */ >+ } else if ((strchr(pattern, ']') == 0) && (strchr(pattern, ':') != 0)) { /* type:table */ > for (cp = pattern; *cp == '!'; cp++) > /* void */ ; > if (dict_handle(pattern) == 0) >diff -Pur postfix-1.1.11-20020613-orig/src/util/match_ops.c postfix-1.1.11-20020613/src/util/match_ops.c >--- postfix-1.1.11-20020613-orig/src/util/match_ops.c Tue Nov 20 21:16:10 2001 >+++ postfix-1.1.11-20020613/src/util/match_ops.c Wed Jun 26 15:26:49 2002 >@@ -81,6 +81,307 @@ > #include <match_ops.h> > #include <stringops.h> > >+#ifdef INET6 >+/* >+ * $Id: match_ops.c,v 1.2 2000/05/22 12:01:17 misiek Exp $ >+ * >+ * This program is free software; you can redistribute it and/or >+ * modify it under the terms of the GNU General Public License >+ * as published by the Free Software Foundation; either version >+ * 2 of the License, or (at your option) any later version. >+ * >+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru> >+ * >+ * Modifications: >+ * Artur Frysiak <wiget@pld.org.pl> >+ * Arkadiusz Mi¶kiewicz <misiek@pld.org.pl> >+ */ >+ >+#include <stdio.h> >+#include <stdlib.h> >+#include <unistd.h> >+#include <syslog.h> >+#include <fcntl.h> >+#include <sys/socket.h> >+#include <netinet/in.h> >+#include <string.h> >+#include <netdb.h> >+#include <arpa/inet.h> >+#include <resolv.h> >+ >+#ifndef AF_DECnet >+#define AF_DECnet 12 >+#endif >+ >+#ifndef PF_PACKET >+#define PF_PACKET 17 >+#endif >+ >+typedef struct >+{ >+ unsigned char family; >+ unsigned char bytelen; >+ signed short bitlen; >+ unsigned int data[4]; >+} inet_prefix; >+ >+/* prototypes */ >+int masked_match(char *, char *, char *); >+int get_integer(int *, char *, int); >+int get_addr_1(inet_prefix *, char *, int); >+int get_prefix_1(inet_prefix *, char *, int); >+int get_addr(inet_prefix *, char *, int); >+int get_prefix(inet_prefix *, char *, int); >+unsigned int get_addr32(char *); >+int matches(char *, char *); >+int inet_addr_match(inet_prefix *, inet_prefix *, int); >+int mask_match(char *, char *, char *); >+ >+int get_integer(int *val, char *arg, int base) >+{ >+ long res; >+ char *ptr; >+ >+ if (!arg || !*arg) >+ return -1; >+ res = strtol(arg, &ptr, base); >+ if (!ptr || ptr == arg || *ptr || res > INT_MAX || res < INT_MIN) >+ return -1; >+ *val = res; >+ return 0; >+} >+ >+int get_addr_1(inet_prefix *addr, char *name, int family) >+{ >+ char *cp; >+ unsigned char *ap = (unsigned char*)addr->data; >+ int i; >+ >+ memset(addr, 0, sizeof(*addr)); >+ >+ if (strcmp(name, "default") == 0 || strcmp(name, "any") == 0) { >+ if (family == AF_DECnet) >+ return -1; >+ addr->family = family; >+ addr->bytelen = (family == AF_INET6 ? 16 : 4); >+ addr->bitlen = -1; >+ return 0; >+ } >+ >+ if (strchr(name, ':')) { >+ addr->family = AF_INET6; >+ if (family != AF_UNSPEC && family != AF_INET6) >+ return -1; >+ if (inet_pton(AF_INET6, name, addr->data) <= 0) >+ return -1; >+ addr->bytelen = 16; >+ addr->bitlen = -1; >+ return 0; >+ } >+ addr->family = AF_INET; >+ if (family != AF_UNSPEC && family != AF_INET) >+ return -1; >+ addr->bytelen = 4; >+ addr->bitlen = -1; >+ for (cp = name, i = 0; *cp; cp++) { >+ if (*cp <= '9' && *cp >= '0') { >+ ap[i] = 10*ap[i] + (*cp-'0'); >+ continue; >+ } >+ if (*cp == '.' && ++i <= 3) >+ continue; >+ return -1; >+ } >+ return 0; >+} >+ >+int get_prefix_1(inet_prefix *dst, char *arg, int family) >+{ >+ int err; >+ unsigned plen; >+ char *slash; >+ >+ memset(dst, 0, sizeof(*dst)); >+ >+ if (strcmp(arg, "default") == 0 || strcmp(arg, "any") == 0) { >+ if (family == AF_DECnet) >+ return -1; >+ dst->family = family; >+ dst->bytelen = 0; >+ dst->bitlen = 0; >+ return 0; >+ } >+ >+ slash = strchr(arg, '/'); >+ if (slash) >+ *slash = 0; >+ err = get_addr_1(dst, arg, family); >+ if (err == 0) { >+ switch(dst->family) { >+ case AF_INET6: >+ dst->bitlen = 128; >+ break; >+ case AF_DECnet: >+ dst->bitlen = 16; >+ break; >+ default: >+ case AF_INET: >+ dst->bitlen = 32; >+ } >+ if (slash) { >+ if (get_integer(&plen, slash+1, 0) || plen > dst->bitlen) { >+ err = -1; >+ goto done; >+ } >+ dst->bitlen = plen; >+ } >+ } >+done: >+ if (slash) >+ *slash = '/'; >+ return err; >+} >+ >+int get_addr(inet_prefix *dst, char *arg, int family) >+{ >+#ifdef AF_PACKET >+ if (family == AF_PACKET) >+ return -1; >+#endif >+ if (get_addr_1(dst, arg, family)) >+ return -1; >+ return 0; >+} >+ >+int get_prefix(inet_prefix *dst, char *arg, int family) >+{ >+#ifdef AF_PACKET >+ if (family == AF_PACKET) >+ return -1; >+#endif >+ if (get_prefix_1(dst, arg, family)) >+ return -1; >+ return 0; >+} >+ >+unsigned int get_addr32(char *name) >+{ >+ inet_prefix addr; >+ if (get_addr_1(&addr, name, AF_INET)) >+ return -1; >+ return addr.data[0]; >+} >+ >+int matches(char *cmd, char *pattern) >+{ >+ int len = strlen(cmd); >+ if (len > strlen(pattern)) >+ return -1; >+ return memcmp(pattern, cmd, len); >+} >+ >+int inet_addr_match(inet_prefix *a, inet_prefix *b, int bits) >+{ >+ unsigned int *a1 = a->data; >+ unsigned int *a2 = b->data; >+ int words = bits >> 0x05; >+ >+ bits &= 0x1f; >+ >+ if (words) >+ if (memcmp(a1, a2, words << 2)) >+ return -1; >+ >+ if (bits) { >+ unsigned int w1, w2; >+ unsigned int mask; >+ >+ w1 = a1[words]; >+ w2 = a2[words]; >+ >+ mask = htonl((0xffffffff) << (0x20 - bits)); >+ >+ if ((w1 ^ w2) & mask) >+ return 1; >+ } >+ >+ return 0; >+} >+ >+/* zero if matches */ >+int mask_match(char *network, char *cprefix, char *address) >+{ >+ inet_prefix *inetwork; >+ inet_prefix *iaddress; >+ int ret, prefix; >+ >+ if (!(network && address && cprefix)) >+ return -1; >+ prefix = strtol(cprefix, (char **)NULL, 10); >+ if ((prefix < 0) || (prefix > 128)) >+ return -1; >+ if ((strlen(network) == 0) || (strlen(address) == 0)) >+ return -1; >+ >+ inetwork = malloc(sizeof(inet_prefix)); >+ iaddress = malloc(sizeof(inet_prefix)); >+ >+ if ((get_addr(iaddress, address, AF_UNSPEC) >= 0) >+ && (get_addr(inetwork, network, AF_UNSPEC) >= 0)) >+ ret = inet_addr_match(inetwork, iaddress, prefix); >+ else >+ ret = -1; >+ free(inetwork); >+ free(iaddress); >+ >+ /* 1 if matches */ >+ /* return (!ret); */ >+ /* 0 if matches */ >+ return ret; >+} >+ >+/* >+ * masked_match() - universal for IPv4 and IPv6 - 1 if matches >+ */ >+int masked_match(net_tok, mask_tok, string) >+char *net_tok; >+char *mask_tok; >+char *string; >+{ >+#ifdef INET6 >+ struct in6_addr in6[2]; >+ char v4addr[2][INET_ADDRSTRLEN]; >+ char newmask[6]; >+ int plen; >+#endif >+ >+ /* Check for NULL */ >+ if (!(net_tok && mask_tok && string)) >+ return 0; /* doesn't match!!! */ >+ >+ /* If IPv6 mapped convert to native-IPv4 */ >+#ifdef INET6 >+ if (inet_pton(AF_INET6, net_tok, &in6[0]) == 1 && >+ inet_pton(AF_INET6, string, &in6[1]) == 1 && >+ IN6_IS_ADDR_V4MAPPED(&in6[0]) && IN6_IS_ADDR_V4MAPPED(&in6[1])) { >+ plen = atoi(mask_tok); >+ if (32 < plen && plen < 129) { >+ sprintf(newmask, "%d", plen - 96); >+ mask_tok = newmask; >+ } >+ >+ (void)inet_ntop(AF_INET, &in6[0].s6_addr[12], v4addr[0], >+ sizeof(v4addr[0])); >+ net_tok = v4addr[0]; >+ (void)inet_ntop(AF_INET, &in6[1].s6_addr[12], v4addr[1], >+ sizeof(v4addr[1])); >+ string = v4addr[1]; >+ } >+#endif >+ return (!mask_match(net_tok, mask_tok, string)); >+} >+#endif >+ > /* match_string - match a string literal */ > > int match_string(int unused_flags, const char *string, const char *pattern) >@@ -177,6 +478,7 @@ > return (0); > } > >+#ifndef INET6 > /* match_parse_mask - parse net/mask pattern */ > > static int match_parse_mask(const char *pattern, unsigned long *net_bits, >@@ -198,27 +500,55 @@ > return (mask != 0); > } > >+#endif >+ > /* match_hostaddr - match host by address */ > > int match_hostaddr(int unused_flags, const char *addr, const char *pattern) > { > char *myname = "match_hostaddr"; >+#ifdef INET6 >+ char *network, *mask, *escl, *escr, *patternx; >+ struct in6_addr in6; >+ char v4addr[INET_ADDRSTRLEN]; >+#else > int mask_shift; > unsigned long mask_bits; > unsigned long net_bits; > unsigned long addr_bits; >+#endif > > if (msg_verbose) > msg_info("%s: %s ~? %s", myname, addr, pattern); > >+#ifdef INET6 >+ if (addr[strspn(addr, "01234567890./:abcdef")] != 0) >+#else > if (addr[strspn(addr, "01234567890./:")] != 0) >+#endif > return (0); > >+#ifdef INET6 >+ patternx = mystrdup(pattern); >+ escl = strchr(patternx,'['); >+ escr = strrchr(patternx,']'); >+ if (escl && escr) { >+ *escr = 0; >+ sprintf(patternx, "%s%s", escl + 1, escr + 1); >+ pattern = patternx; >+ } >+#endif >+ > /* > * Try dictionary lookup. This can be case insensitive. XXX Probably > * should also try again after stripping least significant octets. > */ >- if (strchr(pattern, ':') != 0) { >+#ifdef INET6 >+ if (!(escl && escr) && strchr(pattern, ':') != 0) >+#else >+ if (strchr(pattern, ':') != 0) >+#endif >+ { > if (dict_lookup(pattern, addr) != 0) > return (1); > if (dict_errno != 0) >@@ -229,6 +559,12 @@ > /* > * Try an exact match with the host address. > */ >+#ifdef INET6 >+ if (inet_pton(AF_INET6, addr, &in6) == 1 && IN6_IS_ADDR_V4MAPPED(&in6)) { >+ (void)inet_ntop(AF_INET, &in6.s6_addr[12], v4addr, sizeof(v4addr)); >+ addr = v4addr; >+ } >+#endif > if (strcasecmp(addr, pattern) == 0) { > return (1); > } >@@ -237,6 +573,20 @@ > * In a net/mask pattern, the mask is specified as the number of bits of > * the network part. > */ >+#ifdef INET6 >+ network = mystrdup(patternx); >+ mask = split_at(network, '/'); >+ >+ if (masked_match(network, mask, (char *)addr)) { >+ myfree(network); >+ myfree(patternx); >+ return (1); >+ } else { >+ myfree(network); >+ myfree(patternx); >+ } >+#else >+ > if (match_parse_mask(pattern, &net_bits, &mask_shift)) { > addr_bits = inet_addr(addr); > if (addr_bits == INADDR_NONE) >@@ -244,5 +594,6 @@ > mask_bits = htonl((0xffffffff) << (BITS_PER_ADDR - mask_shift)); > return ((addr_bits & mask_bits) == (net_bits & mask_bits)); > } >+#endif > return (0); > } >diff -Pur postfix-1.1.11-20020613-orig/src/util/sdbm.c postfix-1.1.11-20020613/src/util/sdbm.c >--- postfix-1.1.11-20020613-orig/src/util/sdbm.c Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/util/sdbm.c Wed Jun 26 15:26:49 2002 >@@ -0,0 +1,971 @@ >+/*++ >+/* NAME >+/* sdbm 3h >+/* SUMMARY >+/* SDBM Simple DBM: ndbm work-alike hashed database library >+/* SYNOPSIS >+/* include "sdbm.h" >+/* DESCRIPTION >+/* This file includes the public domain SDBM (ndbm work-alike hashed >+/* database library), based on Per-Aake Larson's Dynamic Hashing >+/* algorithms. BIT 18 (1978). >+/* author: oz@nexus.yorku.ca >+/* status: public domain >+/* The file has been patched following the advice of Uwe Ohse >+/* <uwe@ohse.de>: >+/* -------------------------------------------------------------- >+/* this patch fixes a problem with sdbms .dir file, which arrises when >+/* a second .dir block is needed for the first time. read() returns 0 >+/* in that case, and the library forgot to initialize that new block. >+/* >+/* A related problem is that the calculation of db->maxbno is wrong. >+/* It just appends 4096*BYTESIZ bits, which is not enough except for >+/* small databases (.dir basically doubles everytime it's too small). >+/* -------------------------------------------------------------- >+/* According to Uwe Ohse, the patch has also been submitted to the >+/* author of SDBM. (The 4096*BYTESIZ bits comment may apply with a >+/* different size for Postfix/TLS, as the patch was sent against the >+/* original SDBM distributiona and for Postfix/TLS I have changed the >+/* default sizes. >+/* .nf >+/*--*/ >+ >+/* >+ * sdbm - ndbm work-alike hashed database library >+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). >+ * author: oz@nexus.yorku.ca >+ * status: public domain. >+ * >+ * core routines >+ */ >+ >+#include <stdio.h> >+#include <stdlib.h> >+#ifdef WIN32 >+#include <io.h> >+#include <errno.h> >+#else >+#include <unistd.h> >+#endif >+#include <sys/types.h> >+#include <sys/stat.h> >+#include <fcntl.h> >+#include <errno.h> >+#include <string.h> >+#ifdef __STDC__ >+#include <stddef.h> >+#endif >+ >+#include <sdbm.h> >+ >+/* >+ * useful macros >+ */ >+#define bad(x) ((x).dptr == NULL || (x).dsize <= 0) >+#define exhash(item) sdbm_hash((item).dptr, (item).dsize) >+#define ioerr(db) ((db)->flags |= DBM_IOERR) >+ >+#define OFF_PAG(off) (long) (off) * PBLKSIZ >+#define OFF_DIR(off) (long) (off) * DBLKSIZ >+ >+static long masks[] = >+{ >+ 000000000000, 000000000001, 000000000003, 000000000007, >+ 000000000017, 000000000037, 000000000077, 000000000177, >+ 000000000377, 000000000777, 000000001777, 000000003777, >+ 000000007777, 000000017777, 000000037777, 000000077777, >+ 000000177777, 000000377777, 000000777777, 000001777777, >+ 000003777777, 000007777777, 000017777777, 000037777777, >+ 000077777777, 000177777777, 000377777777, 000777777777, >+ 001777777777, 003777777777, 007777777777, 017777777777 >+}; >+ >+datum nullitem = >+{NULL, 0}; >+ >+typedef struct >+{ >+ int dirf; /* directory file descriptor */ >+ int pagf; /* page file descriptor */ >+ int flags; /* status/error flags, see below */ >+ long maxbno; /* size of dirfile in bits */ >+ long curbit; /* current bit number */ >+ long hmask; /* current hash mask */ >+ long blkptr; /* current block for nextkey */ >+ int keyptr; /* current key for nextkey */ >+ long blkno; /* current page to read/write */ >+ long pagbno; /* current page in pagbuf */ >+ char *pagbuf; /* page file block buffer */ >+ long dirbno; /* current block in dirbuf */ >+ char *dirbuf; /* directory file block buffer */ >+} DBM; >+ >+ >+/* ************************* */ >+ >+/* >+ * sdbm - ndbm work-alike hashed database library >+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). >+ * author: oz@nexus.yorku.ca >+ * status: public domain. keep it that way. >+ * >+ * hashing routine >+ */ >+ >+/* >+ * polynomial conversion ignoring overflows >+ * [this seems to work remarkably well, in fact better >+ * then the ndbm hash function. Replace at your own risk] >+ * use: 65599 nice. >+ * 65587 even better. >+ */ >+static long sdbm_hash (char *str, int len) >+{ >+ unsigned long n = 0; >+ >+#ifdef DUFF >+#define HASHC n = *str++ + 65599 * n >+ if (len > 0) >+ { >+ int loop = (len + 8 - 1) >> 3; >+ >+ switch (len & (8 - 1)) >+ { >+ case 0: >+ do >+ { >+ HASHC; >+ case 7: >+ HASHC; >+ case 6: >+ HASHC; >+ case 5: >+ HASHC; >+ case 4: >+ HASHC; >+ case 3: >+ HASHC; >+ case 2: >+ HASHC; >+ case 1: >+ HASHC; >+ } >+ while (--loop); >+ } >+ >+ } >+#else >+ while (len--) >+ n = *str++ + 65599 * n; >+#endif >+ return n; >+} >+ >+/* >+ * check page sanity: >+ * number of entries should be something >+ * reasonable, and all offsets in the index should be in order. >+ * this could be made more rigorous. >+ */ >+static int chkpage (char *pag) >+{ >+ int n; >+ int off; >+ short *ino = (short *) pag; >+ >+ if ((n = ino[0]) < 0 || n > PBLKSIZ / sizeof (short)) >+ return 0; >+ >+ if (n > 0) >+ { >+ off = PBLKSIZ; >+ for (ino++; n > 0; ino += 2) >+ { >+ if (ino[0] > off || ino[1] > off || >+ ino[1] > ino[0]) >+ return 0; >+ off = ino[1]; >+ n -= 2; >+ } >+ } >+ return 1; >+} >+ >+/* >+ * search for the key in the page. >+ * return offset index in the range 0 < i < n. >+ * return 0 if not found. >+ */ >+static int seepair (char *pag, int n, char *key, int siz) >+{ >+ int i; >+ int off = PBLKSIZ; >+ short *ino = (short *) pag; >+ >+ for (i = 1; i < n; i += 2) >+ { >+ if (siz == off - ino[i] && >+ memcmp (key, pag + ino[i], siz) == 0) >+ return i; >+ off = ino[i + 1]; >+ } >+ return 0; >+} >+ >+#ifdef SEEDUPS >+static int duppair (char *pag, datum key) >+{ >+ short *ino = (short *) pag; >+ >+ return ino[0] > 0 && seepair (pag, ino[0], key.dptr, key.dsize) > 0; >+} >+ >+#endif >+ >+/* ************************* */ >+ >+/* >+ * sdbm - ndbm work-alike hashed database library >+ * based on Per-Aake Larson's Dynamic Hashing algorithms. BIT 18 (1978). >+ * author: oz@nexus.yorku.ca >+ * status: public domain. >+ * >+ * page-level routines >+ */ >+ >+/* >+ * page format: >+ * +------------------------------+ >+ * ino | n | keyoff | datoff | keyoff | >+ * +------------+--------+--------+ >+ * | datoff | - - - ----> | >+ * +--------+---------------------+ >+ * | F R E E A R E A | >+ * +--------------+---------------+ >+ * | <---- - - - | data | >+ * +--------+-----+----+----------+ >+ * | key | data | key | >+ * +--------+----------+----------+ >+ * >+ * calculating the offsets for free area: if the number >+ * of entries (ino[0]) is zero, the offset to the END of >+ * the free area is the block size. Otherwise, it is the >+ * nth (ino[ino[0]]) entry's offset. >+ */ >+ >+static int fitpair (char *pag, int need) >+{ >+ int n; >+ int off; >+ int avail; >+ short *ino = (short *) pag; >+ >+ off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ; >+ avail = off - (n + 1) * sizeof (short); >+ need += 2 * sizeof (short); >+ >+ return need <= avail; >+} >+ >+static void putpair (char *pag, datum key, datum val) >+{ >+ int n; >+ int off; >+ short *ino = (short *) pag; >+ >+ off = ((n = ino[0]) > 0) ? ino[n] : PBLKSIZ; >+/* >+ * enter the key first >+ */ >+ off -= key.dsize; >+ (void) memcpy (pag + off, key.dptr, key.dsize); >+ ino[n + 1] = off; >+/* >+ * now the data >+ */ >+ off -= val.dsize; >+ (void) memcpy (pag + off, val.dptr, val.dsize); >+ ino[n + 2] = off; >+/* >+ * adjust item count >+ */ >+ ino[0] += 2; >+} >+ >+static datum getpair (char *pag, datum key) >+{ >+ int i; >+ int n; >+ datum val; >+ short *ino = (short *) pag; >+ >+ if ((n = ino[0]) == 0) >+ return nullitem; >+ >+ if ((i = seepair (pag, n, key.dptr, key.dsize)) == 0) >+ return nullitem; >+ >+ val.dptr = pag + ino[i + 1]; >+ val.dsize = ino[i] - ino[i + 1]; >+ return val; >+} >+ >+static datum getnkey (char *pag, int num) >+{ >+ datum key; >+ int off; >+ short *ino = (short *) pag; >+ >+ num = num * 2 - 1; >+ if (ino[0] == 0 || num > ino[0]) >+ return nullitem; >+ >+ off = (num > 1) ? ino[num - 1] : PBLKSIZ; >+ >+ key.dptr = pag + ino[num]; >+ key.dsize = off - ino[num]; >+ >+ return key; >+} >+ >+static int delpair (char *pag, datum key) >+{ >+ int n; >+ int i; >+ short *ino = (short *) pag; >+ >+ if ((n = ino[0]) == 0) >+ return 0; >+ >+ if ((i = seepair (pag, n, key.dptr, key.dsize)) == 0) >+ return 0; >+/* >+ * found the key. if it is the last entry >+ * [i.e. i == n - 1] we just adjust the entry count. >+ * hard case: move all data down onto the deleted pair, >+ * shift offsets onto deleted offsets, and adjust them. >+ * [note: 0 < i < n] >+ */ >+ if (i < n - 1) >+ { >+ int m; >+ char *dst = pag + (i == 1 ? PBLKSIZ : ino[i - 1]); >+ char *src = pag + ino[i + 1]; >+ int zoo = dst - src; >+ >+/* >+ * shift data/keys down >+ */ >+ m = ino[i + 1] - ino[n]; >+#ifdef DUFF >+#define MOVB *--dst = *--src >+ if (m > 0) >+ { >+ int loop = (m + 8 - 1) >> 3; >+ >+ switch (m & (8 - 1)) >+ { >+ case 0: >+ do >+ { >+ MOVB; >+ case 7: >+ MOVB; >+ case 6: >+ MOVB; >+ case 5: >+ MOVB; >+ case 4: >+ MOVB; >+ case 3: >+ MOVB; >+ case 2: >+ MOVB; >+ case 1: >+ MOVB; >+ } >+ while (--loop); >+ } >+ } >+#else >+ dst -= m; >+ src -= m; >+ memmove (dst, src, m); >+#endif >+/* >+ * adjust offset index up >+ */ >+ while (i < n - 1) >+ { >+ ino[i] = ino[i + 2] + zoo; >+ i++; >+ } >+ } >+ ino[0] -= 2; >+ return 1; >+} >+ >+static void splpage (char *pag, char *new, long sbit) >+{ >+ datum key; >+ datum val; >+ >+ int n; >+ int off = PBLKSIZ; >+ char cur[PBLKSIZ]; >+ short *ino = (short *) cur; >+ >+ (void) memcpy (cur, pag, PBLKSIZ); >+ (void) memset (pag, 0, PBLKSIZ); >+ (void) memset (new, 0, PBLKSIZ); >+ >+ n = ino[0]; >+ for (ino++; n > 0; ino += 2) >+ { >+ key.dptr = cur + ino[0]; >+ key.dsize = off - ino[0]; >+ val.dptr = cur + ino[1]; >+ val.dsize = ino[0] - ino[1]; >+/* >+ * select the page pointer (by looking at sbit) and insert >+ */ >+ (void) putpair ((exhash (key) & sbit) ? new : pag, key, val); >+ >+ off = ino[1]; >+ n -= 2; >+ } >+} >+ >+static int getdbit (DBM * db, long dbit) >+{ >+ long c; >+ long dirb; >+ >+ c = dbit / BYTESIZ; >+ dirb = c / DBLKSIZ; >+ >+ if (dirb != db->dirbno) >+ { >+ int got; >+ if (lseek (db->dirf, OFF_DIR (dirb), SEEK_SET) < 0 >+ || (got = read(db->dirf, db->dirbuf, DBLKSIZ)) < 0) >+ return 0; >+ if (got==0) >+ memset(db->dirbuf,0,DBLKSIZ); >+ db->dirbno = dirb; >+ } >+ >+ return db->dirbuf[c % DBLKSIZ] & (1 << dbit % BYTESIZ); >+} >+ >+static int setdbit (DBM * db, long dbit) >+{ >+ long c; >+ long dirb; >+ >+ c = dbit / BYTESIZ; >+ dirb = c / DBLKSIZ; >+ >+ if (dirb != db->dirbno) >+ { >+ int got; >+ if (lseek (db->dirf, OFF_DIR (dirb), SEEK_SET) < 0 >+ || (got = read(db->dirf, db->dirbuf, DBLKSIZ)) < 0) >+ return 0; >+ if (got==0) >+ memset(db->dirbuf,0,DBLKSIZ); >+ db->dirbno = dirb; >+ } >+ >+ db->dirbuf[c % DBLKSIZ] |= (1 << dbit % BYTESIZ); >+ >+#if 0 >+ if (dbit >= db->maxbno) >+ db->maxbno += DBLKSIZ * BYTESIZ; >+#else >+ if (OFF_DIR((dirb+1))*BYTESIZ > db->maxbno) >+ db->maxbno=OFF_DIR((dirb+1))*BYTESIZ; >+#endif >+ >+ if (lseek (db->dirf, OFF_DIR (dirb), SEEK_SET) < 0 >+ || write (db->dirf, db->dirbuf, DBLKSIZ) < 0) >+ return 0; >+ >+ return 1; >+} >+ >+/* >+ * getnext - get the next key in the page, and if done with >+ * the page, try the next page in sequence >+ */ >+static datum getnext (DBM * db) >+{ >+ datum key; >+ >+ for (;;) >+ { >+ db->keyptr++; >+ key = getnkey (db->pagbuf, db->keyptr); >+ if (key.dptr != NULL) >+ return key; >+/* >+ * we either run out, or there is nothing on this page.. >+ * try the next one... If we lost our position on the >+ * file, we will have to seek. >+ */ >+ db->keyptr = 0; >+ if (db->pagbno != db->blkptr++) >+ if (lseek (db->pagf, OFF_PAG (db->blkptr), SEEK_SET) < 0) >+ break; >+ db->pagbno = db->blkptr; >+ if (read (db->pagf, db->pagbuf, PBLKSIZ) <= 0) >+ break; >+ if (!chkpage (db->pagbuf)) >+ break; >+ } >+ >+ return ioerr (db), nullitem; >+} >+ >+/* >+ * all important binary trie traversal >+ */ >+static int getpage (DBM * db, long hash) >+{ >+ int hbit; >+ long dbit; >+ long pagb; >+ >+ dbit = 0; >+ hbit = 0; >+ while (dbit < db->maxbno && getdbit (db, dbit)) >+ dbit = 2 * dbit + ((hash & (1 << hbit++)) ? 2 : 1); >+ >+ db->curbit = dbit; >+ db->hmask = masks[hbit]; >+ >+ pagb = hash & db->hmask; >+/* >+ * see if the block we need is already in memory. >+ * note: this lookaside cache has about 10% hit rate. >+ */ >+ if (pagb != db->pagbno) >+ { >+/* >+ * note: here, we assume a "hole" is read as 0s. >+ * if not, must zero pagbuf first. >+ */ >+ if (lseek (db->pagf, OFF_PAG (pagb), SEEK_SET) < 0 >+ || read (db->pagf, db->pagbuf, PBLKSIZ) < 0) >+ return 0; >+ if (!chkpage (db->pagbuf)) >+ return 0; >+ db->pagbno = pagb; >+ } >+ return 1; >+} >+ >+/* >+ * makroom - make room by splitting the overfull page >+ * this routine will attempt to make room for SPLTMAX times before >+ * giving up. >+ */ >+static int makroom (DBM * db, long hash, int need) >+{ >+ long newp; >+ char twin[PBLKSIZ]; >+ char *pag = db->pagbuf; >+ char *new = twin; >+ int smax = SPLTMAX; >+ >+ do >+ { >+/* >+ * split the current page >+ */ >+ (void) splpage (pag, new, db->hmask + 1); >+/* >+ * address of the new page >+ */ >+ newp = (hash & db->hmask) | (db->hmask + 1); >+ >+/* >+ * write delay, read avoidence/cache shuffle: >+ * select the page for incoming pair: if key is to go to the new page, >+ * write out the previous one, and copy the new one over, thus making >+ * it the current page. If not, simply write the new page, and we are >+ * still looking at the page of interest. current page is not updated >+ * here, as sdbm_store will do so, after it inserts the incoming pair. >+ */ >+ if (hash & (db->hmask + 1)) >+ { >+ if (lseek (db->pagf, OFF_PAG (db->pagbno), SEEK_SET) < 0 >+ || write (db->pagf, db->pagbuf, PBLKSIZ) < 0) >+ return 0; >+ db->pagbno = newp; >+ (void) memcpy (pag, new, PBLKSIZ); >+ } >+ else if (lseek (db->pagf, OFF_PAG (newp), SEEK_SET) < 0 >+ || write (db->pagf, new, PBLKSIZ) < 0) >+ return 0; >+ >+ if (!setdbit (db, db->curbit)) >+ return 0; >+/* >+ * see if we have enough room now >+ */ >+ if (fitpair (pag, need)) >+ return 1; >+/* >+ * try again... update curbit and hmask as getpage would have >+ * done. because of our update of the current page, we do not >+ * need to read in anything. BUT we have to write the current >+ * [deferred] page out, as the window of failure is too great. >+ */ >+ db->curbit = 2 * db->curbit + >+ ((hash & (db->hmask + 1)) ? 2 : 1); >+ db->hmask |= db->hmask + 1; >+ >+ if (lseek (db->pagf, OFF_PAG (db->pagbno), SEEK_SET) < 0 >+ || write (db->pagf, db->pagbuf, PBLKSIZ) < 0) >+ return 0; >+ >+ } >+ while (--smax); >+/* >+ * if we are here, this is real bad news. After SPLTMAX splits, >+ * we still cannot fit the key. say goodnight. >+ */ >+#ifdef BADMESS >+ (void) write (2, "sdbm: cannot insert after SPLTMAX attempts.\n", 44); >+#endif >+ return 0; >+ >+} >+ >+static SDBM *sdbm_prep (char *dirname, char *pagname, int flags, int mode) >+{ >+ SDBM *db; >+ struct stat dstat; >+ >+ if ((db = (SDBM *) mymalloc (sizeof (SDBM))) == NULL) >+ return errno = ENOMEM, (SDBM *) NULL; >+ >+ db->flags = 0; >+ db->blkptr = 0; >+ db->keyptr = 0; >+/* >+ * adjust user flags so that WRONLY becomes RDWR, >+ * as required by this package. Also set our internal >+ * flag for RDONLY if needed. >+ */ >+ if (flags & O_WRONLY) >+ flags = (flags & ~O_WRONLY) | O_RDWR; >+ else if ((flags & 03) == O_RDONLY) >+ db->flags = DBM_RDONLY; >+#if defined(OS2) || defined(MSDOS) || defined(WIN32) >+ flags |= O_BINARY; >+#endif >+ >+/* >+ * Make sure to ignore the O_EXCL option, as the file might exist due >+ * to the locking. >+ */ >+ flags &= ~O_EXCL; >+ >+/* >+ * open the files in sequence, and stat the dirfile. >+ * If we fail anywhere, undo everything, return NULL. >+ */ >+ >+ if ((db->pagf = open (pagname, flags, mode)) > -1) >+ { >+ if ((db->dirf = open (dirname, flags, mode)) > -1) >+ { >+/* >+ * need the dirfile size to establish max bit number. >+ */ >+ if (fstat (db->dirf, &dstat) == 0) >+ { >+ /* >+ * success >+ */ >+ return db; >+ } >+ msg_info ("closing dirf"); >+ (void) close (db->dirf); >+ } >+ msg_info ("closing pagf"); >+ (void) close (db->pagf); >+ } >+ myfree ((char *) db); >+ return (SDBM *) NULL; >+} >+ >+static DBM *sdbm_internal_open (SDBM * sdbm) >+{ >+ DBM *db; >+ struct stat dstat; >+ >+ if ((db = (DBM *) mymalloc (sizeof (DBM))) == NULL) >+ return errno = ENOMEM, (DBM *) NULL; >+ >+ db->flags = sdbm->flags; >+ db->hmask = 0; >+ db->blkptr = sdbm->blkptr; >+ db->keyptr = sdbm->keyptr; >+ db->pagf = sdbm->pagf; >+ db->dirf = sdbm->dirf; >+ db->pagbuf = sdbm->pagbuf; >+ db->dirbuf = sdbm->dirbuf; >+ >+/* >+ * need the dirfile size to establish max bit number. >+ */ >+ if (fstat (db->dirf, &dstat) == 0) >+ { >+/* >+ * zero size: either a fresh database, or one with a single, >+ * unsplit data page: dirpage is all zeros. >+ */ >+ db->dirbno = (!dstat.st_size) ? 0 : -1; >+ db->pagbno = -1; >+ db->maxbno = dstat.st_size * BYTESIZ; >+ >+ (void) memset (db->pagbuf, 0, PBLKSIZ); >+ (void) memset (db->dirbuf, 0, DBLKSIZ); >+ return db; >+ } >+ myfree ((char *) db); >+ return (DBM *) NULL; >+} >+ >+static void sdbm_internal_close (DBM * db) >+{ >+ if (db == NULL) >+ errno = EINVAL; >+ else >+ { >+ myfree ((char *) db); >+ } >+} >+ >+datum sdbm_fetch (SDBM * sdb, datum key) >+{ >+ datum retval; >+ DBM *db; >+ >+ if (sdb == NULL || bad (key)) >+ return errno = EINVAL, nullitem; >+ >+ if (!(db = sdbm_internal_open (sdb))) >+ return errno = EINVAL, nullitem; >+ >+ if (getpage (db, exhash (key))) >+ { >+ retval = getpair (db->pagbuf, key); >+ sdbm_internal_close (db); >+ return retval; >+ } >+ >+ sdbm_internal_close (db); >+ >+ return ioerr (sdb), nullitem; >+} >+ >+int sdbm_delete (SDBM * sdb, datum key) >+{ >+ int retval; >+ DBM *db; >+ >+ if (sdb == NULL || bad (key)) >+ return errno = EINVAL, -1; >+ if (sdbm_rdonly (sdb)) >+ return errno = EPERM, -1; >+ >+ if (!(db = sdbm_internal_open (sdb))) >+ return errno = EINVAL, -1; >+ >+ if (getpage (db, exhash (key))) >+ { >+ if (!delpair (db->pagbuf, key)) >+ retval = -1; >+/* >+ * update the page file >+ */ >+ else if (lseek (db->pagf, OFF_PAG (db->pagbno), SEEK_SET) < 0 >+ || write (db->pagf, db->pagbuf, PBLKSIZ) < 0) >+ retval = ioerr (sdb), -1; >+ else >+ retval = 0; >+ } >+ else >+ retval = ioerr (sdb), -1; >+ >+ sdbm_internal_close (db); >+ >+ return retval; >+} >+ >+int sdbm_store (SDBM * sdb, datum key, datum val, int flags) >+{ >+ int need; >+ int retval; >+ long hash; >+ DBM *db; >+ >+ if (sdb == NULL || bad (key)) >+ return errno = EINVAL, -1; >+ if (sdbm_rdonly (sdb)) >+ return errno = EPERM, -1; >+ >+ need = key.dsize + val.dsize; >+/* >+ * is the pair too big (or too small) for this database ?? >+ */ >+ if (need < 0 || need > PAIRMAX) >+ return errno = EINVAL, -1; >+ >+ if (!(db = sdbm_internal_open (sdb))) >+ return errno = EINVAL, -1; >+ >+ if (getpage (db, (hash = exhash (key)))) >+ { >+/* >+ * if we need to replace, delete the key/data pair >+ * first. If it is not there, ignore. >+ */ >+ if (flags == DBM_REPLACE) >+ (void) delpair (db->pagbuf, key); >+#ifdef SEEDUPS >+ else if (duppair (db->pagbuf, key)) >+ { >+ sdbm_internal_close (db); >+ return 1; >+ } >+#endif >+/* >+ * if we do not have enough room, we have to split. >+ */ >+ if (!fitpair (db->pagbuf, need)) >+ if (!makroom (db, hash, need)) >+ { >+ sdbm_internal_close (db); >+ return ioerr (db), -1; >+ } >+/* >+ * we have enough room or split is successful. insert the key, >+ * and update the page file. >+ */ >+ (void) putpair (db->pagbuf, key, val); >+ >+ if (lseek (db->pagf, OFF_PAG (db->pagbno), SEEK_SET) < 0 >+ || write (db->pagf, db->pagbuf, PBLKSIZ) < 0) >+ { >+ sdbm_internal_close (db); >+ return ioerr (db), -1; >+ } >+ /* >+ * success >+ */ >+ sdbm_internal_close (db); >+ return 0; >+ } >+ >+ sdbm_internal_close (db); >+ return ioerr (sdb), -1; >+} >+ >+/* >+ * the following two routines will break if >+ * deletions aren't taken into account. (ndbm bug) >+ */ >+datum sdbm_firstkey (SDBM * sdb) >+{ >+ datum retval; >+ DBM *db; >+ >+ if (sdb == NULL) >+ return errno = EINVAL, nullitem; >+ >+ if (!(db = sdbm_internal_open (sdb))) >+ return errno = EINVAL, nullitem; >+ >+/* >+ * start at page 0 >+ */ >+ if (lseek (db->pagf, OFF_PAG (0), SEEK_SET) < 0 >+ || read (db->pagf, db->pagbuf, PBLKSIZ) < 0) >+ { >+ sdbm_internal_close (db); >+ return ioerr (sdb), nullitem; >+ } >+ db->pagbno = 0; >+ db->blkptr = 0; >+ db->keyptr = 0; >+ >+ retval = getnext (db); >+ sdb->blkptr = db->blkptr; >+ sdb->keyptr = db->keyptr; >+ sdbm_internal_close (db); >+ return retval; >+} >+ >+datum sdbm_nextkey (SDBM * sdb) >+{ >+ datum retval; >+ DBM *db; >+ >+ if (sdb == NULL) >+ return errno = EINVAL, nullitem; >+ >+ if (!(db = sdbm_internal_open (sdb))) >+ return errno = EINVAL, nullitem; >+ >+ retval = getnext (db); >+ sdb->blkptr = db->blkptr; >+ sdb->keyptr = db->keyptr; >+ sdbm_internal_close (db); >+ return retval; >+} >+ >+void sdbm_close (SDBM * db) >+{ >+ if (db == NULL) >+ errno = EINVAL; >+ else >+ { >+ (void) close (db->dirf); >+ (void) close (db->pagf); >+ myfree ((char *) db); >+ } >+} >+ >+SDBM *sdbm_open (char *file, int flags, int mode) >+{ >+ SDBM *db; >+ char *dirname; >+ char *pagname; >+ int n; >+ >+ if (file == NULL || !*file) >+ return errno = EINVAL, (SDBM *) NULL; >+/* >+ * need space for two seperate filenames >+ */ >+ n = strlen (file) * 2 + strlen (DIRFEXT) + strlen (PAGFEXT) + 2; >+ >+ if ((dirname = (char *) mymalloc ((unsigned) n)) == NULL) >+ return errno = ENOMEM, (SDBM *) NULL; >+/* >+ * build the file names >+ */ >+ dirname = strcat (strcpy (dirname, file), DIRFEXT); >+ pagname = strcpy (dirname + strlen (dirname) + 1, file); >+ pagname = strcat (pagname, PAGFEXT); >+ >+ db = sdbm_prep (dirname, pagname, flags, mode); >+ myfree ((char *) dirname); >+ return db; >+} >+ >diff -Pur postfix-1.1.11-20020613-orig/src/util/sdbm.h postfix-1.1.11-20020613/src/util/sdbm.h >--- postfix-1.1.11-20020613-orig/src/util/sdbm.h Thu Jan 1 01:00:00 1970 >+++ postfix-1.1.11-20020613/src/util/sdbm.h Wed Jun 26 15:26:49 2002 >@@ -0,0 +1,97 @@ >+/*++ >+/* NAME >+/* sdbm 3h >+/* SUMMARY >+/* SDBM Simple DBM: ndbm work-alike hashed database library >+/* SYNOPSIS >+/* include "sdbm.h" >+/* DESCRIPTION >+/* .nf >+/*--*/ >+ >+#ifndef UTIL_SDBM_H >+#define UTIL_SDBM_H >+ >+/* >+ * sdbm - ndbm work-alike hashed database library >+ * based on Per-Ake Larson's Dynamic Hashing algorithms. BIT 18 (1978). >+ * author: oz@nexus.yorku.ca >+ * status: public domain. >+ */ >+ >+#define DUFF /* go ahead and use the loop-unrolled version */ >+ >+#include <stdio.h> >+ >+#define DBLKSIZ 16384 /* SSL cert chains require more */ >+#define PBLKSIZ 8192 /* SSL cert chains require more */ >+#define PAIRMAX 8008 /* arbitrary on PBLKSIZ-N */ >+#define SPLTMAX 10 /* maximum allowed splits */ >+ /* for a single insertion */ >+#define DIRFEXT ".dir" >+#define PAGFEXT ".pag" >+ >+typedef struct { >+ int dirf; /* directory file descriptor */ >+ int pagf; /* page file descriptor */ >+ int flags; /* status/error flags, see below */ >+ long blkptr; /* current block for nextkey */ >+ int keyptr; /* current key for nextkey */ >+ char pagbuf[PBLKSIZ]; /* page file block buffer */ >+ char dirbuf[DBLKSIZ]; /* directory file block buffer */ >+} SDBM; >+ >+#define DBM_RDONLY 0x1 /* data base open read-only */ >+#define DBM_IOERR 0x2 /* data base I/O error */ >+ >+/* >+ * utility macros >+ */ >+#define sdbm_rdonly(db) ((db)->flags & DBM_RDONLY) >+#define sdbm_error(db) ((db)->flags & DBM_IOERR) >+ >+#define sdbm_clearerr(db) ((db)->flags &= ~DBM_IOERR) /* ouch */ >+ >+#define sdbm_dirfno(db) ((db)->dirf) >+#define sdbm_pagfno(db) ((db)->pagf) >+ >+typedef struct { >+ char *dptr; >+ int dsize; >+} datum; >+ >+extern datum nullitem; >+ >+/* >+ * flags to sdbm_store >+ */ >+#define DBM_INSERT 0 >+#define DBM_REPLACE 1 >+ >+/* >+ * ndbm interface >+ */ >+extern SDBM *sdbm_open(char *, int, int); >+extern void sdbm_close(SDBM *); >+extern datum sdbm_fetch(SDBM *, datum); >+extern int sdbm_delete(SDBM *, datum); >+extern int sdbm_store(SDBM *, datum, datum, int); >+extern datum sdbm_firstkey(SDBM *); >+extern datum sdbm_nextkey(SDBM *); >+ >+/* >+ * sdbm - ndbm work-alike hashed database library >+ * tuning and portability constructs [not nearly enough] >+ * author: oz@nexus.yorku.ca >+ */ >+ >+#define BYTESIZ 8 >+ >+/* >+ * important tuning parms (hah) >+ */ >+ >+#define SEEDUPS /* always detect duplicates */ >+#define BADMESS /* generate a message for worst case: >+ cannot make room after SPLTMAX splits */ >+#endif /* UTIL_SDBM_H */ >diff -Pur postfix-1.1.11-20020613-orig/src/util/sys_defs.h postfix-1.1.11-20020613/src/util/sys_defs.h >--- postfix-1.1.11-20020613-orig/src/util/sys_defs.h Mon Apr 15 23:56:08 2002 >+++ postfix-1.1.11-20020613/src/util/sys_defs.h Wed Jun 26 15:26:49 2002 >@@ -73,6 +73,10 @@ > #define DEF_MAILBOX_LOCK "flock, dotlock" > #endif > >+#if ((defined(__NetBSD_Version__) && __NetBSD_Version__ >= 105000000) || defined(USAGI_LIBINET6)) >+#define HAVE_GETIFADDRS >+#endif >+ > /* > * UNIX on MAC. > */ >diff -Pur postfix-1.1.11-20020613-orig/src/util/valid_hostname.c postfix-1.1.11-20020613/src/util/valid_hostname.c >--- postfix-1.1.11-20020613-orig/src/util/valid_hostname.c Sun Jan 28 15:10:18 2001 >+++ postfix-1.1.11-20020613/src/util/valid_hostname.c Wed Jun 26 15:26:49 2002 >@@ -47,6 +47,13 @@ > #include <string.h> > #include <ctype.h> > >+#ifdef INET6 >+#include <netinet/in.h> >+#include <sys/socket.h> >+#include <arpa/inet.h> >+#include <netdb.h> >+#endif >+ > /* Utility library. */ > > #include "msg.h" >@@ -103,7 +110,23 @@ > msg_warn("%s: misplaced hyphen: %.100s", myname, name); > return (0); > } >- } else { >+ } >+#ifdef INET6 >+ else if (ch == ':') { >+ struct addrinfo hints, *res; >+ >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = AF_INET6; >+ hints.ai_socktype = SOCK_STREAM; /*dummy*/ >+ hints.ai_flags = AI_NUMERICHOST; >+ if (getaddrinfo(name, "0", &hints, &res) == 0) { >+ freeaddrinfo(res); >+ return 1; >+ } else >+ return 0; >+ } >+#endif >+ else { > if (gripe) > msg_warn("%s: invalid character %d(decimal): %.100s", > myname, ch, name); >@@ -135,6 +158,9 @@ > int byte_count = 0; > int byte_val = 0; > int ch; >+#ifdef INET6 >+ struct addrinfo hints, *res; >+#endif > > #define BYTES_NEEDED 4 > >@@ -146,6 +172,17 @@ > msg_warn("%s: empty address", myname); > return (0); > } >+ >+#ifdef INET6 >+ memset(&hints, 0, sizeof(hints)); >+ hints.ai_family = AF_INET6; >+ hints.ai_socktype = SOCK_STREAM; /*dummy*/ >+ hints.ai_flags = AI_NUMERICHOST; >+ if (getaddrinfo(addr, "0", &hints, &res) == 0) { >+ freeaddrinfo(res); >+ return 1; >+ } >+#endif > > /* > * Scary code to avoid sscanf() overflow nasties.
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 5023
:
2259
| 2260