Directory Services

How a Windows Sockets Service Authenticates a Client

When a client connects to the Windows Sockets service, the service begins its operations for the mutual authentication sequence, which is shown in the following code examples.

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 then 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 succeeded.

GenServerContext calls the following functions from an SSPI security package:

The following code example uses the "negotiate" package from the Secur32.dll library of security packages.

/***************************************************************/
//   DoAuthentication routine for the service
//
//   Manages the service's authentication communication 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;

if(s==INVALID_SOCKET)
{
	return(FALSE);
}
 
// Receive authentication data 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 data 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 = 0;
PAUTH_SEQ		pAS = null;

if((pIn==NULL && cbIn>0) || (pOut==NULL) || (pcbOut==NULL) || (pfDone==NULL))
{
	return(FALSE);
}
 
// Get a structure that contains 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;
}