Platform SDK: Logon Authentication

Using SSPI with a Windows Sockets Server

This sample program works with the client program Using SSPI with a Windows Sockets Client. Both this program and the client program call some identical utility functions that are included in Utility Functions for Windows Sockets Client and Server. This program includes calls to functions in Ws2_32.lib, which must be included among the link libraries.

This program demonstrates the following:

This sample code uses limited error handling.

//--------------------------------------------------------------------
//     Server-side SSPI Windows Sockets program.

#define SEC_SUCCESS(Status) ((Status) >= 0) 
#define SECURITY_WIN32 
// Change the following define statement to use "Kerberos"
// For Windows 2000, it could also be "Negotiate" to choose the best
// possible package available to both client and server.
##define PACKAGE_NAME "NTLM"
#define NT_DLL_NAME "secur32.dll" 
#define TOKEN_SOURCE_NAME       "AuthSamp" 
#define wVerRequested 0x0101
//--------------------------------------------------------------------
//     Include header files

#include <windows.h> 
#include <winsock.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include "comm.h" 
#include "security.h" 
#include "sspi.h" 

//--------------------------------------------------------------------
//      Declare and initialize structures and global variables 

typedef struct _AUTH_SEQ { 
    BOOL _fNewConversation; 
    CredHandle _hcred; 
    BOOL _fHaveCredHandle; 
    BOOL _fHaveCtxtHandle; 
    SecHandle  _hctxt; 
} AUTH_SEQ, *PAUTH_SEQ; 

static PAUTH_SEQ pAS;
static PBYTE g_pInBuf = NULL; 
static PBYTE g_pOutBuf = NULL; 
static DWORD g_cbMaxMessage = 0; 
static unsigned short g_usPort = 2000; 
static HINSTANCE g_hLib; 
static DWORD g_cbMaxToken; 
static PSecurityFunctionTable g_pFuncs; 

//--------------------------------------------------------------------
//     Declare function prototypes

BOOL AcceptAuthSocket (SOCKET *s); 
BOOL CloseAuthSocket(SOCKET s); 
BOOL DoAuthentication(SOCKET s); 
BOOL InitWinsock() ;
BOOL SendMsg(SOCKET s, PBYTE pBuf, DWORD cbBuf) ;
BOOL ReceiveMsg(SOCKET s, PBYTE pBuf, DWORD cbBuf, DWORD *pcbRead) 
BOOL SendBytes(SOCKET s, PBYTE pBuf, DWORD cbBuf) ;
BOOL ReceiveBytes(SOCKET s, PBYTE pBuf, DWORD cbBuf, DWORD *pcbRead) ;
void HandleError(char *s); 
void UseSession(SOCKET s, SecHandle phContext);

//--------------------------------------------------------------------
//     Begin main()
 
void main () 
{ 
SOCKET s; 
WSADATA wsaData; 
 
//--------------------------------------------------------------------
//      Initialize the Windows socket 
 
WSAStartup (wVerRequested, &wsaData); 

if (!(InitPackage (&g_cbMaxMessage)))
{
     HandleError("Security package not initialized.\n");
}

g_pOutBuf = (PBYTE) malloc (g_cbMaxMessage);
g_pInBuf = (PBYTE) malloc (g_cbMaxMessage);

//--------------------------------------------------------------------
//      Make an authenticated connection with client 

if (!(AcceptAuthSocket (&s)))
{
     HandleError("AcceptAuthSocket failed.\n");
}

//--------------------------------------------------------------------
//     Do processing in the SSPI authenticated secure connection

UseSession(s, pAS->hctxt);

//--------------------------------------------------------------------
//      Terminate the session and clean-up. 

if (pAS->_fHaveCredHandle)
{
     g_pFuncs->FreeCredentialHandle (&pAS->_hcred);
}
free (pAS); 
shutdown (s, 2); 
closesocket (s); 
FreeLibrary (g_hLib); 
WSACleanup (); 
free (g_pInBuf); 
free (g_pOutBuf); 
printf("The server-side program ran to completion without error.");
} // end of main 

//--------------------------------------------------------------------
//     Define AcceptAuthSocket.

BOOL AcceptAuthSocket (SOCKET *s) 
{ 
SOCKET sockListen; 
SOCKET sockClient; 
SOCKADDR_IN sin; 
int nRes; 
 
//--------------------------------------------------------------------
//      Create listening socket 
// 
printf("Listening ");

sockListen = socket (PF_INET, SOCK_STREAM, 0); 
if (INVALID_SOCKET == sockListen)  
{ 
     HandleError("Failed to create socket."); 
} 
 
sin.sin_family = AF_INET; 
sin.sin_addr.s_addr = 0; 
sin.sin_port = htons(g_usPort); 
nRes = bind (sockListen, (LPSOCKADDR) &sin, sizeof (sin)); 
if (SOCKET_ERROR == nRes)  
{ 
     HandleError("bind failed: \n"); 
} 

if (SOCKET_ERROR == listen (sockListen, 1))  
{ 
     HandleError("listen failed"); 
}

sockClient = accept (sockListen, NULL, NULL); 
if (INVALID_SOCKET == sockClient)  
{ 
     HandleError("accept failed: "); 
} 
 
closesocket (sockListen); 
 
if (!(InitSession (sockClient)))
{
     HandleError("Session not initalized.\n");
}

if (!(DoAuthentication (sockClient))) 
{
     HandleError("Authentication did not work.");
}

//--------------------------------------------------------------------
//      Set value of *s to the returned socket. 

*s = sockClient; 
return(TRUE); 
} 

