+ /*
+ * In netsec_set_sasl_params, we've already done all of our setup with
+ * sasl_client_init() and sasl_client_new(). So time to set security
+ * properties, call sasl_client_start(), and generate the protocol
+ * messages.
+ */
+
+ memset(&secprops, 0, sizeof(secprops));
+ secprops.maxbufsize = SASL_MAXRECVBUF;
+
+ /*
+ * If we're using TLS, do not negotiate a security layer
+ */
+
+ secprops.max_ssf =
+#ifdef TLS_SUPPORT
+ nsc->tls_active ? 0 :
+#endif /* TLS_SUPPORT */
+ UINT_MAX;
+
+ rc = sasl_setprop(nsc->sasl_conn, SASL_SEC_PROPS, &secprops);
+
+ if (rc != SASL_OK) {
+ netsec_err(errstr, "SASL security property initialization failed: %s",
+ sasl_errstring(rc, NULL, NULL));
+ return NOTOK;
+ }
+
+ /*
+ * Start the actual protocol negotiation, and go through the
+ * sasl_client_step() loop (after sasl_client_start, of course).
+ */
+
+ rc = sasl_client_start(nsc->sasl_conn, mechlist, NULL,
+ (const unsigned char **) &saslbuf, &saslbuflen,
+ &chosen_mech);
+
+ if (rc != SASL_OK && rc != SASL_CONTINUE) {
+ netsec_err(errstr, "SASL client start failed: %s",
+ sasl_errdetail(nsc->sasl_conn));
+ return NOTOK;
+ }
+
+ nsc->sasl_chosen_mech = getcpy(chosen_mech);
+
+ if (nsc->sasl_proto_cb(NETSEC_SASL_START, saslbuf, saslbuflen, &outbuf,
+ &outbuflen, nsc->ns_snoop, errstr) != OK)
+ return NOTOK;
+
+ 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
+ */
+
+ while (rc == SASL_CONTINUE) {
+ /*
+ * Call our SASL callback, which will handle the details of
+ * reading data from the network.
+ */
+
+ if (nsc->sasl_proto_cb(NETSEC_SASL_READ, NULL, 0, &outbuf, &outbuflen,
+ nsc->ns_snoop, errstr) != OK) {
+ if (nsc->sasl_proto_cb(NETSEC_SASL_CANCEL, NULL, 0, &outbuf,
+ &outbuflen, nsc->ns_snoop, NULL) == OK) {
+ netsec_write(nsc, outbuf, outbuflen, NULL);
+ netsec_flush(nsc, NULL);
+ }
+ return NOTOK;
+ }
+
+ rc = sasl_client_step(nsc->sasl_conn, outbuf, outbuflen, NULL,
+ &saslbuf, &saslbuflen);
+ }
+