Я пытаюсь реализовать привязку SASL через GSSAPI, используя учетные данные kerberos с функцией ldap_sasl_bind_s. Я следую за шагами, описанными в ldap_sasl_bind_s (GSSAPI) — что должно быть предусмотрено в структуре BERVAL для учетных данных цепь
Я получаю ожидаемые возвращаемые значения для всех вызовов, описанных в упомянутой цепочке, до последнего (третьего) вызова ldap_sasl_bind_s, который завершается ошибкой LDAP_INVALID_CREDENTIALS. Также я вижу следующую ошибку в окне просмотра событий Windows
Error value:
80090308: LdapErr: DSID-0C0904D1, comment: AcceptSecurityContext error, data 5, v1771
Обратите внимание, что у меня есть два приложения, давайте назовем их клиентом и сервером, клиент запускается под учетной записью активного домена, серверное приложение получает учетные данные от клиента и пытается привязаться к 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);
Я использую один из spn-ов, доступных в моей настройке активного каталога. Этот вызов возвращает 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 и заполняет servresp2 токеном длиной 32 байта, который затем передается клиенту. Последнее сообщение об ошибке на сервере: LDAP_SASL_BIND_IN_PROGRESS.
Я перехожу к DecryptMessage NewContext2 (который был получен при вызове InitSecContext) в качестве первого аргумента. BuffDesc, переданный в качестве второго аргумента в DecryptMessage, содержит указатель на два объекта SecBuffer, SecBuffer [0] имеет тип SECBUFFER_STREAM и содержит ответ сервера (токен, сгенерированный во время второго вызова ldap_sasl_bind_s), а SecBuffer [1] имеет тип SECBUFFER_Dessffer Decer 1 Decair_Dessffer Decage2Decffer Decage_Dessffer Decage_Dessffer Decage. ] заполняется некоторым токеном (также изменяется его размер, поэтому я думаю, что он содержит расшифрованное сообщение). Третий аргумент DecryptMessage равен 0, а последний заполняется значением SECQOP_WRAP_NO_ENCRYPT после расшифровки сообщения. Вот звонок
ULONG ulQop;
res = DecryptMessage( &NewContext2, &BuffDesc, 0, &ulQop);
В буфере SECBUFFER_DATA, переданном в DecryptMessage, я получаю токен длиной 4 байта (который, похоже, является последними 4 байтами входного буфера SECBUFFER_STREAM). Первый байт «дешифрованного сообщения (SecBuff [1] .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;
Я строю входной объект SecBufferDesc для EncryptMessage, используя
три буфера, первый имеет тип 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, однако не смог справиться с этой ошибкой.
Буду признателен за любую помощь, не могли бы вы помочь мне разобраться в этом вопросе или предоставить пример рабочего кода, чтобы я мог взглянуть.
Спасибо !
-Grigor
Задача ещё не решена.