+
+int
+ldap_pvt_sasl_getmechs ( LDAP *ld, char **pmechlist )
+{
+ /* we need to query the server for supported mechs anyway */
+ LDAPMessage *res, *e;
+ char *attrs[] = { "supportedSASLMechanisms", NULL };
+ char **values, *mechlist;
+ int rc;
+
+ Debug( LDAP_DEBUG_TRACE, "ldap_pvt_sasl_getmech\n", 0, 0, 0 );
+
+ rc = ldap_search_s( ld, "", LDAP_SCOPE_BASE,
+ NULL, attrs, 0, &res );
+
+ if ( rc != LDAP_SUCCESS ) {
+ return ld->ld_errno;
+ }
+
+ e = ldap_first_entry( ld, res );
+ if ( e == NULL ) {
+ ldap_msgfree( res );
+ if ( ld->ld_errno == LDAP_SUCCESS ) {
+ ld->ld_errno = LDAP_NO_SUCH_OBJECT;
+ }
+ return ld->ld_errno;
+ }
+
+ values = ldap_get_values( ld, e, "supportedSASLMechanisms" );
+ if ( values == NULL ) {
+ ldap_msgfree( res );
+ ld->ld_errno = LDAP_NO_SUCH_ATTRIBUTE;
+ return ld->ld_errno;
+ }
+
+ mechlist = ldap_charray2str( values, " " );
+ if ( mechlist == NULL ) {
+ LDAP_VFREE( values );
+ ldap_msgfree( res );
+ ld->ld_errno = LDAP_NO_MEMORY;
+ return ld->ld_errno;
+ }
+
+ LDAP_VFREE( values );
+ ldap_msgfree( res );
+
+ *pmechlist = mechlist;
+
+ return LDAP_SUCCESS;
+}
+
+/*
+ * ldap_sasl_interactive_bind_s - interactive SASL authentication
+ *
+ * This routine uses interactive callbacks.
+ *
+ * LDAP_SUCCESS is returned upon success, the ldap error code
+ * otherwise.
+ */
+int
+ldap_sasl_interactive_bind_s(
+ LDAP *ld,
+ LDAP_CONST char *dn, /* usually NULL */
+ LDAP_CONST char *mechs,
+ LDAPControl **serverControls,
+ LDAPControl **clientControls,
+ unsigned flags,
+ LDAP_SASL_INTERACT_PROC *interact,
+ void *defaults )
+{
+ int rc;
+
+#if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
+ ldap_pvt_thread_mutex_lock( &ldap_int_sasl_mutex );
+#endif
+#ifdef LDAP_CONNECTIONLESS
+ if( LDAP_IS_UDP(ld) ) {
+ /* Just force it to simple bind, silly to make the user
+ * ask all the time. No, we don't ever actually bind, but I'll
+ * let the final bind handler take care of saving the cdn.
+ */
+ rc = ldap_simple_bind(ld, dn, NULL);
+ return rc < 0 ? rc : 0;
+ } else
+#endif
+ if( mechs == NULL || *mechs == '\0' ) {
+ char *smechs;
+
+ rc = ldap_pvt_sasl_getmechs( ld, &smechs );
+
+ if( rc != LDAP_SUCCESS ) {
+ goto done;
+ }
+
+ Debug( LDAP_DEBUG_TRACE,
+ "ldap_interactive_sasl_bind_s: server supports: %s\n",
+ smechs, 0, 0 );
+
+ mechs = smechs;
+
+ } else {
+ Debug( LDAP_DEBUG_TRACE,
+ "ldap_interactive_sasl_bind_s: user selected: %s\n",
+ mechs, 0, 0 );
+ }
+
+ rc = ldap_int_sasl_bind( ld, dn, mechs,
+ serverControls, clientControls,
+ flags, interact, defaults );
+
+done:
+#if defined( LDAP_R_COMPILE ) && defined( HAVE_CYRUS_SASL )
+ ldap_pvt_thread_mutex_unlock( &ldap_int_sasl_mutex );
+#endif
+
+ return rc;
+}