-
-/*
- * 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
#include <h/oauth.h>
#include <stdarg.h>
#include <sys/select.h>
+#include "base64.h"
#ifdef CYRUS_SASL
#include <sasl/sasl.h>
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 */
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;
/*
* 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) {
}
free(nsc->sasl_secret);
}
- mh_xfree(nsc->sasl_tmpbuf);
+ free(nsc->sasl_tmpbuf);
#endif /* CYRUS_SASL */
#ifdef TLS_SUPPORT
if (nsc->ssl_io)
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)
* 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);
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;
}
*/
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;
}
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.
*/
* messages.
*/
- memset(&secprops, 0, sizeof(secprops));
+ ZERO(&secprops);
secprops.maxbufsize = SASL_MAXRECVBUF;
/*
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",
#ifdef TLS_SUPPORT
if (tls) {
SSL *ssl;
- BIO *rbio, *wbio, *ssl_bio;;
+ BIO *rbio, *wbio, *ssl_bio;
if (! tls_initialized) {
SSL_library_init();
* 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",
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",
*/
if (! noverify) {
+#ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
X509_VERIFY_PARAM *param;
+#endif /* HAVE_X509_VERIFY_PARAM_SET1_HOST */
SSL_set_verify(ssl, SSL_VERIFY_PEER, NULL);
if (! nsc->ns_hostname) {
return NOTOK;
}
+#ifdef HAVE_X509_VERIFY_PARAM_SET1_HOST
param = SSL_get0_param(ssl);
if (! X509_VERIFY_PARAM_set1_host(param, nsc->ns_hostname, 0)) {
SSL_free(ssl);
return NOTOK;
}
+#endif /* HAVE_X509_VERIFY_PARAM_SET1_HOST */
}
ssl_bio = BIO_new(BIO_f_ssl());
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);
#else /* TLS_SUPPORT */
NMH_UNUSED(nsc);
+ NMH_UNUSED(noverify);
if (tls) {
netsec_err(errstr, "TLS is not supported");
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(
}
} else {
netsec_err(errstr, "TLS negotiation failed: %s",
- ERR_error_string(ERR_get_error(), NULL));
+ ERR_error_string(errcode, NULL));
}
/*