[PATCH v2 7/7] wldap32: supply SASL credentials in a mechanism-specific form

Damjan Jovanovic damjan.jov at gmail.com
Sat Feb 13 04:45:30 CST 2021


So far it appears that SASL mechanisms require credentials supplied
to them in a mechanism-specific form.

OpenLDAP's ldap_sasl_interactive_bind() passes the caller-supplied
rmech to ldap_int_sasl_bind() in libraries/libldap/cyrus.c.
There, it is populated from the chosen authentication mechanism
(mech) returned by sasl_client_start(), before calling the interact()
callback. By providing rmech to our sasl_interact() callback, it can
know which SASL mechanism it is supplying credentials for, and can
supply them in a mechanism-specific form.

Hans reported GSSAPI and GSS-SPNEGO want an empty AUTH_CB_USER.
I verified DIGEST-MD5 wants AUTH_CB_AUTHNAME and doesn't mind if
AUTH_CB_USER is supplied. Dmitry reported that for his mechanism
(some variation of Kerberos?) AUTH_CB_AUTHNAME is used for initial
tickets but AUTH_CB_USER is mandatory thereafter. This patch should
hopefully make all those mechanisms happy.

Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=50572
Signed-off-by: Damjan Jovanovic <damjan.jov at gmail.com>
---
 dlls/wldap32/bind.c | 65 ++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 58 insertions(+), 7 deletions(-)
-------------- next part --------------
diff --git a/dlls/wldap32/bind.c b/dlls/wldap32/bind.c
index 1498dc49fe6..826feca9bc8 100644
--- a/dlls/wldap32/bind.c
+++ b/dlls/wldap32/bind.c
@@ -181,28 +181,50 @@ exit:
 
 #ifdef HAVE_LDAP
 
+struct bind_pvt {
+    SEC_WINNT_AUTH_IDENTITY_A *id;
+    const char *mech;
+};
+
 static int sasl_interact( LDAP *ld, unsigned flags, void *defaults, void *interact )
 {
 #ifdef HAVE_SASL_SASL_H
-    SEC_WINNT_AUTH_IDENTITY_A *id = defaults;
+    struct bind_pvt *pvt = defaults;
+    SEC_WINNT_AUTH_IDENTITY_A *id = pvt->id;
+    const char *mech = pvt->mech;
     sasl_interact_t *sasl = interact;
 
     TRACE( "%p,%08x,%p,%p\n", ld, flags, defaults, interact );
 
+    if (mech == NULL)
+        mech = "unknown/invalid";
+
     while (sasl->id != SASL_CB_LIST_END)
     {
-        TRACE("sasl->id = %04lx\n", sasl->id);
+        TRACE("mechanism %s, sasl->id = %04lx\n", debugstr_a(mech), sasl->id);
 
         if (sasl->id == SASL_CB_GETREALM)
         {
             sasl->result = id->Domain;
             sasl->len = id->DomainLength;
         }
-        else if (sasl->id == SASL_CB_USER)
+        else if (sasl->id == SASL_CB_AUTHNAME)
         {
             sasl->result = id->User;
             sasl->len = id->UserLength;
         }
+        else if (sasl->id == SASL_CB_USER)
+        {
+            if (!strcmp(mech, "GSSAPI"))
+                ;
+            else if (!strcmp(mech, "GSS-SPNEGO"))
+                ;
+            else
+            {
+                sasl->result = id->User;
+                sasl->len = id->UserLength;
+            }
+        }
         else if (sasl->id == SASL_CB_PASS)
         {
             sasl->result = id->Password;
@@ -219,6 +241,38 @@ static int sasl_interact( LDAP *ld, unsigned flags, void *defaults, void *intera
 #endif /* HAVE_SASL_SASL_H */
 }
 
+static int _sasl_bind_s( LDAP *ld, SEC_WINNT_AUTH_IDENTITY_A *idU )
+{
+    struct bind_pvt pvt;
+    LDAPMessage *result = NULL;
+
+    pvt.id = idU;
+    pvt.mech = NULL;
+    while (1)
+    {
+        int msgid;
+        int ret;
+
+        ret = ldap_sasl_interactive_bind( ld,
+                                          NULL /* server will ignore DN anyway */,
+                                          NULL /* query supportedSASLMechanisms */,
+                                          NULL, NULL, LDAP_SASL_QUIET, sasl_interact, &pvt,
+                                          result, &pvt.mech, &msgid );
+        ldap_msgfree( result );
+        if (ret != LDAP_SASL_BIND_IN_PROGRESS)
+            return ret;
+        ret = ldap_result( ld, msgid, LDAP_MSG_ALL, NULL, &result );
+        if ( ret == -1 || !result )
+        {
+            int err;
+            ldap_get_option( ld, LDAP_OPT_RESULT_CODE, &err );
+            return err;
+        }
+        else if ( ret == 0 )
+            return LDAP_TIMELIMIT_EXCEEDED;
+    }
+}
+
 #endif /* HAVE_LDAP */
 
 /***********************************************************************
@@ -292,10 +346,7 @@ ULONG CDECL ldap_bind_sW( WLDAP32_LDAP *ld, PWCHAR dn, PWCHAR cred, ULONG method
             idU.Password = (unsigned char *)strnWtoU( id->Password, id->PasswordLength, &idU.PasswordLength );
         }
 
-        ret = map_error( ldap_sasl_interactive_bind_s( ld->ld,
-                             NULL /* server will ignore DN anyway */,
-                             NULL /* query supportedSASLMechanisms */,
-                             NULL, NULL, LDAP_SASL_QUIET, sasl_interact, &idU ));
+        ret = map_error( _sasl_bind_s( ld->ld, &idU ));
 
         if (id && (id->Flags & SEC_WINNT_AUTH_IDENTITY_ANSI))
         {


More information about the wine-devel mailing list