Platform SDK: Active Directory, ADSI, and Directory Services |
When a client connects to the Windows Sockets service, the service begins its side of the mutual authentication sequence, which is shown in the following code samples.
The DoAuthentication routine uses the socket handle to receive the first authentication packet from the client. The client buffer is passed to the GenServerContext routine, which, in turn, passes the buffer to the SSPI security package for authentication. DoAuthentication then sends the security package output back to the client. This loop is repeated until the authentication fails or GenServerContext sets a flag indicating the authentication was successful.
GenServerContext calls the following functions from an SSPI security package.
This sample uses the "negotiate" package from the secur32.dll library of security packages.
/***************************************************************/ // DoAuthentication routine for the service // // Manages the service's authentication conversation with the client // using the supplied socket handle. // // Returns TRUE if the mutual authentication is successful. // Otherwise, it returns FALSE. // /***************************************************************/ BOOL DoAuthentication (SOCKET s) { DWORD cbIn, cbOut; BOOL done = FALSE; // Receive authentication information from the client and pass // it to the security package. Send the package's output back // to the client. Repeat until done. do { if (!ReceiveMsg (s, g_pInBuf, g_cbMaxMessage, &cbIn)) return(FALSE); cbOut = g_cbMaxMessage; if (!GenServerContext (s, g_pInBuf, cbIn, g_pOutBuf, &cbOut, &done)) return(FALSE); if (!SendMsg (s, g_pOutBuf, cbOut)) return(FALSE); } while(!done); return(TRUE); } /***************************************************************/ // GenServerContext routine // // Handles the service's interactions with the security package. // Takes an input buffer coming from the client and generates a // buffer of information to send back to the client. Also returns // an indication when the authentication is complete. // // Returns TRUE if the mutual authentication is successful. // Otherwise, it returns FALSE. // /***************************************************************/ BOOL GenServerContext ( DWORD dwKey, BYTE *pIn, DWORD cbIn, BYTE *pOut, DWORD *pcbOut, BOOL *pfDone) { SECURITY_STATUS ssStatus; TimeStamp Lifetime; SecBufferDesc OutBuffDesc; SecBuffer OutSecBuff; SecBufferDesc InBuffDesc; SecBuffer InSecBuff; ULONG ContextAttributes; PAUTH_SEQ pAS; // Get structure containing the state of the authentication sequence. if (!GetEntry (dwKey, (PVOID*) &pAS)) return(FALSE); if (pAS->_fNewConversation) { ssStatus = g_pFuncs->AcquireCredentialsHandle ( NULL, // principal PACKAGE_NAME, SECPKG_CRED_INBOUND, NULL, // LOGON id NULL, // authentication data NULL, // get key function NULL, // get key argument &pAS->_hcred, &Lifetime ); if (SEC_SUCCESS (ssStatus)) pAS->_fHaveCredHandle = TRUE; else { fprintf (stderr, "AcquireCredentialsHandle failed: %u\n", ssStatus); return(FALSE); } } // Prepare the output buffer. OutBuffDesc.ulVersion = 0; OutBuffDesc.cBuffers = 1; OutBuffDesc.pBuffers = &OutSecBuff; OutSecBuff.cbBuffer = *pcbOut; OutSecBuff.BufferType = SECBUFFER_TOKEN; OutSecBuff.pvBuffer = pOut; // Prepare the input buffer. InBuffDesc.ulVersion = 0; InBuffDesc.cBuffers = 1; InBuffDesc.pBuffers = &InSecBuff; InSecBuff.cbBuffer = cbIn; InSecBuff.BufferType = SECBUFFER_TOKEN; InSecBuff.pvBuffer = pIn; ssStatus = g_pFuncs->AcceptSecurityContext ( &pAS->_hcred, pAS->_fNewConversation ? NULL : &pAS->_hctxt, &InBuffDesc, ASC_REQ_MUTUAL_AUTH, // context requirements SECURITY_NATIVE_DREP, &pAS->_hctxt, &OutBuffDesc, &ContextAttributes, &Lifetime ); if (!SEC_SUCCESS (ssStatus)) { fprintf (stderr, "AcceptSecurityContext failed: %u\n", ssStatus); return FALSE; } if (!(ContextAttributes && ASC_RET_MUTUAL_AUTH)) _tprintf(TEXT("Mutual Auth not set in returned context.\n")); pAS->_fHaveCtxtHandle = TRUE; // Complete the authentication token -- if necessary. if ((SEC_I_COMPLETE_NEEDED == ssStatus) || (SEC_I_COMPLETE_AND_CONTINUE == ssStatus)) { if (g_pFuncs->CompleteAuthToken) { ssStatus = g_pFuncs->CompleteAuthToken (&pAS->_hctxt, &OutBuffDesc); if (!SEC_SUCCESS(ssStatus)) { fprintf (stderr, "complete failed: %u\n", ssStatus); return FALSE; } } else { fprintf (stderr, "Complete not supported.\n"); return FALSE; } } *pcbOut = OutSecBuff.cbBuffer; if (pAS->_fNewConversation) pAS->_fNewConversation = FALSE; *pfDone = !((SEC_I_CONTINUE_NEEDED == ssStatus) || (SEC_I_COMPLETE_AND_CONTINUE == ssStatus)); return TRUE; }