+ if (i) {
+ netsec_err(errstr, "Chosen mechanism %s not supported by server",
+ nsc->sasl_mech);
+ return NOTOK;
+ }
+ }
+
+#ifdef OAUTH_SUPPORT
+ 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 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.
+ */
+
+ if (nsc->ns_snoop) {
+ fprintf(stderr, "Using internal XOAUTH2 mechanism\n");
+ }
+
+ if (! nsc->oauth_service) {
+ netsec_err(errstr, "Internal error: OAuth2 service name not given");
+ return NOTOK;
+ }
+
+ nsc->sasl_chosen_mech = mh_xstrdup(nsc->sasl_mech);
+
+ 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;
+ }
+
+ rc = nsc->sasl_proto_cb(NETSEC_SASL_START, xoauth_client_res,
+ xoauth_client_res_len, NULL, 0,
+ nsc->sasl_proto_context, 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,
+ nsc->sasl_proto_context, 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 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,
+ nsc->sasl_proto_context, NULL);
+ rc = nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
+ nsc->sasl_proto_context, errstr);
+ if (rc == 0) {
+ netsec_err(errstr, "Unexpected success after OAuth failure!");
+ }
+ return NOTOK;
+ }
+ return OK;
+ }
+#endif /* OAUTH_SUPPORT */
+
+#ifdef CYRUS_SASL