我正在尝试使用 Kerberos 凭证和 ldap_sasl_bind_s() 函数通过 GSSAPI 实现 SASL 绑定。我按照 ldap_sasl_bind_s(GSSAPI) - 凭证 BERVAL 结构中应提供什么 链中描述的步骤进行操作。
我获得了上述链中描述的所有调用的预期返回值,直到最后一次(第三次)调用 ldap_sasl_bind_s(),该调用因 LDAP_INVALID_CREDENTIALS 错误而失败。我还看到 Windows Event Viewer 中出现以下错误:
Error value:
80090308: LdapErr: DSID-0C0904D1, comment: AcceptSecurityContext error, data 5, v1771
请注意我有两份申请。让我们称它们为客户端和服务器;客户端正在某个 Active Directory 域帐户下运行,服务器应用程序从客户端接收凭据并尝试使用客户端提供的令牌绑定到 LDAP。
这是我所做的步骤。客户来电
int res = AcquireCredentialsHandle(NULL, "Kerberos" , SECPKG_CRED_BOTH,NULL, NULL, NULL, NULL, &credhandle1, &expry1);
填写credhandle1后,我再次将其传递给客户端的InitializeSecurityContext的第一次调用:
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);
我使用 Active Directory 设置中可用的 spn-s 之一。此调用返回 SEC_I_CONTINUE_NEEDED,并填充 sec_buffer_desc1,然后将其传递到我的服务器应用程序以使用构造的令牌调用 ldap_sasl_bind_s()。
第一次调用 ldap_sasl_bind_s() 返回 LDAP_SUCCESS,并填充
struct berval *servresp
。电话如下:
rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred1, NULL, NULL, &servresp);
servresp
中的令牌被传递到客户端应用程序,该应用程序执行第二次InitializeSecurityContext调用,如下所示
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() 的服务器
rc1 = ldap_sasl_bind_s(ld1, "", "GSSAPI", &cred2, NULL, NULL, &servresp2);
此调用再次返回 LDAP_SUCCESS 并用 32 字节长的令牌填充 servresp2,然后将其传递给客户端。服务器中的最后一个错误消息是 LDAP_SASL_BIND_IN_PROGRESS。
我传递给 DecryptMessage NewContext2 (在 InitSecContext 调用中收到)作为第一个参数。作为第二个参数传递给 DecryptMessage 的 BuffDesc 包含指向两个 SecBuffer 对象的指针,SecBuffer[0] 的类型为 SECBUFFER_STREAM 并包含服务器响应(第二次调用 ldap_sasl_bind_s 生成的令牌),SecBuffer1 的类型为 SECBUFFER_DATA。在 DecryptMessage 调用 SecBuffer1 后 正在被一些令牌填充(它的大小也正在改变,所以我认为它包含解密的消息)。 DecryptMessage 的第三个参数为 0,最后一个参数在解密消息后由 SECQOP_WRAP_NO_ENCRYPT 值填充。电话如下:
ULONG ulQop;
res = DecryptMessage( &NewContext2, &BuffDesc, 0, &ulQop);
在传递给 DecryptMessage 的 SECBUFFER_DATA 缓冲区中,我收到一个四字节长的令牌(这似乎是输入 SECBUFFER_STREAM 缓冲区的最后四个字节)。 “解密消息(SecBuff1.pvBuffer)”的第一个字节是7,然后我执行以下操作
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:
err = EncryptMessage(&NewContext2,fQOP,&inSecBufDescSecond, 0);
返回 SEC_E_OK,并在缓冲区中生成 28 字节长的令牌,类型为 SECBUFFER_TOKEN。然后,将此输出令牌传递到我的服务器应用程序,该应用程序使用此令牌作为客户端凭据调用 ldap_sasl_bind_s,并因无效凭据错误而失败。
我查看了帖子中提到的 RFC,并尝试找到任何具有 SASL 和 kerberos 凭据的工作示例。但是,我无法处理这个错误。
我怎样才能弄清这个问题的真相?或者一些工作代码示例可能是什么?
我遇到了完全相同的问题,我想我找到了解决方案:
您在第三次 ldap_sasl_bind_s 调用中发送的消息应该是提供给 EncryptMessage 的所有三个缓冲区的串联(按 TOKEN、DATA、PADDING 的顺序)
当我这样做时,它起作用了!