Platform SDK: Logon Authentication

Using SSPI with a Windows Sockets Client

This sample program works with the server program Using SSPI with a Windows Sockets Server. Both this program and the server 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.

//--------------------------------------------------------------------
//      Client-side program to establish an SSPI socket connection
//      with a server and exchange messages.

//--------------------------------------------------------------------
//     Define macros and constants.

#define SEC_SUCCESS(Status) ((Status) >= 0) 
// 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 "security.dll"
// secur32.dll could also be used.
#define TOKEN_SOURCE_NAME       "AuthSamp" 
#define SECURITY_WIN32 
#define SERVER_NAME "SampleServer1"
#define wVerRequested 0x0101

//--------------------------------------------------------------------
//     Include header files.

#include <windows.h> 
#include <winsock.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include "sspi.h" 
 
//--------------------------------------------------------------------
//     Declare and initialize global structures and variables 

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

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

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

BOOL ConnectAuthSocket(LPCSTR szServer, SOCKET *s); 
BOOL CloseAuthSocket(SOCKET s); 
BOOL DoAuthentication(SOCKET s); 
BOOL GenClientContext (DWORD dwKey, BYTE *pIn, DWORD cbIn, BYTE *pOut,
        DWORD *pcbOut, BOOL *pfDone);
BOOL InitPackage (DWORD *pcbMaxMessage) ;
BOOL InitSession ();
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);

//--------------------------------------------------------------------
//      Define main()
 
void main() 
{ 
//--------------------------------------------------------------------
//     Declare and initialize local variables.

SOCKET s; 
WSADATA wsaData; 

//--------------------------------------------------------------------
//      Initialize Windows Sockets 
 
WSAStartup (wVerRequested, &wsaData); 

//--------------------------------------------------------------------
//      Initialize the SSPI security package. 

if (!(InitPackage (&g_cbMaxMessage)))
{
     HandleError("The security package could not be initialized.");
}

//--------------------------------------------------------------------
//      Allocate memory for the input and output message buffers.
 
g_pInBuf = (BYTE *) malloc (g_cbMaxMessage+512);
g_pOutBuf = (BYTE *) malloc (g_cbMaxMessage+512);
 
//--------------------------------------------------------------------
//      Connect to server 
 
if (!(ConnectAuthSocket (SERVER_NAME, &s)))
{
     HandleError("Could not connect to the socket.");
}
 
//--------------------------------------------------------------------
//      Make this an authenticated connection 
 
if (!(InitSession ()) )
{
     HandleError("The connection could not be initialized.");
}

if (!(DoAuthentication (s))) 
{
     HandleError("The connection could not be authenticated.");
}
//--------------------------------------------------------------------
//     Do some processing in the secure connection.

UseSession(s, pAS->_hctxt);

//--------------------------------------------------------------------
//     Clean up and terminate 
 
g_pFuncs->DeleteSecurityContext (&pAS->_hctxt); 
g_pFuncs->FreeCredentialHandle (&pAS->_hcred); 
free (pAS); 
shutdown (s, 2); 
closesocket (s); 
FreeLibrary (g_hLib); 
WSACleanup (); 
free (g_pInBuf); 
free (g_pOutBuf); 
printf("Program ran to completion.\n"); 
} // End of main

//--------------------------------------------------------------------
//     Define ConnectAuthSocket()
//     Connect to the Windows Sockets server. 
 
