X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/c2655c2b98253e03c42eeeee1e5c60fe7107c5a4..42db3a2c36e26e0106b1e480407e32d3c8c09bef:/sbr/netsec.c?ds=sidebyside diff --git a/sbr/netsec.c b/sbr/netsec.c index 537df825..83d75631 100644 --- a/sbr/netsec.c +++ b/sbr/netsec.c @@ -6,10 +6,13 @@ * complete copyright information. */ -#include -#include -#include -#include +#include "h/mh.h" +#include "credentials.h" +#include "getcpy.h" +#include "brkstring.h" +#include "h/utils.h" +#include "h/netsec.h" +#include "h/oauth.h" #include #include #include "base64.h" @@ -30,7 +33,7 @@ static int netsec_get_user(void *context, int id, const char **result, static int netsec_get_password(sasl_conn_t *conn, void *context, int id, sasl_secret_t **psecret); -static int sasl_initialized = 0; +static bool sasl_initialized; #define SASL_MAXRECVBUF 65536 #endif /* CYRUS_SASL */ @@ -39,7 +42,7 @@ static int sasl_initialized = 0; #include #include -static int tls_initialized = 0; +static bool tls_initialized; static SSL_CTX *sslctx = NULL; /* SSL Context */ #endif /* TLS_SUPPORT */ @@ -57,9 +60,9 @@ struct _netsec_context { 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 */ void *ns_snoop_context; /* Context data for snoop function */ + char *ns_snoop_savebuf; /* Save buffer for snoop data */ int ns_timeout; /* Network read timeout, in seconds */ char *ns_userid; /* Userid for authentication */ char *ns_hostname; /* Hostname we've connected to */ @@ -145,9 +148,9 @@ netsec_init(void) nsc->ns_writefd = -1; nsc->ns_noclose = 0; nsc->ns_snoop = 0; - nsc->ns_snoop_noend = 0; nsc->ns_snoop_cb = NULL; nsc->ns_snoop_context = NULL; + nsc->ns_snoop_savebuf = NULL; nsc->ns_userid = NULL; nsc->ns_hostname = NULL; nsc->ns_timeout = 60; /* Our default */ @@ -196,6 +199,7 @@ netsec_shutdown(netsec_context *nsc) free(nsc->ns_outbuffer); free(nsc->sasl_mech); free(nsc->sasl_chosen_mech); + free(nsc->ns_snoop_savebuf); #ifdef OAUTH_SERVICE free(nsc->oauth_service); #endif /* OAUTH_SERVICE */ @@ -287,7 +291,8 @@ netsec_set_snoop(netsec_context *nsc, int snoop) * Set the snoop callback for this connection. */ -void netsec_set_snoop_callback(netsec_context *nsc, +void +netsec_set_snoop_callback(netsec_context *nsc, netsec_snoop_callback callback, void *context) { nsc->ns_snoop_cb = callback; @@ -805,6 +810,7 @@ netsec_vprintf(netsec_context *nsc, char **errstr, const char *format, va_list ap) { int rc; + va_list apcopy; /* * Cheat a little. If we can fit the data into our outgoing buffer, @@ -812,8 +818,10 @@ netsec_vprintf(netsec_context *nsc, char **errstr, const char *format, */ retry: + va_copy(apcopy, ap); rc = vsnprintf((char *) nsc->ns_outptr, - nsc->ns_outbufsize - nsc->ns_outbuflen, format, ap); + nsc->ns_outbufsize - nsc->ns_outbuflen, format, apcopy); + va_end(apcopy); if (rc >= (int) (nsc->ns_outbufsize - nsc->ns_outbuflen)) { /* @@ -846,35 +854,6 @@ retry: goto retry; } - if (nsc->ns_snoop) { - int outlen = rc; - if (outlen > 0 && nsc->ns_outptr[outlen - 1] == '\n') { - outlen--; - if (outlen > 0 && nsc->ns_outptr[outlen - 1] == '\r') - outlen--; - } else { - nsc->ns_snoop_noend = 1; - } - if (outlen > 0 || nsc->ns_snoop_noend == 0) { -#ifdef CYRUS_SASL - if (nsc->sasl_seclayer) - fprintf(stderr, "(sasl-encrypted) "); -#endif /* CYRUS_SASL */ -#ifdef TLS_SUPPORT - if (nsc->tls_active) - fprintf(stderr, "(tls-encrypted) "); -#endif /* TLS_SUPPORT */ - fprintf(stderr, "=> "); - if (nsc->ns_snoop_cb) - nsc->ns_snoop_cb(nsc, (char *) nsc->ns_outptr, outlen, - nsc->ns_snoop_context); - else - fprintf(stderr, "%.*s\n", outlen, nsc->ns_outptr); - } else { - nsc->ns_snoop_noend = 0; - } - } - nsc->ns_outptr += rc; nsc->ns_outbuflen += rc; @@ -900,6 +879,95 @@ netsec_flush(netsec_context *nsc, char **errstr) if (netoutlen == 0) return OK; + /* + * If we have snoop turned on, output the data. + * + * Note here; if we don't have a CR or LF at the end, save the data + * in ns_snoop_savebuf for later and print it next time. + */ + + if (nsc->ns_snoop) { + unsigned int snoopoutlen = netoutlen; + const char *snoopoutbuf = (const char *) nsc->ns_outbuffer; + + while (snoopoutlen > 0) { + const char *end = strpbrk(snoopoutbuf, "\r\n"); + unsigned int outlen; + + if (! end) { + if (nsc->ns_snoop_savebuf) { + nsc->ns_snoop_savebuf = mh_xrealloc(nsc->ns_snoop_savebuf, + strlen(nsc->ns_snoop_savebuf) + + snoopoutlen + 1); + strncat(nsc->ns_snoop_savebuf, snoopoutbuf, snoopoutlen); + } else { + nsc->ns_snoop_savebuf = mh_xmalloc(snoopoutlen + 1); + strncpy(nsc->ns_snoop_savebuf, snoopoutbuf, snoopoutlen); + nsc->ns_snoop_savebuf[snoopoutlen] = '\0'; + } + break; + } + + outlen = end - snoopoutbuf; + +#ifdef CYRUS_SASL + if (nsc->sasl_seclayer) + fprintf(stderr, "(sasl-encrypted) "); +#endif /* CYRUS_SASL */ +#ifdef TLS_SUPPORT + if (nsc->tls_active) + fprintf(stderr, "(tls-encrypted) "); +#endif /* TLS_SUPPORT */ + fprintf(stderr, "=> "); + if (nsc->ns_snoop_cb) { + const char *ptr; + unsigned int cb_len = outlen; + + if (nsc->ns_snoop_savebuf) { + cb_len += strlen(nsc->ns_snoop_savebuf); + nsc->ns_snoop_savebuf = mh_xrealloc(nsc->ns_snoop_savebuf, + outlen); + ptr = nsc->ns_snoop_savebuf; + } else { + ptr = snoopoutbuf; + } + + nsc->ns_snoop_cb(nsc, ptr, cb_len, nsc->ns_snoop_context); + + if (nsc->ns_snoop_savebuf) { + free(nsc->ns_snoop_savebuf); + nsc->ns_snoop_savebuf = NULL; + } + } else { + if (nsc->ns_snoop_savebuf) { + fprintf(stderr, "%s", nsc->ns_snoop_savebuf); + free(nsc->ns_snoop_savebuf); + nsc->ns_snoop_savebuf = NULL; + } + fprintf(stderr, "%.*s\n", outlen, snoopoutbuf); + } + + /* + * Alright, hopefully any previous leftover data is done, + * and we have the current line output. Move things past the + * next CR/LF. + */ + + snoopoutlen -= outlen; + snoopoutbuf += outlen; + + if (snoopoutlen > 0 && *snoopoutbuf == '\r') { + snoopoutlen--; + snoopoutbuf++; + } + + if (snoopoutlen > 0 && *snoopoutbuf == '\n') { + snoopoutlen--; + snoopoutbuf++; + } + } + } + /* * If SASL security layers are in effect, run the data through * sasl_encode() first. @@ -971,7 +1039,7 @@ netsec_set_sasl_params(netsec_context *nsc, const char *service, sasl_errstring(retval, NULL, NULL)); return NOTOK; } - sasl_initialized++; + sasl_initialized = true; } /* @@ -1042,7 +1110,8 @@ netsec_set_sasl_params(netsec_context *nsc, const char *service, * library when asked. */ -int netsec_get_user(void *context, int id, const char **result, +int +netsec_get_user(void *context, int id, const char **result, unsigned int *len) { netsec_context *nsc = (netsec_context *) context; @@ -1418,6 +1487,21 @@ netsec_get_sasl_mechanism(netsec_context *nsc) return nsc->sasl_chosen_mech; } +/* + * Return the negotiated SASL strength security factor (SSF) + */ + +int +netsec_get_sasl_ssf(netsec_context *nsc) +{ +#ifdef CYRUS_SASL + return nsc->sasl_ssf; +#else /* CYRUS_SASL */ + NMH_UNUSED(nsc); + return 0; +#endif /* CYRUS_SASL */ +} + /* * Set an OAuth2 service name, if we support it. */ @@ -1475,7 +1559,7 @@ netsec_set_tls(netsec_context *nsc, int tls, int noverify, char **errstr) return NOTOK; } - tls_initialized++; + tls_initialized = true; } if (nsc->ns_readfd == -1 || nsc->ns_writefd == -1) {