+ bio_writer_t *writer;
+ chunk_t data;
+
+ writer = bio_writer_create(32);
+ writer->write_data8(writer, chunk_from_str(sasl->get_name(sasl)));
+ switch (sasl->build(sasl, &data))
+ {
+ case INVALID_STATE:
+ break;
+ case NEED_MORE:
+ writer->write_data(writer, data);
+ free(data.ptr);
+ break;
+ case SUCCESS:
+ /* shouldn't happen */
+ free(data.ptr);
+ /* FALL */
+ case FAILED:
+ default:
+ writer->destroy(writer);
+ return FAILED;
+ }
+ if (!pt_tls_write(this->tls, writer, PT_TLS_SASL_MECH_SELECTION,
+ this->identifier++))
+ {
+ return FAILED;
+ }
+ while (TRUE)
+ {
+ reader = pt_tls_read(this->tls, &vendor, &type, &identifier);
+ if (!reader)
+ {
+ return FAILED;
+ }
+ if (vendor != 0)
+ {
+ reader->destroy(reader);
+ return FAILED;
+ }
+ switch (type)
+ {
+ case PT_TLS_SASL_AUTH_DATA:
+ switch (sasl->process(sasl, reader->peek(reader)))
+ {
+ case NEED_MORE:
+ reader->destroy(reader);
+ break;
+ case SUCCESS:
+ /* should not happen, as it would come in a RESULT */
+ case FAILED:
+ default:
+ reader->destroy(reader);
+ return FAILED;
+ }
+ break;
+ case PT_TLS_SASL_RESULT:
+ if (!reader->read_uint8(reader, &result))
+ {
+ reader->destroy(reader);
+ return FAILED;
+ }
+ switch (result)
+ {
+ case PT_TLS_SASL_RESULT_ABORT:
+ DBG1(DBG_TNC, "received SASL abort result");
+ reader->destroy(reader);
+ return FAILED;
+ case PT_TLS_SASL_RESULT_SUCCESS:
+ DBG1(DBG_TNC, "received SASL success result");
+ switch (sasl->process(sasl, reader->peek(reader)))
+ {
+ case SUCCESS:
+ reader->destroy(reader);
+ return SUCCESS;
+ case NEED_MORE:
+ /* inacceptable, it won't get more. FALL */
+ case FAILED:
+ default:
+ reader->destroy(reader);
+ return FAILED;
+ }
+ break;
+ case PT_TLS_SASL_RESULT_MECH_FAILURE:
+ case PT_TLS_SASL_RESULT_FAILURE:
+ DBG1(DBG_TNC, "received SASL failure result");
+ /* non-fatal failure, try again */
+ reader->destroy(reader);
+ return NEED_MORE;
+ }
+ default:
+ return FAILED;
+ }
+
+ writer = bio_writer_create(32);
+ switch (sasl->build(sasl, &data))
+ {
+ case INVALID_STATE:
+ break;
+ case SUCCESS:
+ /* shoudln't happen, continue until we get a result */
+ case NEED_MORE:
+ writer->write_data(writer, data);
+ free(data.ptr);
+ break;
+ case FAILED:
+ default:
+ writer->destroy(writer);
+ return FAILED;
+ }
+ if (!pt_tls_write(this->tls, writer, PT_TLS_SASL_AUTH_DATA,
+ this->identifier++))
+ {
+ return FAILED;
+ }
+ }
+}
+
+/**
+ * Read SASL mechanism list, select and run mechanism
+ */
+static status_t select_and_do_sasl(private_pt_tls_client_t *this)
+{
+ bio_reader_t *reader;
+ sasl_mechanism_t *sasl = NULL;