+ rc = sasl_client_step(nsc->sasl_conn, (char *) outbuf, outbuflen, NULL,
+ (const char **) &saslbuf, &saslbuflen);
+
+ free(outbuf);
+
+ 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) {
+ netsec_write(nsc, outbuf, outbuflen, NULL);
+ netsec_flush(nsc, NULL);
+ free(outbuf);
+ }
+ 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) {
+ netsec_write(nsc, outbuf, outbuflen, NULL);
+ netsec_flush(nsc, NULL);
+ free(outbuf);
+ }
+ return NOTOK;
+ }
+
+ if (netsec_write(nsc, outbuf, outbuflen, errstr) != OK) {
+ free(outbuf);
+ return NOTOK;
+ }
+
+ free(outbuf);
+
+ if (netsec_flush(nsc, errstr) != OK)
+ return NOTOK;
+ }
+
+ /*
+ * SASL exchanges should be complete, process the final response message
+ * from the server.
+ */
+
+ if (nsc->sasl_proto_cb(NETSEC_SASL_FINISH, NULL, 0, NULL, 0,
+ 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 NOTOK;
+ }
+
+ /*
+ * At this point, SASL should be complete. Get a few properties
+ * from the authentication exchange.
+ */
+
+ rc = sasl_getprop(nsc->sasl_conn, SASL_SSF, (const void **) &ssf);
+
+ if (rc != SASL_OK) {
+ netsec_err(errstr, "Cannot retrieve SASL negotiated security "
+ "strength factor: %s", sasl_errstring(rc, NULL, NULL));
+ return NOTOK;
+ }
+
+ nsc->sasl_ssf = *ssf;
+
+ if (nsc->sasl_ssf > 0) {
+ rc = sasl_getprop(nsc->sasl_conn, SASL_MAXOUTBUF,
+ (const void **) &outbufmax);
+
+ if (rc != SASL_OK) {
+ netsec_err(errstr, "Cannot retrieve SASL negotiated output "
+ "buffer size: %s", sasl_errstring(rc, NULL, NULL));
+ return NOTOK;
+ }
+
+ nsc->sasl_maxoutsize = *outbufmax;
+
+ if (nsc->sasl_maxoutsize > nsc->ns_outbufsize) {
+ nsc->ns_outbufsize = nsc->sasl_maxoutsize;
+ nsc->ns_outbuffer = mh_xrealloc(nsc->ns_outbuffer,
+ nsc->ns_outbufsize);
+ }