+ /*
+ * If we've been passed a requested mechanism, check our mechanism
+ * list from the protocol. If it's not supported, return an error.
+ */
+
+ if (nsc->sasl_mech) {
+ char **str, *mlist = getcpy(mechlist);
+ int i;
+
+ str = brkstring(mlist, " ", NULL);
+
+ for (i = 0; str[i] != NULL; i++) {
+ if (strcasecmp(nsc->sasl_mech, str[i]) == 0) {
+ break;
+ }
+ }
+
+ i = (str[i] == NULL);
+
+ free(str);
+ free(mlist);
+
+ 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->oauth_service) {
+ netsec_err(errstr, "Internal error: OAuth2 service name not given");
+ return NOTOK;
+ }
+
+ nsc->sasl_chosen_mech = getcpy(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, 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 */
+
+#ifdef CYRUS_SASL