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 */
char *sasl_mech; /* User-requested mechanism */
char *sasl_chosen_mech; /* Mechanism chosen by SASL */
netsec_sasl_callback sasl_proto_cb; /* SASL callback we use */
+ void *sasl_proto_context; /* Context to be used by SASL callback */
#ifdef OAUTH_SUPPORT
char *oauth_service; /* OAuth2 service name */
#endif /* OAUTH_SUPPORT */
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 */
nsc->sasl_mech = NULL;
nsc->sasl_chosen_mech = NULL;
nsc->sasl_proto_cb = NULL;
+ nsc->sasl_proto_context = NULL;
#ifdef OAUTH_SUPPORT
nsc->oauth_service = NULL;
#endif /* OAUTH_SUPPORT */
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 */
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;
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.
int
netsec_set_sasl_params(netsec_context *nsc, const char *service,
const char *mechanism, netsec_sasl_callback callback,
- char **errstr)
+ void *context, char **errstr)
{
#ifdef CYRUS_SASL
sasl_callback_t *sasl_cbs;
*/
if (mechanism) {
- char *p;
nsc->sasl_mech = mh_xstrdup(mechanism);
-
- for (p = nsc->sasl_mech; *p; p++)
- if (isascii((unsigned char) *p)) /* Leave non-ASCII lower alone. */
- *p = toupper((unsigned char) *p);
+ to_upper(nsc->sasl_mech);
}
nsc->sasl_proto_cb = callback;
+ nsc->sasl_proto_context = context;
return OK;
}
* us room for a terminating NUL
*/
- *psecret = (sasl_secret_t *) malloc(sizeof(sasl_secret_t) + len);
+ *psecret = malloc(sizeof(sasl_secret_t) + len);
if (! *psecret)
return SASL_NOMEM;
}
rc = nsc->sasl_proto_cb(NETSEC_SASL_START, xoauth_client_res,
- xoauth_client_res_len, NULL, 0, errstr);
+ xoauth_client_res_len, NULL, 0,
+ nsc->sasl_proto_context, errstr);
free(xoauth_client_res);
if (rc != OK)
* error.
*/
- rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0, errstr);
+ rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
+ nsc->sasl_proto_context, errstr);
if (rc != OK) {
/*
* NOT get a success message at this point.
*/
free(*errstr);
- nsc->sasl_proto_cb(NETSEC_SASL_WRITE, NULL, 0, NULL, 0, NULL);
+ nsc->sasl_proto_cb(NETSEC_SASL_WRITE, NULL, 0, NULL, 0,
+ nsc->sasl_proto_context, NULL);
rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
- errstr);
+ nsc->sasl_proto_context, errstr);
if (rc == 0) {
netsec_err(errstr, "Unexpected success after OAuth failure!");
}
nsc->sasl_chosen_mech = getcpy(chosen_mech);
if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, NULL, 0,
- errstr) != OK)
+ nsc->sasl_proto_context, errstr) != OK)
return NOTOK;
/*
*/
if (nsc->sasl_proto_cb(NETSEC_SASL_READ, NULL, 0, &outbuf, &outbuflen,
- errstr) != OK) {
- nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
+ nsc->sasl_proto_context, errstr) != OK) {
+ nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0,
+ nsc->sasl_proto_context, NULL);
return NOTOK;
}
if (rc != SASL_OK && rc != SASL_CONTINUE) {
netsec_err(errstr, "SASL client negotiation failed: %s",
sasl_errdetail(nsc->sasl_conn));
- nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
+ nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0,
+ nsc->sasl_proto_context, NULL);
return NOTOK;
}
if (nsc->sasl_proto_cb(NETSEC_SASL_WRITE, saslbuf, saslbuflen,
- NULL, 0, errstr) != OK) {
- nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
+ NULL, 0, nsc->sasl_proto_context,
+ errstr) != OK) {
+ nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0,
+ nsc->sasl_proto_context, NULL);
return NOTOK;
}
}
*/
if (nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
- errstr) != OK) {
+ nsc->sasl_proto_context, errstr) != OK) {
/*
* At this point we can't really send an abort since the SASL dialog
* has completed, so just bubble back up the error message.
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 */
+ return 0;
+#endif /* CYRUS_SASL */
+}
+
/*
* Set an OAuth2 service name, if we support it.
*/