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
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
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);
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);
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.
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);
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 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);
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.
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);
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;
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);
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.
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.
Thank you ! -Grigor
ldap_sasl_bind_s
. OpenLDAP uses Cyrus SASL for all SASL operations...or are you using the Windows-native LDAP metthods? – Michael-OGSSAPI
andGSS-SPNEGO
through SSPI. If you plan to pass an alternative credential, use theberval
structure. Assign the SSPI cred handle to the value of theberval
struct and the length withsizeof
. Should probably be 8 bytes. First try to implement auth only w/o conf and int. – Michael-O