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 function, 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:
- AcquireCredentialsHandle extracts the service credentials from the service security context that was established when the service started.
- AcceptSecurityContext attempts to perform the mutual authentication using the service credentials and the authentication data received from the client. To request mutual authentication, the AcceptSecurityContext call must specify the ASC_REQ_MUTUAL_AUTH flag.
- CompleteAuthToken is called, if necessary, to complete the authentication operation.
The following code example uses the negotiate package from the Secur32.dll library of security packages.
/***************************************************************/
// DoAuthentication routine for the service
//
// Manages the service authentication communication with the client
// using the supplied socket handle.
//
// Returns TRUE if the mutual authentication succeeds.
// 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 output back
// to the client. Repeat until complete.
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 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;
}
Feedback
https://aka.ms/ContentUserFeedback.
Coming soon: Throughout 2024 we will be phasing out GitHub Issues as the feedback mechanism for content and replacing it with a new feedback system. For more information see:Submit and view feedback for