]> git.ipfire.org Git - people/ms/dma.git/blobdiff - crypto.c
dns: do not treat unreachable DNS server as permanent error
[people/ms/dma.git] / crypto.c
index 91821377ffbf9ac9eb6b6a9a529e8694c3c709e8..897b55bfdcfcc94814ba8482056c72e3d4a31f35 100644 (file)
--- a/crypto.c
+++ b/crypto.c
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
- *
- * $DragonFly: src/libexec/dma/crypto.c,v 1.3 2008/09/02 15:11:49 matthias Exp $
  */
 
-#ifdef HAVE_CRYPTO
-
 #include <openssl/x509.h>
 #include <openssl/md5.h>
 #include <openssl/ssl.h>
 
 #include "dma.h"
 
-extern struct config *config;
-
 static int
-init_cert_file(struct qitem *it, SSL_CTX *ctx, const char *path)
+init_cert_file(SSL_CTX *ctx, const char *path)
 {
        int error;
 
        /* Load certificate into ctx */
        error = SSL_CTX_use_certificate_chain_file(ctx, path);
        if (error < 1) {
-               syslog(LOG_ERR, "%s: SSL: Cannot load certificate: %s",
-                       it->queueid, path);
+               syslog(LOG_ERR, "SSL: Cannot load certificate `%s': %s", path, ssl_errstr());
                return (-1);
        }
 
        /* Add private key to ctx */
        error = SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM);
        if (error < 1) {
-               syslog(LOG_ERR, "%s: SSL: Cannot load private key: %s",
-                       it->queueid, path);
+               syslog(LOG_ERR, "SSL: Cannot load private key `%s': %s", path, ssl_errstr());
                return (-1);
        }
 
@@ -77,8 +69,7 @@ init_cert_file(struct qitem *it, SSL_CTX *ctx, const char *path)
         */
        error = SSL_CTX_check_private_key(ctx);
        if (error < 1) {
-               syslog(LOG_ERR, "%s: SSL: Cannot check private key: %s",
-                       it->queueid, path);
+               syslog(LOG_ERR, "SSL: Cannot check private key: %s", ssl_errstr());
                return (-1);
        }
 
@@ -86,29 +77,38 @@ init_cert_file(struct qitem *it, SSL_CTX *ctx, const char *path)
 }
 
 int
-smtp_init_crypto(struct qitem *it, int fd, int feature)
+smtp_init_crypto(int fd, int feature)
 {
        SSL_CTX *ctx = NULL;
+#if (OPENSSL_VERSION_NUMBER >= 0x00909000L)
+       const SSL_METHOD *meth = NULL;
+#else
        SSL_METHOD *meth = NULL;
+#endif
        X509 *cert;
-       char buf[2048];
        int error;
 
+       /* XXX clean up on error/close */
        /* Init SSL library */
        SSL_library_init();
+       SSL_load_error_strings();
 
        meth = TLSv1_client_method();
 
        ctx = SSL_CTX_new(meth);
        if (ctx == NULL) {
-               syslog(LOG_ERR, "%s: remote delivery deferred:"
-                      " SSL init failed: %m", it->queueid);
-               return (2);
+               syslog(LOG_WARNING, "remote delivery deferred: SSL init failed: %s", ssl_errstr());
+               return (1);
        }
 
        /* User supplied a certificate */
-       if (config->certfile != NULL)
-               init_cert_file(it, ctx, config->certfile);
+       if (config.certfile != NULL) {
+               error = init_cert_file(ctx, config.certfile);
+               if (error) {
+                       syslog(LOG_WARNING, "remote delivery deferred");
+                       return (1);
+               }
+       }
 
        /*
         * If the user wants STARTTLS, we have to send EHLO here
@@ -116,54 +116,56 @@ smtp_init_crypto(struct qitem *it, int fd, int feature)
        if (((feature & SECURETRANS) != 0) &&
             (feature & STARTTLS) != 0) {
                /* TLS init phase, disable SSL_write */
-               config->features |= NOSSL;
+               config.features |= NOSSL;
 
                send_remote_command(fd, "EHLO %s", hostname());
                if (read_remote(fd, 0, NULL) == 2) {
                        send_remote_command(fd, "STARTTLS");
                        if (read_remote(fd, 0, NULL) != 2) {
-                               syslog(LOG_ERR, "%s: remote delivery failed:"
-                                 " STARTTLS not available: %m", it->queueid);
-                               config->features &= ~NOSSL;
-                               return (-1);
+                               if ((feature & TLS_OPP) == 0) {
+                                       syslog(LOG_ERR, "remote delivery deferred: STARTTLS not available: %s", neterr);
+                                       return (1);
+                               } else {
+                                       syslog(LOG_INFO, "in opportunistic TLS mode, STARTTLS not available: %s", neterr);
+                                       return (0);
+                               }
                        }
                }
                /* End of TLS init phase, enable SSL_write/read */
-               config->features &= ~NOSSL;
+               config.features &= ~NOSSL;
        }
 