//--------------------------------------------------------------------
//      Define DoAuthentication()  
//      Manage the authentication conversation with the client by the 
//      supplied socket handle.    

BOOL DoAuthentication (SOCKET s)
{ 
DWORD cbIn, cbOut; 
BOOL fDone = FALSE;  

while(!fDone);  
{ 
     if (!(ReceiveMsg (
          s, 
          g_pInBuf, 
          g_cbMaxMessage, 
          &cbIn)))
     {
          HandleError("ReceiveMsg failed in DoAuthentication.");
     }
     cbOut = g_cbMaxMessage; 

     if (!(GenServerContext (
          s, 
          g_pInBuf, 
          cbIn, 
          g_pOutBuf, 
          &cbOut, 
          &fDone)))
     {
          HandleError("GenServerContext failed.\n");
     }
    if(!fDone)
    {
         if (!(SendMsg (
              s, 
              g_pOutBuf, 
              cbOut))) 
          {
              HandleError("Message not sent from DoAuthentication.");
           }
     }
}  // end while loop.
return(TRUE); 
} 

//--------------------------------------------------------------------
//      Handle communication with the security package. 

//--------------------------------------------------------------------
//     Define InitPackage()
//     Find, load, and initialize the security package 
//     Return TRUE is successful, otherwise FALSE. 

BOOL InitPackage (DWORD *pcbMaxMessage) 
{ 
FARPROC pInit; 
SECURITY_STATUS ss; 
PSecPkgInfo pkgInfo; 
ULONG cPackages, i;
SecPkgInfo *ppPackageInfo;
 
//--------------------------------------------------------------------
//     Load the SSPI Library
       Load and initialize a security package. 

if(!(g_hLib = LoadLibrary (NT_DLL_NAME)))
{
     HandleError("Could not load the dll."); 
} 

if(!(pInit = GetProcAddress (g_hLib, SECURITY_ENTRYPOINT)))
{
     HandleError("Could not get security initialization routine."); 
} 
 
if(!(g_pFuncs = (PSecurityFunctionTable) pInit ()))
{ 
     HandleError("Could not initialize the security package."); 
} 

//--------------------------------------------------------------------
//      List the available security packages.

ss = g_pFuncs->EnumerateSecurityPackages(
     &cPackages,          
     &ppPackageInfo  );
if( SEC_SUCCESS(ss))
{
     printf("The security packages available are:\n");
     for(i=0;i<cPackages;i++)
     {
          printf("%s \n",ppPackageInfo[i].Name);
     }
}
else
{
     HandleError("Could not list available security packages.");
}

//--------------------------------------------------------------------
//      Query the security package for the maximum token length.. 

ss = g_pFuncs->QuerySecurityPackageInfo (PACKAGE_NAME, &pkgInfo); 
if (!(SEC_SUCCESS(ss)))  
{
     HandleError("Could not query selected package information."); 
} 
 
g_cbMaxToken = pkgInfo->cbMaxToken; 
g_pFuncs->FreeContextBuffer (pkgInfo); 
*pcbMaxMessage = g_cbMaxToken; 
return TRUE; 
} 

//--------------------------------------------------------------------
//     Define GenServerContext()
//    Take an input buffer coming from the client and return a buffer 
//    to be sent to the client. Also returns an indication of whether 
//    or not the context is complete. 
 
