struct _netsec_context {
int ns_fd; /* Descriptor for network connection */
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 */
int ns_timeout; /* Network read timeout, in seconds */
char *ns_userid; /* Userid for authentication */
unsigned char *ns_inbuffer; /* Our read input buffer */
nsc->ns_fd = -1;
nsc->ns_snoop = 0;
+ nsc->ns_snoop_noend = 0;
+ nsc->ns_snoop_cb = NULL;
nsc->ns_userid = NULL;
nsc->ns_timeout = 60; /* Our default */
nsc->ns_inbufsize = NETSEC_BUFSIZE;
*len = ptr - nsc->ns_inptr;
nsc->ns_inptr += count;
nsc->ns_inbuflen -= count;
+ if (nsc->ns_snoop) {
+#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, sptr, strlen(sptr));
+ else
+ fprintf(stderr, "%s\n", sptr);
+ }
return sptr;
}
}
}
}
+ 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, nsc->ns_outptr, outlen);
+ else
+ fprintf(stderr, "%.*s\n", outlen, nsc->ns_outptr);
+ } else {
+ nsc->ns_snoop_noend = 0;
+ }
+ }
+
nsc->ns_outptr += rc;
nsc->ns_outbuflen += rc;
int *outbufmax;
#endif
#ifdef OAUTH_SUPPORT
- const char *xoauth_client_res;
+ unsigned char *xoauth_client_res;
+ size_t xoauth_client_res_len;
#endif /* OAUTH_SUPPORT */
int rc;
}
#ifdef OAUTH_SUPPORT
- if (strcasecmp(nsc->sasl_mech, "XOAUTH2") == 0) {
+ if (nsc->sasl_mech && strcasecmp(nsc->sasl_mech, "XOAUTH2") == 0) {
/*
* This should be relatively straightforward, but requires some
* help from the plugin. Basically, if XOAUTH2 is a success,
- * the plugin has to return success, but no output data. If
+ * the callback has to return success, but no output data. If
* there is output data, it will be assumed that it is the JSON
* error message.
*/
nsc->sasl_chosen_mech = getcpy(nsc->sasl_mech);
- xoauth_client_res = mh_oauth_do_xoauth(nsc->ns_userid,
- nsc->oauth_service,
- nsc->ns_snoop ? stderr : NULL);
-
- if (xoauth_client_res == NULL) {
- netsec_err(errstr, "Internal error: mh_oauth_do_xoauth() "
- "returned NULL");
+ if (mh_oauth_do_xoauth(nsc->ns_userid, nsc->oauth_service,
+ &xoauth_client_res, &xoauth_client_res_len,
+ nsc->ns_snoop ? stderr : NULL) != OK) {
+ netsec_err(errstr, "Internal error: Unable to get OAuth2 "
+ "bearer token");
return NOTOK;
}
-#if 0
- rc = nsc->sasl_proto_cb(NETSEC_SASL_START,
-#endif
+ rc = nsc->sasl_proto_cb(NETSEC_SASL_START, xoauth_client_res,
+ xoauth_client_res_len, NULL, 0, errstr);
+ free(xoauth_client_res);
+
+ if (rc != OK)
+ return NOTOK;
+
+ /*
+ * Okay, we need to do a NETSEC_SASL_FINISH now. If we return
+ * success, we indicate that with no output data. But if we
+ * fail, then send a blank message and get the resulting
+ * error.
+ */
+
+ rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0, errstr);
+
+ if (rc != OK) {
+ /*
+ * 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
+ */
+ free(errstr);
+ nsc->sasl_proto_cb(NETSEC_SASL_WRITE, NULL, 0, NULL, 0, NULL);
+ rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
+ errstr);
+ if (rc == 0) {
+ netsec_err(errstr, "Unexpected success after OAuth failure!");
+ }
+ return NOTOK;
+ }
+ return OK;
}
#endif /* OAUTH_SUPPORT */
nsc->sasl_chosen_mech = getcpy(chosen_mech);
- if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, &outbuf,
- &outbuflen, errstr) != OK)
+ if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, NULL, 0,
+ errstr) != OK)
return NOTOK;
- if (outbuflen > 0) {
- if (netsec_write(nsc, outbuf, outbuflen, errstr) != OK) {
- free(outbuf);
- return NOTOK;
- }
- free(outbuf);
- if (netsec_flush(nsc, errstr) != OK)
- return NOTOK;
- }
-
-
/*
* We've written out our first message; enter in the step loop
*/
if (nsc->sasl_proto_cb(NETSEC_SASL_READ, NULL, 0, &outbuf, &outbuflen,
errstr) != OK) {
- if (nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, &outbuf,
- &outbuflen, NULL) == OK) {
- if (outbuflen > 0) {
- netsec_write(nsc, outbuf, outbuflen, NULL);
- netsec_flush(nsc, NULL);
- free(outbuf);
- }
- }
+ nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
return NOTOK;
}
if (rc != SASL_OK && rc != SASL_CONTINUE) {
netsec_err(errstr, "SASL client negotiation failed: %s",
sasl_errdetail(nsc->sasl_conn));
- if (nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, &outbuf,
- &outbuflen, NULL) == OK) {
- if (outbuflen > 0) {
- netsec_write(nsc, outbuf, outbuflen, NULL);
- netsec_flush(nsc, NULL);
- free(outbuf);
- }
- }
+ nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
return NOTOK;
}
if (nsc->sasl_proto_cb(NETSEC_SASL_WRITE, saslbuf, saslbuflen,
- &outbuf, &outbuflen, errstr) != OK) {
- if (nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, &outbuf,
- &outbuflen, NULL) == OK) {
- if (outbuflen > 0) {
- netsec_write(nsc, outbuf, outbuflen, NULL);
- netsec_flush(nsc, NULL);
- free(outbuf);
- }
- }
+ NULL, 0, errstr) != OK) {
+ nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, NULL, 0, NULL);
return NOTOK;
}
-
- if (outbuflen > 0) {
- if (netsec_write(nsc, outbuf, outbuflen, errstr) != OK) {
- free(outbuf);
- return NOTOK;
- }
- free(outbuf);
- if (netsec_flush(nsc, errstr) != OK)
- return NOTOK;
- }
}
/*