-       config->ssl = SSL_new(ctx);
-       if (config->ssl == NULL) {
-               syslog(LOG_ERR, "%s: remote delivery deferred:"
-                      " SSL struct creation failed:", it->queueid);
-               return (2);
+       config.ssl = SSL_new(ctx);
+       if (config.ssl == NULL) {
+               syslog(LOG_NOTICE, "remote delivery deferred: SSL struct creation failed: %s",
+                      ssl_errstr());
+               return (1);
        }
 
        /* Set ssl to work in client mode */
-       SSL_set_connect_state(config->ssl);
+       SSL_set_connect_state(config.ssl);
 
        /* Set fd for SSL in/output */
-       error = SSL_set_fd(config->ssl, fd);
+       error = SSL_set_fd(config.ssl, fd);
        if (error == 0) {
-               error = SSL_get_error(config->ssl, error);
-               syslog(LOG_ERR, "%s: remote delivery deferred:"
-                      " SSL set fd failed (%d): %m", it->queueid, error);
-               return (2);
+               syslog(LOG_NOTICE, "remote delivery deferred: SSL set fd failed: %s",
+                      ssl_errstr());
+               return (1);
        }
 
        /* Open SSL connection */
-       error = SSL_connect(config->ssl);
+       error = SSL_connect(config.ssl);
        if (error < 0) {
-               syslog(LOG_ERR, "%s: remote delivery failed:"
-                      " SSL handshake fataly failed: %m", it->queueid);
-               return (-1);
+               syslog(LOG_ERR, "remote delivery deferred: SSL handshake failed fatally: %s",
+                      ssl_errstr());
+               return (1);
        }
 
        /* Get peer certificate */
-       cert = SSL_get_peer_certificate(config->ssl);
+       cert = SSL_get_peer_certificate(config.ssl);
        if (cert == NULL) {
-               syslog(LOG_ERR, "%s: remote delivery deferred:"
-                      " Peer did not provied certificate: %m", it->queueid);
+               syslog(LOG_WARNING, "remote delivery deferred: Peer did not provide certificate: %s",
+                      ssl_errstr());
        }
        X509_free(cert);
 
@@ -173,15 +175,16 @@ smtp_init_crypto(struct qitem *it, int fd, int feature)
 /*
  * hmac_md5() taken out of RFC 2104.  This RFC was written by H. Krawczyk,
  * M. Bellare and R. Canetti.
- */ 
+ *
+ * text      pointer to data stream
+ * text_len  length of data stream
+ * key       pointer to authentication key
+ * key_len   length of authentication key
+ * digest    caller digest to be filled int
+ */
 void
-hmac_md5(text, text_len, key, key_len, digest)
-unsigned char*  text;                /* pointer to data stream */
-int             text_len;            /* length of data stream */
-unsigned char*  key;                 /* pointer to authentication key */
-int             key_len;             /* length of authentication key */
-caddr_t         digest;              /* caller digest to be filled in */
-
+hmac_md5(unsigned char *text, int text_len, unsigned char *key, int key_len,
+    unsigned char* digest)
 {
         MD5_CTX context;
         unsigned char k_ipad[65];    /* inner padding -
@@ -251,9 +254,10 @@ caddr_t         digest;              /* caller digest to be filled in */
  * CRAM-MD5 authentication
  */
 int
-smtp_auth_md5(struct qitem *it, int fd, char *login, char *password)
+smtp_auth_md5(int fd, char *login, char *password)
 {
-       unsigned char buffer[BUF_SIZE], digest[BUF_SIZE], ascii_digest[33];
+       unsigned char digest[BUF_SIZE];
+       char buffer[BUF_SIZE], ascii_digest[33];
        char *temp;
        int len, i;
        static char hextab[] = "0123456789abcdef";
@@ -266,15 +270,18 @@ smtp_auth_md5(struct qitem *it, int fd, char *login, char *password)
        /* Send AUTH command according to RFC 2554 */
        send_remote_command(fd, "AUTH CRAM-MD5");
        if (read_remote(fd, sizeof(buffer), buffer) != 3) {
-               syslog(LOG_ERR, "%s: smarthost authentification:"
-                      " AUTH cram-md5 not available: %m", it->queueid);
+               syslog(LOG_DEBUG, "smarthost authentication:"
+                      " AUTH cram-md5 not available: %s", neterr);
                /* if cram-md5 is not available */
+               free(temp);
                return (-1);
        }
 
        /* skip 3 char status + 1 char space */
        base64_decode(buffer + 4, temp);
-       hmac_md5(temp, strlen(temp), password, strlen(password), digest);
+       hmac_md5((unsigned char *)temp, strlen(temp),
+                (unsigned char *)password, strlen(password), digest);
+       free(temp);
 
        ascii_digest[32] = 0;
        for (i = 0; i < 16; i++) {
@@ -285,22 +292,21 @@ smtp_auth_md5(struct qitem *it, int fd, char *login, char *password)
        /* prepare answer */
        snprintf(buffer, BUF_SIZE, "%s %s", login, ascii_digest);
 
-       /* temp will be allocated inside base64_encode again */
-       free(temp);
        /* encode answer */
        len = base64_encode(buffer, strlen(buffer), &temp);
-       if (len <= 0)
+       if (len < 0) {
+               syslog(LOG_ERR, "can not encode auth reply: %m");
                return (-1);
+       }
 
        /* send answer */
        send_remote_command(fd, "%s", temp);
+       free(temp);
        if (read_remote(fd, 0, NULL) != 2) {
-               syslog(LOG_ERR, "%s: remote delivery deferred:"
-                               " AUTH cram-md5 failed: %m", it->queueid);
+               syslog(LOG_WARNING, "remote delivery deferred:"
+                               " AUTH cram-md5 failed: %s", neterr);
                return (-2);
        }
 
        return (0);
 }
-
-#endif /* HAVE_CRYPTO */