C语言 如何在WinLDAP中使用ldap_sasl_bind?

eanckbw9  于 2024-01-06  发布在  其他
关注(0)|答案(2)|浏览(260)

我目前使用ldap_bind_s绑定到我的C应用程序中的SEC_WINNT_AUTH_IDENTITY结构的服务器,但该函数被标记为已弃用。因此,我想将其更改为ldap_sasl_bind_s函数。

  1. int main(void) {
  2. LDAP *ld;
  3. int rc = 0;
  4. char *binddn = "cn=admin,dc=local";
  5. const int version = LDAP_VERSION3;
  6. SEC_WINNT_AUTH_IDENTITY wincreds;
  7. struct berval saslcred;
  8. wincreds.User = "admin";
  9. wincreds.UserLength = 5;
  10. wincreds.Password = "secret";
  11. wincreds.PasswordLength = 6;
  12. wincreds.Domain = NULL;
  13. wincreds.DomainLength = 0;
  14. wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
  15. ld = ldap_initA("localhost", LDAP_PORT);
  16. ldap_set_optionA(ld, LDAP_OPT_PROTOCOL_VERSION, &version);
  17. rc = ldap_bind_sA(ld, binddn, (PCHAR)&wincreds, LDAP_AUTH_DIGEST);
  18. printf("0x%x\n", rc); // It's OK (0x0)
  19. ldap_unbind(ld);
  20. saslcred.bv_val = "secret";
  21. saslcred.bv_len = 6;
  22. rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, NULL);
  23. printf("0x%x\n", rc); // Returns with 0x59
  24. ldap_unbind(ld)
  25. return 0;
  26. }

字符串
ldap_sasl_bind_s返回LDAP_PARAM_ERROR代码。显然,上面的函数参数是错误的,但是我找不到一个使用winldap和SASL绑定的工作示例代码。
我将非常感谢一些指导,如何使这段代码工作。

sqyvllje

sqyvllje1#

ldap_sasl_bind_sA的最后一个参数不能为NULL。它必须指向函数可以放置服务器响应(struct berval*)的位置。

  1. ...
  2. struct berval* serverResponse = NULL;
  3. rc = ldap_sasl_bind_sA(ld, binddn, "DIGEST-MD5", &saslcred, NULL, NULL, &serverResponse);
  4. ...

字符串

t5zmwmid

t5zmwmid2#

所以最后,经过过去两周的研究和调试,我成功地编写了一个使用 DIGEST-MD5 身份验证和WinLDAP的 ldap_sasl_bind_s 函数的工作示例代码。对应的RFC,这个答案和官方的SSPI documentation给了我很多帮助。
我遇到的一些问题:

  • 不管文档中对ldap_connect函数的描述如何:如果您想使用ldap_sasl_bind_s函数,首先调用它不仅仅是一种“良好的编程实践”,这是必要的。如果没有它,ldap_sasl_bind_s 将返回 LDAP_SERVER_DOWN(0x 51)错误代码。
  • 有效的 pszTargetName(userst-uri)参数对于InitializeSecurityContext函数避免无效令牌错误至关重要。

我希望它能帮助其他人花更少的时间来弄清楚如何在WinLDAP中使用SASL绑定机制。

  1. #include <stdio.h>
  2. #include <windows.h>
  3. #include <winldap.h>
  4. #define SECURITY_WIN32 1
  5. #include <security.h>
  6. #include <sspi.h>
  7. int _tmain(int argc, _TCHAR* argv[]) {
  8. LDAP *ld;
  9. int rc = 0;
  10. const int version = LDAP_VERSION3;
  11. SEC_WINNT_AUTH_IDENTITY wincreds;
  12. struct berval *servresp = NULL;
  13. SECURITY_STATUS res;
  14. CredHandle credhandle;
  15. CtxtHandle newhandle;
  16. SecBufferDesc OutBuffDesc;
  17. SecBuffer OutSecBuff;
  18. SecBufferDesc InBuffDesc;
  19. SecBuffer InSecBuff;
  20. unsigned long contextattr;
  21. ZeroMemory(&wincreds, sizeof(wincreds));
  22. // Set credential information
  23. wincreds.User = (unsigned short *)L"root";
  24. wincreds.UserLength = 4;
  25. wincreds.Password = (unsigned short *)L"p@ssword";
  26. wincreds.PasswordLength = 8;
  27. wincreds.Domain = NULL;
  28. wincreds.DomainLength = 0;
  29. wincreds.Flags = SEC_WINNT_AUTH_IDENTITY_UNICODE;
  30. res = AcquireCredentialsHandle(NULL, L"WDigest", SECPKG_CRED_OUTBOUND,
  31. NULL, &wincreds, NULL, NULL, &credhandle, NULL);
  32. // Buffer for the output token.
  33. OutBuffDesc.ulVersion = 0;
  34. OutBuffDesc.cBuffers = 1;
  35. OutBuffDesc.pBuffers = &OutSecBuff;
  36. OutSecBuff.BufferType = SECBUFFER_TOKEN;
  37. OutSecBuff.pvBuffer = NULL;
  38. ld = ldap_init(L"localhost", LDAP_PORT);
  39. rc = ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, (void*)&version);
  40. rc = ldap_connect(ld, NULL); // Need to connect before SASL bind!
  41. do {
  42. if (servresp != NULL) {
  43. InBuffDesc.ulVersion = 0;
  44. InBuffDesc.cBuffers = 1;
  45. InBuffDesc.pBuffers = &InSecBuff;
  46. /* The digest-challenge will be passed as an input buffer to
  47. InitializeSecurityContext function */
  48. InSecBuff.cbBuffer = servresp->bv_len;
  49. InSecBuff.BufferType = SECBUFFER_TOKEN;
  50. InSecBuff.pvBuffer = servresp->bv_val;
  51. /* The OutBuffDesc will contain the digest-response. */
  52. res = InitializeSecurityContext(&credhandle, &newhandle, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH | ISC_REQ_ALLOCATE_MEMORY,
  53. 0, 0, &InBuffDesc, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
  54. }
  55. else {
  56. res = InitializeSecurityContext(&credhandle, NULL, L"ldap/localhost", ISC_REQ_MUTUAL_AUTH, 0, 0, NULL, 0, &newhandle, &OutBuffDesc, &contextattr, NULL);
  57. }
  58. switch (res) {
  59. case SEC_I_COMPLETE_NEEDED:
  60. case SEC_I_COMPLETE_AND_CONTINUE:
  61. case SEC_E_OK:
  62. case SEC_I_CONTINUE_NEEDED:
  63. break;
  64. case SEC_E_INVALID_HANDLE:
  65. return -2;
  66. case SEC_E_INVALID_TOKEN:
  67. return -1;
  68. default:
  69. break;
  70. }
  71. struct berval cred;
  72. cred.bv_len = OutSecBuff.cbBuffer;
  73. /* The digest-response will be passed to the server
  74. as credential after the second (loop)run. */
  75. cred.bv_val = (char *)OutSecBuff.pvBuffer;
  76. // The servresp will contain the digest-challange after the first call.
  77. rc = ldap_sasl_bind_s(ld, L"", L"DIGEST-MD5", &cred, NULL, NULL, &servresp);
  78. ldap_get_option(ld, LDAP_OPT_ERROR_NUMBER, &res)
  79. } while (res == LDAP_SASL_BIND_IN_PROGRESS);
  80. if (rc != LDAP_SUCCESS) {
  81. printf("Bind failed with 0x%x\n", rc);
  82. } else {
  83. printf("Bind succeeded\n");
  84. }
  85. return 0;
  86. }

字符串

展开查看全部

相关问题