X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/19411b971b43385bbc15f1c9cfb4a2665cd5ebb5..c576ad2674c37a1c63f004c71049998f38854c64:/sbr/netsec.c diff --git a/sbr/netsec.c b/sbr/netsec.c index b8806a17..25b1f888 100644 --- a/sbr/netsec.c +++ b/sbr/netsec.c @@ -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 #include #include +#include "base64.h" #ifdef CYRUS_SASL #include @@ -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", @@ -1543,7 +1544,9 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr) */ 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) { @@ -1553,6 +1556,7 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr) 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)) { @@ -1562,6 +1566,7 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr) SSL_free(ssl); return NOTOK; } +#endif /* HAVE_X509_VERIFY_PARAM_SET1_HOST */ } ssl_bio = BIO_new(BIO_f_ssl()); @@ -1576,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); @@ -1622,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( @@ -1630,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)); } /*