BOOL GenServerContext ( 
DWORD dwKey, 
BYTE *pIn, 
DWORD cbIn, 
BYTE *pOut, 
DWORD *pcbOut, 
BOOL *pfDone) 
{ 
SECURITY_STATUS ss; 
TimeStamp Lifetime; 
SecBufferDesc OutBuffDesc; 
SecBuffer OutSecBuff; 
SecBufferDesc InBuffDesc; 
SecBuffer InSecBuff; 
ULONG ContextAttributes; 

if (pAS->_fNewConversation) 
{
     ss = g_pFuncs->AcquireCredentialsHandle ( 
          NULL,              // Use the default principal 
          PACKAGE_NAME, 
          SECPKG_CRED_INBOUND, 
          NULL,              // Use the current LOGON id 
          NULL, 
          NULL, 
          NULL, 
          &pAS->_hcred, 
          &Lifetime );
     if (SEC_SUCCESS (ss))
     { 
          pAS->_fHaveCredHandle = TRUE;  
     } 
     else
     {
           HandleError("AcquireCreds failed."); 
     }
}
//--------------------------------------------------------------------
//      Prepare input and output buffers 

OutBuffDesc.ulVersion = 0; 
OutBuffDesc.cBuffers = 1; 
OutBuffDesc.pBuffers = &OutSecBuff;  

OutSecBuff.cbBuffer = *pcbOut;
OutSecBuff.BufferType = SECBUFFER_TOKEN;
OutSecBuff.pvBuffer = pOut; 

InBuffDesc.ulVersion = 0; 
InBuffDesc.cBuffers = 1; 
InBuffDesc.pBuffers = &InSecBuff; 

InSecBuff.cbBuffer = cbIn; 
InSecBuff.BufferType = SECBUFFER_TOKEN; 
InSecBuff.pvBuffer = pIn; 

ss = g_pFuncs->AcceptSecurityContext ( 
          &pAS->_hcred, 
          pAS->_fNewConversation ? NULL : &pAS->_hctxt, 
          &InBuffDesc, 
          0,
          SECURITY_NATIVE_DREP, 
          &pAS->_hctxt, 
          &OutBuffDesc, 
          &ContextAttributes, 
           &Lifetime 
); 
if (!SEC_SUCCESS (ss))
{
     HandleError("Accept context failed."); 
}
 
pAS->_fHaveCtxtHandle = TRUE; 
 
//--------------------------------------------------------------------
//      Complete token -- if needed 

if ((SEC_I_COMPLETE_NEEDED == ss) 
          || (SEC_I_COMPLETE_AND_CONTINUE == ss))  
{ 
     if (g_pFuncs->CompleteAuthToken)
     {
          ss = g_pFuncs->CompleteAuthToken (
               &pAS->_hctxt, 
               &OutBuffDesc);
          if (!SEC_SUCCESS(ss))  
          {
               HandleError("Complete failed.");
          }
     } 
    else 
     { 
          HandleError("Complete not supported."); 
     } 
} 
 
*pcbOut = OutSecBuff.cbBuffer; 
 
pAS->_fNewConversation = FALSE; 
*pfDone = !((SEC_I_CONTINUE_NEEDED == ss) || 
          (SEC_I_COMPLETE_AND_CONTINUE == ss)); 
return TRUE; 
}  // end GenServerContext 

//--------------------------------------------------------------------
//     Define ImpersonateContext()

BOOL ImpersonateContext (DWORD dwKey) 
{ 
SECURITY_STATUS ss; 
 
ss = (g_pFuncs->ImpersonateSecurityContext) (&pAS->_hctxt); 
if (!(SEC_SUCCESS(ss)))
{ 
     HandleError("Impersonation failed."); 
} 
return(TRUE); 
} // end ImpersonateContext.
 
//--------------------------------------------------------------------
//      Define RevertContext.
//      Revert to the original server context. 
//      Return TRUE is successful, otherwise, FALSE. 

BOOL RevertContext (DWORD dwKey) 
{ 
SECURITY_STATUS ss; 
 
ss = g_pFuncs->RevertSecurityContext (&pAS->_hctxt); 
if (!(SEC_SUCCESS(ss)))
{
     HandleError("Revert to original context failed."); 
} 
return(TRUE); 
} end ReverContext.
 
//--------------------------------------------------------------------
//      Define InitSession.
//      Initialize the server's context. 
//      Return TRUE if successful; otherwise, FALSE. 

BOOL InitSession (DWORD dwKey) 
{ 
 
if(!(pAS = (PAUTH_SEQ) malloc (sizeof (AUTH_SEQ))))
{
     HandleError("Memory allocation error in InitSession.");
}
 
pAS->_fNewConversation = TRUE; 
pAS->_fHaveCredHandle = FALSE; 
pAS->_fHaveCtxtHandle = FALSE; 

return(TRUE); 
} 

//--------------------------------------------------------------------
//     Define UseSession.

void UseSession(SOCKET s, SecHandle phContext)
{ 
char szUser[80]; 
DWORD cbUser = 80; 

//--------------------------------------------------------------------
//      Impersonate the client 

ImpersonateContext (s);

//--------------------------------------------------------------------
//      Get the user name of the impersonated client. 
 
if (GetUserName (szUser, &cbUser))
{
     printf("The impersonated user name is %s",szUser);
}
else
{
     HandleError("GetUserName failed.\n");
}

//--------------------------------------------------------------------
//     Revert to self 

if (!(RevertContext (s)))
{
     HandleError("Could not revert to security context.\n");
}
printf("Sending the message 'Testing. This message is sent to check the connection.'\n");
if (!(SendMsg(
          s,
          (PBYTE)"Testing. This message is sent to check the connection.", 
          60))
{
     HandleError("User Message not sent.\n");
}

printf("Sending the user name.\n");
if (!(SendMsg(
      s,
     (PBYTE)szUser, 
      cbUser)))
{
     HandleError("User name not sent.\n");
}
} // end of UseSession.