BOOL ConnectAuthSocket (
          LPCSTR szServer,  // server name. 
          SOCKET *s)        // pointer to the socket.
{ 
//--------------------------------------------------------------------
//     Declare and initialize local variables.

SOCKET sockServer; 
unsigned long ulAddress; 
struct hostent *pHost; 
SOCKADDR_IN sin; 

//--------------------------------------------------------------------
//      Look up the address for the server name 

ulAddress = inet_addr (szServer); 
if(pHost = gethostbyname (szServer))
{
     memcpy((char FAR *)&ulAddress, pHost->h_addr, pHost->h_length); 
}
else
{
     HandleError("Unable to resolve host name."); 
} 
 
//--------------------------------------------------------------------
//      Create the socket 

if(!(sockServer = socket (
     PF_INET, 
     SOCK_STREAM, 
     0)))
{
     HandleError("Unable to create socket."); 
} 
 
sin.sin_family = AF_INET; 
sin.sin_addr.s_addr = ulAddress; 
sin.sin_port = htons (g_usPort); 
 
//--------------------------------------------------------------------
//      Connect to remote endpoint 
 
if (connect (
     sockServer, 
     (LPSOCKADDR) &sin, 
     sizeof (sin)))
{ 
     HandleError("connect failed:"); 
} 

*s = sockServer; 
return(TRUE); 
} // End ConnectAuthSocket

//--------------------------------------------------------------------
//     Define DoAuthentication().
//     Manage the authentication conversation with the server via the 
//     supplied socket handle. 

BOOL DoAuthentication (SOCKET s) 
{ 
//--------------------------------------------------------------------
//     Declare and initialize local variables.

BOOL fDone = FALSE; 
DWORD cbOut, cbIn; 

cbOut = g_cbMaxMessage; 
if (!(GenClientContext (
     s, 
     NULL, 
     0, 
     g_pOutBuf, 
     &cbOut, 
     &fDone)))
{
     HandleError("Client context could not be generated.");
}
 
if (!(SendMsg (
     s, 
     g_pOutBuf, 
     cbOut)))
{
     HandleError("Message could not be sent.");
}

while(!fDone)
{
     if (!(ReceiveMsg(
          s,
          g_pInBuf, 
          g_cbMaxMessage, 
          &cbIn))) 
     {
          HandleError("Message not received.");
     }
     cbOut = g_cbMaxMessage; 
     GenClientContext (
          s, 
          g_pInBuf, 
          cbIn, 
          g_pOutBuf, 
          &cbOut, 
          &fDone);
     if (!(SendMsg (
          s, 
          g_pOutBuf, 
          cbOut)))
     {
          HandleError("Message not sent.");
     }
} // End of while loop
return(fDone); 
} // End of DoAuthentication

//--------------------------------------------------------------------
//      Handle communication with the security package. 
 
//--------------------------------------------------------------------
//     Define InitPackage()

BOOL InitPackage (DWORD *pcbMaxMessage) 
{ 
//--------------------------------------------------------------------
//     Declare and initialize local variables.

FARPROC pInit; 
SECURITY_STATUS ss; 
PSecPkgInfo pkgInfo; 
ULONG cPackages, i;
SecPkgInfo *ppPackageInfo;
 
//--------------------------------------------------------------------
//     Load and initialize an security package library 

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

if(!(pInit = GetProcAddress (g_hLib, SECURITY_ENTRYPOINT)))
{ 
     HandleError("Could not get sec init routine."); 
} 
 
if(!(g_pFuncs = (PSecurityFunctionTable) pInit ()))
{ 
     HandleError("Could not initialize the security package"); 
} 
 
//--------------------------------------------------------------------
// List the available packages 

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

//--------------------------------------------------------------------
//  Query one of the packages for the maximum token length.

ss = g_pFuncs->QuerySecurityPackageInfo (PACKAGE_NAME, &pkgInfo); 
if (!SEC_SUCCESS(ss))  
{ 
     HandleError("Could not query package information."); 
} 
 
g_cbMaxToken = pkgInfo->cbMaxToken; 
g_pFuncs->FreeContextBuffer (pkgInfo); 
*pcbMaxMessage = g_cbMaxToken; 
return TRUE; 
} 
 
//--------------------------------------------------------------------
//     Define GenClientContext().
 
