X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/0e8670d5ff9bfdbfe97364ac97fc1cd8e8e66117..6648309573e82f1e4c6f441dcd616b59b8eaad71:/sbr/netsec.c diff --git a/sbr/netsec.c b/sbr/netsec.c index 7d5c48c8..97d306b4 100644 --- a/sbr/netsec.c +++ b/sbr/netsec.c @@ -71,6 +71,8 @@ struct _netsec_context { unsigned int ns_outbuflen; /* Output buffer data length */ unsigned int ns_outbufsize; /* Output buffer size */ char *sasl_mech; /* User-requested mechanism */ + char *sasl_chosen_mech; /* Mechanism chosen by SASL */ + netsec_sasl_callback sasl_proto_cb; /* SASL callback we use */ #ifdef OAUTH_SUPPORT char *oauth_service; /* OAuth2 service name */ #endif /* OAUTH_SUPPORT */ @@ -78,11 +80,9 @@ struct _netsec_context { char *sasl_hostname; /* Hostname we've connected to */ sasl_conn_t *sasl_conn; /* SASL connection context */ sasl_ssf_t sasl_ssf; /* SASL Security Strength Factor */ - netsec_sasl_callback sasl_proto_cb; /* SASL callback we use */ sasl_callback_t *sasl_cbs; /* Callbacks used by SASL */ nmh_creds_t sasl_creds; /* Credentials (username/password) */ sasl_secret_t *sasl_secret; /* SASL password structure */ - char *sasl_chosen_mech; /* Mechanism chosen by SASL */ int sasl_seclayer; /* If true, SASL security layer is enabled */ char *sasl_tmpbuf; /* Temporary read buffer for decodes */ size_t sasl_maxbufsize; /* Maximum negotiated SASL buffer size */ @@ -147,6 +147,8 @@ netsec_init(void) nsc->ns_outptr = nsc->ns_outbuffer; nsc->ns_outbuflen = 0; nsc->sasl_mech = NULL; + nsc->sasl_chosen_mech = NULL; + nsc->sasl_proto_cb = NULL; #ifdef OAUTH_SUPPORT nsc->oauth_service = NULL; #endif /* OAUTH_SUPPORT */ @@ -156,7 +158,6 @@ netsec_init(void) nsc->sasl_cbs = NULL; nsc->sasl_creds = NULL; nsc->sasl_secret = NULL; - nsc->sasl_chosen_mech = NULL; nsc->sasl_ssf = 0; nsc->sasl_seclayer = 0; nsc->sasl_tmpbuf = NULL; @@ -185,6 +186,8 @@ netsec_shutdown(netsec_context *nsc, int closeflag) free(nsc->ns_outbuffer); if (nsc->sasl_mech) free(nsc->sasl_mech); + if (nsc->sasl_chosen_mech) + free(nsc->sasl_chosen_mech); #ifdef OAUTH_SERVICE if (nsc->oauth_service) free(nsc->oauth_service); @@ -208,8 +211,6 @@ netsec_shutdown(netsec_context *nsc, int closeflag) } free(nsc->sasl_secret); } - if (nsc->sasl_chosen_mech) - free(nsc->sasl_chosen_mech); if (nsc->sasl_tmpbuf) free(nsc->sasl_tmpbuf); #endif /* CYRUS_SASL */ @@ -292,7 +293,7 @@ void netsec_b64_snoop_decoder(netsec_context *nsc, const char *string, size_t len, void *context) { - const char *decoded; + unsigned char *decoded; size_t decodedlen; int offset; NMH_UNUSED(nsc); @@ -410,11 +411,12 @@ netsec_read(netsec_context *nsc, void *buffer, size_t size, char **errstr) * * - Unlike every other function, we return a pointer to the * existing buffer. This pointer is valid until you call another - * read functiona again. - * - We NUL-terminated the buffer right at the end, before the terminator. + * read function again. + * - We NUL-terminate the buffer right at the end, before the CR-LF terminator. * - Technically we look for a LF; if we find a CR right before it, then * we back up one. - * - If your data may contain embedded NULs, this won't work. + * - If your data may contain embedded NULs, this won't work. You should + * be using netsec_read() in that case. */ char * @@ -508,7 +510,9 @@ netsec_fillread(netsec_context *nsc, char **errstr) nsc->ns_inptr = nsc->ns_inbuffer; } +#ifdef CYRUS_SASL retry: +#endif /* CYRUS_SASL */ /* * If we are using TLS and there's anything pending, then skip the * select call @@ -945,6 +949,13 @@ netsec_set_sasl_params(netsec_context *nsc, const char *hostname, return NOTOK; } + nsc->sasl_hostname = getcpy(hostname); +#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 @@ -961,14 +972,8 @@ netsec_set_sasl_params(netsec_context *nsc, const char *hostname, } nsc->sasl_proto_cb = callback; - nsc->sasl_hostname = getcpy(hostname); return OK; -#else /* CYRUS_SASL */ - netsec_err(errstr, "SASL is not supported"); - - return NOTOK; -#endif /* CYRUS_SASL */ } #ifdef CYRUS_SASL @@ -1095,7 +1100,9 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr) unsigned char *xoauth_client_res; size_t xoauth_client_res_len; #endif /* OAUTH_SUPPORT */ +#if defined CYRUS_SASL || defined OAUTH_SUPPORT int rc; +#endif /* CYRUS_SASL || OAUTH_SUPPORT */ /* * If we've been passed a requested mechanism, check our mechanism @@ -1170,7 +1177,8 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr) /* * We're going to assume the error here is a JSON response; * we ignore it and send a blank message in response. We should - * then get either an +OK or -ERR + * then get a failure messages with a useful error. We should + * NOT get a success message at this point. */ free(*errstr); nsc->sasl_proto_cb(NETSEC_SASL_WRITE, NULL, 0, NULL, 0, NULL); @@ -1359,7 +1367,18 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr) return OK; #else - netsec_err(errstr, "SASL not supported"); + /* + * If we're at this point, then either we have NEITHER OAuth2 or + * Cyrus-SASL compiled in, or have OAuth2 but didn't give the XOAUTH2 + * mechanism on the command line. + */ + + if (! nsc->sasl_mech) + netsec_err(errstr, "SASL library support not available; please " + "specify a SASL mechanism to use"); + else + netsec_err(errstr, "No support for the %s SASL mechanism", + nsc->sasl_mech); return NOTOK; #endif /* CYRUS_SASL */ @@ -1372,11 +1391,7 @@ netsec_negotiate_sasl(netsec_context *nsc, const char *mechlist, char **errstr) char * netsec_get_sasl_mechanism(netsec_context *nsc) { -#ifdef CYRUS_SASL return nsc->sasl_chosen_mech; -#else /* CYRUS_SASL */ - return NULL; -#endif /* CYRUS_SASL */ } /* @@ -1390,6 +1405,8 @@ netsec_set_oauth_service(netsec_context *nsc, const char *service) nsc->oauth_service = getcpy(service); return OK; #else /* OAUTH_SUPPORT */ + NMH_UNUSED(nsc); + NMH_UNUSED(service); return NOTOK; #endif /* OAUTH_SUPPORT */ } @@ -1462,12 +1479,11 @@ netsec_set_tls(netsec_context *nsc, int tls, char **errstr) * supplied socket. * * Then we create an SSL BIO, and assign our current SSL connection - * to it. We then create a buffer BIO and push it in front of our - * SSL BIO. So the chain looks like: - * - * buffer BIO -> SSL BIO -> socket BIO. + * to it. This is done so our code stays simple if we want to use + * any buffering BIOs (right now we do our own buffering). + * So the chain looks like: * - * So writes and reads are buffered (we mostly care about writes). + * SSL BIO -> socket BIO. */ rbio = BIO_new_socket(nsc->ns_readfd, BIO_NOCLOSE);