SASL bind over GSSAPI using kerberos credentials with ldap_sasl_bind_s function(SASL 使用带有 ldap_sasl_bind_s 函数的 kerberos 凭证通过 GSSAPI 绑定)
问题描述
我正在尝试使用带有 ldap_sasl_bind_s 函数的 kerberos 凭据通过 GSSAPI 实现 SASL 绑定.我遵循 ldap_sasl_bind_s(GSSAPI) - 凭证BERVAL结构链中应提供什么
I am trying to implement SASL bind over GSSAPI using kerberos credentials with ldap_sasl_bind_s function. I follow to the steps described in ldap_sasl_bind_s(GSSAPI) - What should be provided in the credentials BERVAL structure chain
我得到了上述链中描述的所有调用的预期返回值,直到对 ldap_sasl_bind_s 的最后(第三次)调用失败并出现 LDAP_INVALID_CREDENTIALS 错误.我还看到 Windows 事件查看器中出现以下错误
I get expected return values for all calls described in the mentioned chain, until the last(third) call to ldap_sasl_bind_s, which fails with LDAP_INVALID_CREDENTIALS error. Also I see the following error occurs in the windows event viewer
Error value:
80090308: LdapErr: DSID-0C0904D1, comment: AcceptSecurityContext error, data 5, v1771
请注意,我有两个应用程序,我们称它们为客户端和服务器,客户端在某个 Active 域帐户下运行,服务器应用程序从客户端接收凭据并尝试使用客户端提供的令牌绑定到 ldap.这是我做的步骤.客户来电
Please note I have two applications, let us call them client and server, client is being run under some Active domain account,server application receives credentials from the client and tries to bind to ldap using tokens provided by the client. here are the steps I do. Client calls
int res = AcquireCredentialsHandle(NULL, "Kerberos" , SECPKG_CRED_BOTH,NULL, NULL, NULL, NULL, &credhandle1, &expry1);
填充 credhandle1 后,我再次将其传递给客户端的 InitializeSecurityContext 的第一次调用
After filling credhandle1 I pass it to the first call of InitializeSecurityContext again in the client side
res = InitializeSecurityContext(&credhandle1,NULL,(SEC_CHAR*)(&spn1[0]),ISC_REQ_INTEGRITY|ISC_REQ_MUTUAL_AUTH|ISC_REQ_SEQUENCE_DETECT|ISC_REQ_CONFIDENTIALITY|ISC_REQ_DELEGATE,0,SECURITY_NATIVE_DREP ,NULL,0,&NewContext2,&sec_buffer_desc1,&contextattr2,&expry2);
我使用活动目录设置中可用的 spn-s 之一.此调用返回 SEC_I_CONTINUE_NEEDED,并填充 sec_buffer_desc1,然后将其传递给我的服务器应用程序以使用构造的令牌调用 ldap_sasl_bind_s.
I use one of the spn-s available in my active directory setup. This call returns SEC_I_CONTINUE_NEEDED, and fills sec_buffer_desc1 which is then passed to my server application to call ldap_sasl_bind_s with constructed token.
ldap_sasl_bind_s的第一次调用返回LDAP_SUCCESS,并填充struct berval *servresp,这里是调用
First call of ldap_sasl_bind_s returns LDAP_SUCCESS, and fills struct berval *servresp, here is the call
rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred1, NULL, NULL, &servresp);
将 servresp 中的令牌传递给客户端应用程序,客户端应用程序执行 InitializeSecurityContext 的第二次调用,如下所示
The token in servresp is passed to the client application which does the second call of InitializeSecurityContext as follows
res = InitializeSecurityContext(&credhandle1, &NewContext2, (SEC_CHAR*)(&spn1[0]),ISC_REQ_INTEGRITY|ISC_REQ_MUTUAL_AUTH|ISC_REQ_SEQUENCE_DETECT|ISC_REQ_CONFIDENTIALITY|ISC_REQ_DELEGATE,0, 0, &InBuffDesc3, 0, &NewContext3, &sec_buffer_desc3, &contextattr3, &expry3);
InBuffDesc3 包含从服务器返回的凭据.此调用返回 SEC_E_OK,并在 sec_buffer_desc3 中产生空输出令牌,这个令牌被传递给第二次调用 ldap_sasl_bind_s 的服务器
InBuffDesc3 contains credentials returned from the server. This call returns SEC_E_OK, and produced empty output token in sec_buffer_desc3, This token is passed to the server which calls ldap_sasl_bind_s second time
rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred2, NULL, NULL, &servresp2);
此调用再次返回 LDAP_SUCCESS 并用 32 字节长的令牌填充 servresp2,然后将其传递给客户端.服务器中的最后一条错误消息是 LDAP_SASL_BIND_IN_PROGRESS.
This call again returns LDAP_SUCCESS and fills servresp2 with 32 byte long token which is then passed to the client. Last error message in the server is LDAP_SASL_BIND_IN_PROGRESS.
我将 DecryptMessage NewContext2(在 InitSecContext 调用中收到)作为第一个参数传递.作为第二个参数传递给 DecryptMessage 的 BuffDesc 包含指向两个 SecBuffer 对象的指针,SecBuffer[0] 具有类型 SECBUFFER_STREAM 并包含服务器响应(由第二次调用 ldap_sasl_bind_s 生成的令牌),SecBuffer[1] 具有类型 SECBUFFER_DATA.DecryptMessage 调用 SecBuffer[1]] 被一些令牌填充(它的大小也在改变,所以我认为它包含解密的消息).DecryptMessage 的第三个参数为 0,最后一个参数在解密消息后由 SECQOP_WRAP_NO_ENCRYPT 值填充.这是电话
I pass to DecryptMessage NewContext2 (that was received in InitSecContext call) as a first argument. BuffDesc passed as second argument to DecryptMessage contains pointer to two SecBuffer objects, SecBuffer[0] has type SECBUFFER_STREAM and contains server response (token generated by the second call of ldap_sasl_bind_s) and SecBuffer[1] has type SECBUFFER_DATA.After DecryptMessage call SecBuffer[1] is being filled by some token(also it's size is being changed, so I think that it contains decrypted message). Third argument of DecryptMessage is 0 and the last one is being filled by SECQOP_WRAP_NO_ENCRYPT value after Decrypting the message. Here is the call
ULONG ulQop;
res = DecryptMessage( &NewContext2, &BuffDesc, 0, &ulQop);
在传递给 DecryptMessage 的 SECBUFFER_DATA 缓冲区中,我收到 4 个字节长的令牌(这似乎是输入 SECBUFFER_STREAM 缓冲区的最后 4 个字节).解密后的消息(SecBuff[1].pvBuffer)"的第一个字节是7,那么我做下面的
In SECBUFFER_DATA buffer passed to DecryptMessage I receive 4 bytes long token (which seems to be the last 4 bytes of input SECBUFFER_STREAM buffer). The first byte of "decrypted message(SecBuff[1].pvBuffer)" is 7, then I do the following
unsigned char * ptr = (unsigned char *)SecBuff[1].pvBuffer;
int maxsize = (ptr[1]<<16) | (ptr[2]<<8)| (ptr[3]);
ptr = (unsigned char *) malloc(4);
ptr[0]= 4;
ptr[1]= maxsize>>16;
ptr[2]= maxsize>>8;
ptr[3]= maxsize;
我正在使用 EncryptMessage 构建输入 SecBufferDesc 对象三个缓冲区,第一个具有 SECBUFFER_TOKEN 类型,它在 EncryptMEssage 调用之后填充(所以我认为它在此调用之后包含加密消息),第二个具有 SECBUFFER_DATA 类型并包含我在上面构造的 ptr,第三个缓冲区类型为 SECBUFFER_PADDING.我调用 EncryptMessage 如下
I am constructing the input SecBufferDesc object for EncryptMessage using three buffers, first one has type SECBUFFER_TOKEN which is filled after EncryptMEssage call(so I think it contains encrypted message after this call), the second one has SECBUFFER_DATA type and contains ptr I have constructed above, and the third buffer of type SECBUFFER_PADDING. I call EncryptMessage as follows
err = EncryptMessage(&NewContext2,fQOP,&inSecBufDescSecond, 0);
返回 SEC_E_OK,并在缓冲区中生成 28 字节长的令牌,类型为 SECBUFFER_TOKEN,然后将此输出令牌传递给我的服务器应用程序,该应用程序使用此令牌作为客户端凭据调用 ldap_sasl_bind_s,并因无效凭据错误而失败.
which returns SEC_E_OK, and produces 28 bytes long token in the buffer with type SECBUFFER_TOKEN, this output token is then passed to my server application which calls ldap_sasl_bind_s with this token as client credentials and fails with invalid credentials error.
我查看了帖子中提到的 RFC 也试图找到任何带有 SASL 和 kerberos 凭据的工作示例,但是无法处理此错误.任何帮助将不胜感激,请您帮我找出这个问题的根源,或者提供一些有效的代码示例,以便我查看.
I looked at RFC mentioned in the post also tried to find any working example with SASL and kerberos credentials, however was not able to deal with this error. Any help will be appreciated, could you please help me to get to the bottom of this issue, or provide some working code example so that I can take a look.
谢谢!-格里高尔
推荐答案
我遇到了完全相同的问题,我想我找到了解决方案:
I ran into the exact same problem, and I think I found the solution:
您在第三个 ldap_sasl_bind_s 调用中发送的消息应该是提供给 EncryptMessage 的所有三个缓冲区的串联(按 TOKEN、DATA、PADDING 的顺序)
The message you send in the third ldap_sasl_bind_s call should be the concatenation of all three buffers given to EncryptMessage (in the order TOKEN, DATA, PADDING)
当我这样做时,它起作用了!
When I do that, it works!
这篇关于SASL 使用带有 ldap_sasl_bind_s 函数的 kerberos 凭证通过 GSSAPI 绑定的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:SASL 使用带有 ldap_sasl_bind_s 函数的 kerberos 凭证通过 GSSAPI 绑定
基础教程推荐
- 从 std::cin 读取密码 2021-01-01
- 为什么语句不能出现在命名空间范围内? 2021-01-01
- 管理共享内存应该分配多少内存?(助推) 2022-12-07
- 如何“在 Finder 中显示"或“在资源管理器中显 2021-01-01
- Windows Media Foundation 录制音频 2021-01-01
- 在 C++ 中循环遍历所有 Lua 全局变量 2021-01-01
- 如何在不破坏 vtbl 的情况下做相当于 memset(this, ...) 的操作? 2022-01-01
- 使用从字符串中提取的参数调用函数 2022-01-01
- 为 C/C++ 中的项目的 makefile 生成依赖项 2022-01-01
- 如何使图像调整大小以在 Qt 中缩放? 2021-01-01