BOOL GenClientContext ( 
DWORD dwKey, 
BYTE *pIn, 
DWORD cbIn, 
BYTE *pOut, 
DWORD *pcbOut, 
BOOL *pfDone) 
{ 
//--------------------------------------------------------------------
//     Declare and initialize local variables.

SECURITY_STATUS ss; 
TimeStamp Lifetime;
SecBufferDesc OutBuffDesc;
SecBufferDesc InBuffDesc;
SecBuffer OutSecBuff; 
SecBuffer InSecBuff; 
ULONG ContextAttributes; 
 
if (pAS->_fNewConversation)  
{ 
     ss = g_pFuncs->AcquireCredentialsHandle ( 
        NULL,           // use the default principal 
        PACKAGE_NAME, 
        SECPKG_CRED_OUTBOUND, 
        NULL,          // use the default LOGON id 
        NULL,          // no authentication data 
        NULL,          // no callback function needed to get a key 
        NULL,          // no callback function arguments needed  
        &pAS->_hcred, 
        &Lifetime); 
     if (SEC_SUCCESS (ss)) 
     {
         pAS->_fHaveCredHandle = TRUE;
     }
     else 
     { 
          HandleError("AcquireCreds failed."); 
     }
} 

//--------------------------------------------------------------------
//      Prepare buffers 
// 
OutBuffDesc.ulVersion = 0; 
OutBuffDesc.cBuffers = 1; 
OutBuffDesc.pBuffers = &OutSecBuff; 
 
OutSecBuff.cbBuffer = *pcbOut; 
OutSecBuff.BufferType = SECBUFFER_TOKEN; 
OutSecBuff.pvBuffer = pOut; 
 
if (!pAS->_fNewConversation)  
{ 
     InBuffDesc.ulVersion = 0; 
     InBuffDesc.cBuffers = 1; 
     InBuffDesc.pBuffers = &InSecBuff; 
 
     InSecBuff.cbBuffer = cbIn; 
     InSecBuff.BufferType = SECBUFFER_TOKEN; 
     InSecBuff.pvBuffer = pIn; 
} 

ss = g_pFuncs->InitializeSecurityContext( 
     &pAS->_hcred, 
     pAS->_fNewConversation ? NULL : &pAS->_hctxt, 
     TOKEN_SOURCE_NAME, 
     0,// context requirements 
     0,// reserved1 
     SECURITY_NATIVE_DREP, 
     pAS->_fNewConversation ? NULL : &InBuffDesc, 
     0,// reserved2 
     &pAS->_hctxt, 
     &OutBuffDesc, 
     &ContextAttributes, 
     &Lifetime 
); 

if (!SEC_SUCCESS (ss))  
{ 
     HandleError("init context failed."); 
} 
pAS->_fHaveCtxtHandle = TRUE; 

//--------------------------------------------------------------------
//      Complete token -- if applicable 
// 
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 GenClientContext

//--------------------------------------------------------------------
//     Define InitSession(),

BOOL InitSession () 
{ 
 
pAS = (PAUTH_SEQ) malloc (sizeof (AUTH_SEQ)); 
if (NULL == pAS) 
{
     return(FALSE);
}

pAS->_fNewConversation = TRUE; 
pAS->_fHaveCredHandle = FALSE; 
pAS->_fHaveCtxtHandle = FALSE; 
 
return(TRUE); 
} // end InitSession

//--------------------------------------------------------------------
//     Define UseSession().
void UseSession(SOCKET s, SecHandle phContext)
{
//--------------------------------------------------------------------
//     Declare and initialize local variables.

int cbRead; 
char achData[BUFSIZ];

if (ReceiveMsg(
     s, 
     (BYTE *) achData,  
     g_cbMaxMessage, 
     (unsigned long *)&cbRead)) 
{
     printf ("First read: %d %s\n", cbRead, achData); 
}
else
{
     HandleError("Message not received.");
}

if (ReceiveMsg (
     s, 
     (BYTE *) achData,  
     g_cbMaxMessage, 
     (unsigned long *)&cbRead)) 
{
     printf ("Second read: %d %s\n", cbRead, achData); 
}
else
{
     HandleError("Message not received.");
}

/*
if (ReceiveMsg (
     s, 
     (BYTE *) achData,  
     g_cbMaxMessage, 
     (unsigned long *)&cbRead)) 
{
     printf ("Second read: %d %s\n", cbRead, achData); 
}
else
{
     HandleError("Message not received.");
}
*/
} // end of UseSession.