]> diplodocus.org Git - nmh/blobdiff - sbr/netsec.c
mhlsbr.c: Don't strchr(3) non-string NUL-less buffer.
[nmh] / sbr / netsec.c
index e8f8901f086461824d95bd170995209cc0472b52..25b1f888fbcf2a146ff670fad0bf48802d088a6c 100644 (file)
@@ -1,6 +1,4 @@
-
-/*
- * netsec.c -- Network security routines for handling protocols that
+/* netsec.c -- Network security routines for handling protocols that
  *            require SASL and/or TLS.
  *
  * This code is Copyright (c) 2016, by the authors of nmh.  See the
@@ -14,6 +12,7 @@
 #include <h/oauth.h>
 #include <stdarg.h>
 #include <sys/select.h>
+#include "base64.h"
 
 #ifdef CYRUS_SASL
 #include <sasl/sasl.h>
@@ -56,6 +55,7 @@ static SSL_CTX *sslctx = NULL;                /* SSL Context */
 struct _netsec_context {
     int ns_readfd;             /* Read descriptor for network connection */
     int ns_writefd;            /* Write descriptor for network connection */
+    int ns_noclose;            /* Do not close file descriptors if set */
     int ns_snoop;              /* If true, display network data */
     int ns_snoop_noend;                /* If true, didn't get a CR/LF on last line */
     netsec_snoop_callback *ns_snoop_cb; /* Snoop output callback */
@@ -142,6 +142,7 @@ netsec_init(void)
     NEW(nsc);
     nsc->ns_readfd = -1;
     nsc->ns_writefd = -1;
+    nsc->ns_noclose = 0;
     nsc->ns_snoop = 0;
     nsc->ns_snoop_noend = 0;
     nsc->ns_snoop_cb = NULL;
@@ -182,25 +183,24 @@ netsec_init(void)
 
 /*
  * Shutdown the connection completely and free all resources.
- * The connection is only closed if the flag is given.
  */
 
 void
-netsec_shutdown(netsec_context *nsc, int closeflag)
+netsec_shutdown(netsec_context *nsc)
 {
-    mh_xfree(nsc->ns_userid);
-    mh_xfree(nsc->ns_hostname);
-    mh_xfree(nsc->ns_inbuffer);
-    mh_xfree(nsc->ns_outbuffer);
-    mh_xfree(nsc->sasl_mech);
-    mh_xfree(nsc->sasl_chosen_mech);
+    free(nsc->ns_userid);
+    free(nsc->ns_hostname);
+    free(nsc->ns_inbuffer);
+    free(nsc->ns_outbuffer);
+    free(nsc->sasl_mech);
+    free(nsc->sasl_chosen_mech);
 #ifdef OAUTH_SERVICE
-    mh_xfree(nsc->oauth_service);
+    free(nsc->oauth_service);
 #endif /* OAUTH_SERVICE */
 #ifdef CYRUS_SASL
     if (nsc->sasl_conn)
        sasl_dispose(&nsc->sasl_conn);
-    mh_xfree(nsc->sasl_cbs);
+    free(nsc->sasl_cbs);
     if (nsc->sasl_creds)
        nmh_credentials_free(nsc->sasl_creds);
     if (nsc->sasl_secret) {
@@ -209,7 +209,7 @@ netsec_shutdown(netsec_context *nsc, int closeflag)
        }
        free(nsc->sasl_secret);
     }
-    mh_xfree(nsc->sasl_tmpbuf);
+    free(nsc->sasl_tmpbuf);
 #endif /* CYRUS_SASL */
 #ifdef TLS_SUPPORT
     if (nsc->ssl_io)
@@ -220,7 +220,7 @@ netsec_shutdown(netsec_context *nsc, int closeflag)
        BIO_free_all(nsc->ssl_io);
 #endif /* TLS_SUPPORT */
 
-    if (closeflag) {
+    if (! nsc->ns_noclose) {
        if (nsc->ns_readfd != -1)
            close(nsc->ns_readfd);
        if (nsc->ns_writefd != -1 && nsc->ns_writefd != nsc->ns_readfd)
@@ -393,7 +393,7 @@ netsec_read(netsec_context *nsc, void *buffer, size_t size, char **errstr)
      * assume here that this has something in it.
      */
 
-    retlen = size > nsc->ns_inbuflen ? nsc->ns_inbuflen : size;
+    retlen = min(size, nsc->ns_inbuflen);
 
     memcpy(buffer, nsc->ns_inptr, retlen);
 
@@ -461,8 +461,10 @@ retry:
                if (nsc->ns_snoop_cb)
                    nsc->ns_snoop_cb(nsc, sptr, strlen(sptr),
                                     nsc->ns_snoop_context);
-               else
-                   fprintf(stderr, "%s\n", sptr);
+               else {
+                    fputs(sptr, stderr);
+                    putc('\n', stderr);
+                }
            }
            return sptr;
        }
@@ -474,7 +476,7 @@ retry:
      */
 
     if (count >= nsc->ns_inbufsize / 2) {
-       netsec_err(errstr, "Unable to find a line terminator after %d bytes",
+       netsec_err(errstr, "Unable to find a line terminator after %zu bytes",
                   count);
        return NULL;
     }
@@ -1011,14 +1013,13 @@ netsec_set_sasl_params(netsec_context *nsc, const char *service,
     nsc->sasl_creds = nmh_get_credentials(nsc->ns_hostname, nsc->ns_userid);
 
 #else /* CYRUS_SASL */
-    NMH_UNUSED(hostname);
     NMH_UNUSED(service);
     NMH_UNUSED(errstr);
 #endif /* CYRUS_SASL */
 
     /*
      * According to the RFC, mechanisms can only be uppercase letter, numbers,
-     * and a hypen or underscore.  So make sure we uppercase any letters
+     * and a hyphen or underscore.  So make sure we uppercase any letters
      * in case the user passed in lowercase.
      */
 
@@ -1219,7 +1220,7 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
      * messages.
      */
 
-    memset(&secprops, 0, sizeof(secprops));
+    ZERO(&secprops);
     secprops.maxbufsize = SASL_MAXRECVBUF;
 
     /*
@@ -1281,7 +1282,7 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr)
        rc = sasl_client_step(nsc->sasl_conn, (char *) outbuf, outbuflen, NULL,
                              (const char **) &saslbuf, &saslbuflen);
 
-        mh_xfree(outbuf);
+        free(outbuf);
 
        if (rc != SASL_OK && rc != SASL_CONTINUE) {
            netsec_err(errstr, "SASL client negotiation failed: %s",
@@ -1438,7 +1439,7 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr)
 #ifdef TLS_SUPPORT
     if (tls) {
        SSL *ssl;
-       BIO *rbio, *wbio, *ssl_bio;;
+        BIO *rbio, *wbio, *ssl_bio;
 
        if (! tls_initialized) {
            SSL_library_init();
@@ -1510,7 +1511,7 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr)
         * SSL BIO -> socket BIO.
         */
 
-       rbio = BIO_new_socket(nsc->ns_readfd, BIO_NOCLOSE);
+       rbio = BIO_new_socket(nsc->ns_readfd, BIO_CLOSE);
 
        if (! rbio) {
            netsec_err(errstr, "Unable to create a read socket BIO: %s",
@@ -1519,7 +1520,7 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr)
            return NOTOK;
        }
 
-       wbio = BIO_new_socket(nsc->ns_writefd, BIO_NOCLOSE);
+       wbio = BIO_new_socket(nsc->ns_writefd, BIO_CLOSE);
 
        if (! wbio) {
            netsec_err(errstr, "Unable to create a write socket BIO: %s",
@@ -1580,6 +1581,13 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr)
        BIO_set_ssl(ssl_bio, ssl, BIO_CLOSE);
        nsc->ssl_io = ssl_bio;
 
+       /*
+        * Since SSL now owns these file descriptors, have it handle the
+        * closing of them instead of netsec_shutdown().
+        */
+
+       nsc->ns_noclose = 1;
+
        return OK;
     }
     BIO_free_all(nsc->ssl_io);
@@ -1626,7 +1634,7 @@ netsec_negotiate_tls(netsec_context *nsc, char **errstr)
            if (BIO_get_ssl(nsc->ssl_io, &ssl) < 1) {
                netsec_err(errstr, "Certificate verification failed, but "
                           "cannot retrieve SSL handle: %s",
-                          ERR_error_string(ERR_get_error(), NULL));
+                           ERR_error_string(ERR_get_error(), NULL));
            } else {
                netsec_err(errstr, "Server certificate verification failed: %s",
                           X509_verify_cert_error_string(
@@ -1634,7 +1642,7 @@ netsec_negotiate_tls(netsec_context *nsc, char **errstr)
            }
        } else {
            netsec_err(errstr, "TLS negotiation failed: %s",
-                      ERR_error_string(ERR_get_error(), NULL));
+                       ERR_error_string(errcode, NULL));
        }
 
        /*