https://bugs.winehq.org/show_bug.cgi?id=55304
Bug ID: 55304 Summary: Kerberos authentication stopped to work after PE wldap32 conversion Product: Wine Version: 8.13 Hardware: x86-64 OS: Linux Status: NEW Keywords: patch, regression Severity: normal Priority: P2 Component: wldap32 Assignee: wine-bugs@winehq.org Reporter: dmitry@baikal.ru CC: hans@meelstraat.net Regression SHA1: 02e52db7aa627b980dec3dfd4053e20a380ee555 Distribution: ---
Created attachment 74900 --> https://bugs.winehq.org/attachment.cgi?id=74900 patch
SASL2 plugin in libs/ldap/libldap/sasl_w.c doesn't follow the rfc4752 specification in several ways, and it looks like it was never tested with Kerberos since it queries the key info using QueryContextAttributesA(SECPKG_ATTR_KEY_INFO) however this attribute is not supported neither by Wine Kerberos implementation nor by Kerberos in Windows 10. Actually SSF (SASL Security Strength Factor) value returned by the plugin is never used by libldap, so it's not necessary to set SSF to anything but 1. Besides, dlls/kerberos uses constants for trailer, signature and max buffer size that no longer work with modern implementations. Also at least the Kerberos servers I was testing with use trailer length either 64 or 60, so I had to add a patch to query Kerberos security trailer length from the context, otherwise it's not possible to correctly encode/decode LDAP messages and server responses.
I'm attaching a patch that makes Kerberos authentication work again.
Here are some useful links that were used as a reference: https://www.rfc-editor.org/rfc/rfc4752#page-3 https://github.com/openldap/openldap/blob/master/libraries/libldap/cyrus.c https://github.com/cyrusimap/cyrus-sasl/blob/master/lib/client.c https://github.com/cyrusimap/cyrus-sasl/blob/master/plugins/gssapi.c
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #1 from Hans Leidekker hans@meelstraat.net --- I have replaced QueryContextAttributesA(SECPKG_ATTR_KEY_INFO) with QueryContextAttributesA(SECPKG_ATTR_SESSION_KEY) after implementing the attribute for Kerberos and NTLM.
SSF is used by ldap_int_sasl_bind() to determine if the SASL security layer should be used at all. This page documents it as representing the key size for values > 1:
https://docs.oracle.com/cd/E19120-01/open.solaris/819-2145/sasl.intro-44/ind...
I don't understand why the trailer size depends on the server since we have always depended on a constant trailer size. Is that because of a difference between Samba and AD?
I can find references for Windows changing from 12000 max token size to 48000 but not 48256. Where does it come from?
Also note that your changes to sasl_decode() and sasl_encode() break NTLM.
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #2 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Hans Leidekker from comment #1)
Thanks for looking at this.
I have replaced QueryContextAttributesA(SECPKG_ATTR_KEY_INFO) with QueryContextAttributesA(SECPKG_ATTR_SESSION_KEY) after implementing the attribute for Kerberos and NTLM.
Thanks.
SSF is used by ldap_int_sasl_bind() to determine if the SASL security layer should be used at all. This page documents it as representing the key size for values > 1:
https://docs.oracle.com/cd/E19120-01/open.solaris/819-2145/sasl.intro-44/ index.html
libldap simply checks for a not zero ssf value: https://github.com/openldap/openldap/blob/master/libraries/libldap/cyrus.c#L...
I don't understand why the trailer size depends on the server since we have always depended on a constant trailer size. Is that because of a difference between Samba and AD?
I've tested with Microsoft and Samba servers and both of them use 60 for actual encryped data, and decrypting with 64 abviously doesn't work. In the same time QueryContextAttributesA(SECPKG_ATTR_SIZES) returns 64 for the connection.
I can find references for Windows changing from 12000 max token size to 48000 but not 48256. Where does it come from?
It comes from a test that calls QueryContextAttributesA(SECPKG_ATTR_SIZES) under Windows 10 for the Samba server.
Also note that your changes to sasl_decode() and sasl_encode() break NTLM.
Do you have a sample code that breaks that could be used for testing purposes?
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #3 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Hans Leidekker from comment #1)
I have replaced QueryContextAttributesA(SECPKG_ATTR_KEY_INFO) with QueryContextAttributesA(SECPKG_ATTR_SESSION_KEY) after implementing the attribute for Kerberos and NTLM.
According to my testing Kerberos implementation under Windows 10 returns SEC_E_UNSUPPORTED_FUNCTION for QueryContextAttributes(SECPKG_ATTR_SESSION_KEY). What Windows version are you testing with?
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #4 from Hans Leidekker hans@meelstraat.net --- (In reply to Dmitry Timoshkov from comment #3)
(In reply to Hans Leidekker from comment #1)
I have replaced QueryContextAttributesA(SECPKG_ATTR_KEY_INFO) with QueryContextAttributesA(SECPKG_ATTR_SESSION_KEY) after implementing the attribute for Kerberos and NTLM.
According to my testing Kerberos implementation under Windows 10 returns SEC_E_UNSUPPORTED_FUNCTION for QueryContextAttributes(SECPKG_ATTR_SESSION_KEY). What Windows version are you testing with?
A very old Windows 2008 system.
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #5 from Hans Leidekker hans@meelstraat.net --- (In reply to Dmitry Timoshkov from comment #3)
(In reply to Hans Leidekker from comment #1)
I have replaced QueryContextAttributesA(SECPKG_ATTR_KEY_INFO) with QueryContextAttributesA(SECPKG_ATTR_SESSION_KEY) after implementing the attribute for Kerberos and NTLM.
According to my testing Kerberos implementation under Windows 10 returns SEC_E_UNSUPPORTED_FUNCTION for QueryContextAttributes(SECPKG_ATTR_SESSION_KEY). What Windows version are you testing with?
What about Negotiate?
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #6 from Hans Leidekker hans@meelstraat.net --- (In reply to Dmitry Timoshkov from comment #2)
(In reply to Hans Leidekker from comment #1)
SSF is used by ldap_int_sasl_bind() to determine if the SASL security layer should be used at all. This page documents it as representing the key size for values > 1:
https://docs.oracle.com/cd/E19120-01/open.solaris/819-2145/sasl.intro-44/ index.html
libldap simply checks for a not zero ssf value: https://github.com/openldap/openldap/blob/master/libraries/libldap/cyrus. c#L745
That's an implementation detail we shouldn't rely on.
I don't understand why the trailer size depends on the server since we have always depended on a constant trailer size. Is that because of a difference between Samba and AD?
I've tested with Microsoft and Samba servers and both of them use 60 for actual encryped data, and decrypting with 64 abviously doesn't work. In the same time QueryContextAttributesA(SECPKG_ATTR_SIZES) returns 64 for the connection.
I can find references for Windows changing from 12000 max token size to 48000 but not 48256. Where does it come from?
It comes from a test that calls QueryContextAttributesA(SECPKG_ATTR_SIZES) under Windows 10 for the Samba server.
Hmm, maybe it's not decrypting in-place? This used to work without querying the trailer size from the context.
Also note that your changes to sasl_decode() and sasl_encode() break NTLM.
Do you have a sample code that breaks that could be used for testing purposes?
I modified the wldap32 test to connect to an AD LDAP server and hacked the Kerberos dll to return an error so that Negotiate falls back to NTLM. Essentially it's this:
ldap_bind_sA( ld, NULL, (char *)&auth_id, LDAP_AUTH_NEGOTIATE );
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #7 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Hans Leidekker from comment #6)
Also note that your changes to sasl_decode() and sasl_encode() break NTLM.
Do you have a sample code that breaks that could be used for testing purposes?
I modified the wldap32 test to connect to an AD LDAP server and hacked the Kerberos dll to return an error so that Negotiate falls back to NTLM. Essentially it's this:
ldap_bind_sA( ld, NULL, (char *)&auth_id, LDAP_AUTH_NEGOTIATE );
According to my testing with the attached patchset and WINEDEBUG=+libldap simply connecting with ldap_search_s(LDAP_AUTH_NEGOTIATE) doesn't involve SASL plugin encoding/decoding, but ldap_search_s("defaultNamingContext") after the connection does, that's why I've added a test with ldap_search_s().
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #8 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Dmitry Timoshkov from comment #7)
(In reply to Hans Leidekker from comment #6)
Also note that your changes to sasl_decode() and sasl_encode() break NTLM.
Do you have a sample code that breaks that could be used for testing purposes?
I modified the wldap32 test to connect to an AD LDAP server and hacked the Kerberos dll to return an error so that Negotiate falls back to NTLM. Essentially it's this:
ldap_bind_sA( ld, NULL, (char *)&auth_id, LDAP_AUTH_NEGOTIATE );
According to my testing with the attached patchset and WINEDEBUG=+libldap simply connecting with ldap_search_s(LDAP_AUTH_NEGOTIATE) doesn't involve
Sorry, a typo: should be 'simply connecting with ldap_bind_s(LDAP_AUTH_NEGOTIATE)'.
SASL plugin encoding/decoding, but ldap_search_s("defaultNamingContext") after the connection does, that's why I've added a test with ldap_search_s().
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #9 from Hans Leidekker hans@meelstraat.net --- (In reply to Dmitry Timoshkov from comment #8)
(In reply to Dmitry Timoshkov from comment #7)
(In reply to Hans Leidekker from comment #6)
Also note that your changes to sasl_decode() and sasl_encode() break NTLM.
Do you have a sample code that breaks that could be used for testing purposes?
I modified the wldap32 test to connect to an AD LDAP server and hacked the Kerberos dll to return an error so that Negotiate falls back to NTLM. Essentially it's this:
ldap_bind_sA( ld, NULL, (char *)&auth_id, LDAP_AUTH_NEGOTIATE );
According to my testing with the attached patchset and WINEDEBUG=+libldap simply connecting with ldap_search_s(LDAP_AUTH_NEGOTIATE) doesn't involve
Sorry, a typo: should be 'simply connecting with ldap_bind_s(LDAP_AUTH_NEGOTIATE)'.
SASL plugin encoding/decoding, but ldap_search_s("defaultNamingContext") after the connection does, that's why I've added a test with ldap_search_s().
Right, to test NTLM encoding/decoding you also need a search call.
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #10 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Hans Leidekker from comment #5)
(In reply to Dmitry Timoshkov from comment #3)
(In reply to Hans Leidekker from comment #1)
I have replaced QueryContextAttributesA(SECPKG_ATTR_KEY_INFO) with QueryContextAttributesA(SECPKG_ATTR_SESSION_KEY) after implementing the attribute for Kerberos and NTLM.
According to my testing Kerberos implementation under Windows 10 returns SEC_E_UNSUPPORTED_FUNCTION for QueryContextAttributes(SECPKG_ATTR_SESSION_KEY). What Windows version are you testing with?
What about Negotiate?
Do you have an idea how to test it? Apparently for a proper test it's necessary to create a connection, and once the connection is set up it's up to a backend (NTLM/Kerberos) to handle it.
(In reply to Hans Leidekker from comment #6)
(In reply to Dmitry Timoshkov from comment #2)
(In reply to Hans Leidekker from comment #1)
SSF is used by ldap_int_sasl_bind() to determine if the SASL security layer should be used at all. This page documents it as representing the key size for values > 1:
https://docs.oracle.com/cd/E19120-01/open.solaris/819-2145/sasl.intro-44/ index.html
libldap simply checks for a not zero ssf value: https://github.com/openldap/openldap/blob/master/libraries/libldap/cyrus. c#L745
That's an implementation detail we shouldn't rely on.
Why? Since libldap is now part of wldap32 and GSSAPI SASL pluging is also part of libldap now it's part of the implementation detail we can surely rely on.
I don't understand why the trailer size depends on the server since we have always depended on a constant trailer size. Is that because of a difference between Samba and AD?
I've tested with Microsoft and Samba servers and both of them use 60 for actual encryped data, and decrypting with 64 abviously doesn't work. In the same time QueryContextAttributesA(SECPKG_ATTR_SIZES) returns 64 for the connection.
I can find references for Windows changing from 12000 max token size to 48000 but not 48256. Where does it come from?
It comes from a test that calls QueryContextAttributesA(SECPKG_ATTR_SIZES) under Windows 10 for the Samba server.
Hmm, maybe it's not decrypting in-place? This used to work without querying the trailer size from the context.
It does encrypt/decrypt in place, however as far as I understand it in win32 data and trailer are separate buffers while gss_wrap/gss_unwrap operate on a continuous buffer, and using wrong trailer size creates a hole between data and trailer which breaks gss_wrap/gss_unwrap assumptions.
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #11 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Dmitry Timoshkov from comment #10)
I don't understand why the trailer size depends on the server since we have always depended on a constant trailer size. Is that because of a difference between Samba and AD?
I've tested with Microsoft and Samba servers and both of them use 60 for actual encryped data, and decrypting with 64 abviously doesn't work. In the same time QueryContextAttributesA(SECPKG_ATTR_SIZES) returns 64 for the connection.
I can find references for Windows changing from 12000 max token size to 48000 but not 48256. Where does it come from?
It comes from a test that calls QueryContextAttributesA(SECPKG_ATTR_SIZES) under Windows 10 for the Samba server.
Hmm, maybe it's not decrypting in-place? This used to work without querying the trailer size from the context.
It does encrypt/decrypt in place, however as far as I understand it in win32 data and trailer are separate buffers while gss_wrap/gss_unwrap operate on a continuous buffer, and using wrong trailer size creates a hole between data and trailer which breaks gss_wrap/gss_unwrap assumptions.
Also using wrong trailer size leads to incorrect total buffer length passed to gss_unwrap.
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #12 from Hans Leidekker hans@meelstraat.net --- (In reply to Dmitry Timoshkov from comment #10)
What about Negotiate?
Do you have an idea how to test it? Apparently for a proper test it's necessary to create a connection, and once the connection is set up it's up to a backend (NTLM/Kerberos) to handle it.
Yes, but you'd call QueryContextAttributes() on a Negotiate context handle instead of Kerberos/NTLM. We already have some tests for Negotiate.
(In reply to Hans Leidekker from comment #6)
(In reply to Dmitry Timoshkov from comment #2)
(In reply to Hans Leidekker from comment #1)
SSF is used by ldap_int_sasl_bind() to determine if the SASL security layer should be used at all. This page documents it as representing the key size for values > 1:
https://docs.oracle.com/cd/E19120-01/open.solaris/819-2145/sasl.intro-44/ index.html
libldap simply checks for a not zero ssf value: https://github.com/openldap/openldap/blob/master/libraries/libldap/cyrus. c#L745
That's an implementation detail we shouldn't rely on.
Why? Since libldap is now part of wldap32 and GSSAPI SASL pluging is also part of libldap now it's part of the implementation detail we can surely rely on.
We include it Wine but it's still code from an external project that we want to update when necessary. I'd rather avoid depending on how the value is used. Also note that the session key attribute was specifically added to GSSAPI to be compatible with SSPI.
I don't understand why the trailer size depends on the server since we have always depended on a constant trailer size. Is that because of a difference between Samba and AD?
I've tested with Microsoft and Samba servers and both of them use 60 for actual encryped data, and decrypting with 64 abviously doesn't work. In the same time QueryContextAttributesA(SECPKG_ATTR_SIZES) returns 64 for the connection.
I can find references for Windows changing from 12000 max token size to 48000 but not 48256. Where does it come from?
Found it, max token size is 48256 for Negotiate and 48000 for Kerberos.
It comes from a test that calls QueryContextAttributesA(SECPKG_ATTR_SIZES) under Windows 10 for the Samba server.
Hmm, maybe it's not decrypting in-place? This used to work without querying the trailer size from the context.
It does encrypt/decrypt in place, however as far as I understand it in win32 data and trailer are separate buffers while gss_wrap/gss_unwrap operate on a continuous buffer, and using wrong trailer size creates a hole between data and trailer which breaks gss_wrap/gss_unwrap assumptions.
The _iov variants should be compatible with win32 and I'm pretty sure this worked before. I'd like to figure out why it doesn't work anymore.
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #13 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Hans Leidekker from comment #12)
It comes from a test that calls QueryContextAttributesA(SECPKG_ATTR_SIZES) under Windows 10 for the Samba server.
Hmm, maybe it's not decrypting in-place? This used to work without querying the trailer size from the context.
It does encrypt/decrypt in place, however as far as I understand it in win32 data and trailer are separate buffers while gss_wrap/gss_unwrap operate on a continuous buffer, and using wrong trailer size creates a hole between data and trailer which breaks gss_wrap/gss_unwrap assumptions.
The _iov variants should be compatible with win32 and I'm pretty sure this worked before. I'd like to figure out why it doesn't work anymore.
As I can see iov variants are used only for DCE style contexts, and that's not the case for the GSSAPI plugin.
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #14 from Hans Leidekker hans@meelstraat.net --- (In reply to Dmitry Timoshkov from comment #13)
(In reply to Hans Leidekker from comment #12)
It comes from a test that calls QueryContextAttributesA(SECPKG_ATTR_SIZES) under Windows 10 for the Samba server.
Hmm, maybe it's not decrypting in-place? This used to work without querying the trailer size from the context.
It does encrypt/decrypt in place, however as far as I understand it in win32 data and trailer are separate buffers while gss_wrap/gss_unwrap operate on a continuous buffer, and using wrong trailer size creates a hole between data and trailer which breaks gss_wrap/gss_unwrap assumptions.
The _iov variants should be compatible with win32 and I'm pretty sure this worked before. I'd like to figure out why it doesn't work anymore.
As I can see iov variants are used only for DCE style contexts, and that's not the case for the GSSAPI plugin.
Right, previously we'd use the Unix LDAP library which links to SASL which in turn links to GSSAPI. I'll check SASL to see how it uses GSSAPI.
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #15 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Hans Leidekker from comment #14)
(In reply to Dmitry Timoshkov from comment #13)
(In reply to Hans Leidekker from comment #12)
It comes from a test that calls QueryContextAttributesA(SECPKG_ATTR_SIZES) under Windows 10 for the Samba server.
Hmm, maybe it's not decrypting in-place? This used to work without querying the trailer size from the context.
It does encrypt/decrypt in place, however as far as I understand it in win32 data and trailer are separate buffers while gss_wrap/gss_unwrap operate on a continuous buffer, and using wrong trailer size creates a hole between data and trailer which breaks gss_wrap/gss_unwrap assumptions.
The _iov variants should be compatible with win32 and I'm pretty sure this worked before. I'd like to figure out why it doesn't work anymore.
As I can see iov variants are used only for DCE style contexts, and that's not the case for the GSSAPI plugin.
Right, previously we'd use the Unix LDAP library which links to SASL which in turn links to GSSAPI. I'll check SASL to see how it uses GSSAPI.
Just in case it could be useful: when working on the attached patchset for the testing purposes and better understanding how native SASL GSSAPI plugin works I created a linux test program that connects to the test server using ldap_sasl_interactive_bind_s() and calls ldap_search_ext_s(). Then I statically linked this test program with libldap and libsasl2, and experimented with the plugin. Sources that were used in the experiments I listed in the first comment.
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #16 from Dmitry Timoshkov dmitry@baikal.ru --- Created attachment 75039 --> https://bugs.winehq.org/attachment.cgi?id=75039 patch v2
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #17 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Hans Leidekker from comment #1)
I can find references for Windows changing from 12000 max token size to 48000 but not 48256. Where does it come from?
Also note that your changes to sasl_decode() and sasl_encode() break NTLM.
I've attached new version of the patch that should address your concerns. Hans, does it look better for you?
https://bugs.winehq.org/show_bug.cgi?id=55304
Fabian Maurer dark.shadow4@web.de changed:
What |Removed |Added ---------------------------------------------------------------------------- CC| |dark.shadow4@web.de
--- Comment #18 from Fabian Maurer dark.shadow4@web.de --- Any news on this?
https://bugs.winehq.org/show_bug.cgi?id=55304
--- Comment #19 from Dmitry Timoshkov dmitry@baikal.ru --- (In reply to Fabian Maurer from comment #18)
Any news on this?
Nothing has changed, LDAP over a Kerberos connection is still broken.