SSPI Sample Application

The following is an example of an SSPI application.

#include <windows.h>
#include <sspi.h>
#include <issperr.h>
#include <winsock.h>

#define BUFFERLEN     16384 

BOOL InitSspi (HINSTANCE);
BOOL AuthConn (PSecurityFunctionTable, PSecPkgInfo, DWORD);

/***********************************************************************

FUNCTION: 
  WinMain

PURPOSE: 
  Called by the system as the initial entry point for this Windows 
  CEbased application.

***********************************************************************/
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, 
                    LPTSTR lpCmdLine, int nCmdShow)
{
  HINSTANCE DllHandle;
  TCHAR szError[100];

  // Load the security provider DLL.
  DllHandle = LoadLibrary (TEXT("secur32.dll"));

  if (!DllHandle)
  {
    wsprintf (szError, 
              TEXT("Failed in loading secur32.dll, Error: %x"),
              GetLastError ());
    return 0;
  }

  if (!InitSspi (DllHandle))
  {
    MessageBox (NULL, 
                TEXT("Failed in initializing the SSPI."),
                TEXT("Error"),
                MB_OK);
    return 0;
  }

  return 1;
}

/***********************************************************************

FUNCTION: 
  InitSspi

PURPOSE: 
  Initializes Security Support Provider Interface.

***********************************************************************/
BOOL InitSspi (HINSTANCE DllHandle)
{
  DWORD dwIndex,
        dwNumOfPkgs,
        dwPkgToUse;
  TCHAR szError[100];

  INIT_SECURITY_INTERFACE InitSecurityInterface;
  PSecurityFunctionTable pSecurityInterface = NULL;
  PSecPkgInfo pSecurityPackages = NULL;
  SECURITY_STATUS status;
  ULONG ulCapabilities;

  // Get the address of the function InitSecurityInterface.
  InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress (
                                        DllHandle, 
                                        TEXT("InitSecurityInterfaceW"));

  if (!InitSecurityInterface)
  {
    wsprintf (szError, 
              TEXT("Failed in getting the function address, Error: %x"),
              GetLastError ());
    return FALSE;
  }

  // Use InitSecurityInterface to get the function table.
  pSecurityInterface = (*InitSecurityInterface)();

  if (!pSecurityInterface)
  {
    wsprintf (szError, 
              TEXT("Failed in getting the function table, Error: %x"),
              GetLastError ());
    return FALSE;
  }

  if (!(pSecurityInterface->EnumerateSecurityPackages))
  {
    wsprintf (szError, 
              TEXT("Failed in getting the function table, Error: %x"),
              GetLastError ());
    return FALSE;
  }

  // Retrieve the security packages supported by the provider.
  status = (*pSecurityInterface->EnumerateSecurityPackages)(
                                                    &dwNumOfPkgs, 
                                                    &pSecurityPackages);
  if (status != SEC_E_OK)
  {
    wsprintf (szError, 
              TEXT("Failed in retrieving security packages, Error: %x"),
              GetLastError ());
    return FALSE;
  }

  // Initialize dwPkgToUse. 
  dwPkgToUse = -1;

  // Assume the application needs integrity, privacy, and impersonation 
  // on messages.
  ulCapabilities = SECPKG_FLAG_INTEGRITY | SECPKG_FLAG_PRIVACY | 
                   SECPKG_FLAG_IMPERSONATION;

  // Determine which package should be used.
  for (dwIndex = 0; dwIndex < dwNumOfPkgs; dwIndex++)
  {
    if ((pSecurityPackages[dwIndex].fCapabilities & ulCapabilities) ==
        ulCapabilities)
    {
      dwPkgToUse = dwIndex;
      break;
    }
  }

  if (!AuthConn (pSecurityInterface, pSecurityPackages, dwPkgToUse))
  {
    MessageBox (NULL, 
                TEXT("Failed in authenticating a connection."),
                TEXT("Error"),
                MB_OK);
    return FALSE;
  }
  
  return TRUE;
}

/***********************************************************************

FUNCTION: 
  AuthConn

PURPOSE: 
  Authenticates a connection.

***********************************************************************/
BOOL AuthConn (PSecurityFunctionTable pSecurityInterface,
               PSecPkgInfo pSecurityPackages,
               DWORD dwPkgToUse)
{
  BOOL bReturn = FALSE;           // Return value of the function
  TCHAR szError[100],             // String for the error message
        szTargetName[100];        // Target name 
  LPSTR pszOutBuffer = NULL;      // Used in security data xfr
  ULONG ulContextReq,             // Required context attributes
        ulContextAttributes;      // Receives attributes of the context
  TimeStamp tsExpiry;             // Returned credentials' life time
  SECURITY_STATUS status;         // Return codes
  CredHandle hCredential;         // Handle to the credential 
  CtxtHandle hNewContext;         // Handle to the security context
  SecBuffer OutSecBuffer;         // Output buffer
  SecBufferDesc OutBufferDesc;    // Output buffer descriptor

  // Check if the pointer to SecurityFunctionTable is valid.
  if (!pSecurityInterface)
    goto exit;
 
  // Allocate buffer memory for pszOutBuffer.
  if (!(pszOutBuffer = new char[BUFFERLEN]))
    goto exit;

  // Acquire an outbound credential handle.
  status = (*pSecurityInterface->AcquireCredentialsHandle)(
                                    NULL,
                                    pSecurityPackages[dwPkgToUse].Name,
                                    SECPKG_CRED_OUTBOUND,
                                    NULL,
                                    NULL,
                                    NULL,
                                    NULL,
                                    &hCredential,
                                    &tsExpiry);
  if (status != SEC_E_OK)
  {
    wsprintf (szError, 
              TEXT("Failed in acquiring the credential handle: %x"), 
              status);
    goto exit;
  }

  // Initialize the OutSecBuffer structure.
  OutSecBuffer.cbBuffer = BUFFERLEN;
  OutSecBuffer.BufferType = SECBUFFER_TOKEN;
  OutSecBuffer.pvBuffer = pszOutBuffer;

  // Initialize the OutBufferDesc structure.
  OutBufferDesc.ulVersion = 0;
  OutBufferDesc.cBuffers = 1;
  OutBufferDesc.pBuffers = &OutSecBuffer;

  ulContextReq = ISC_REQ_MUTUAL_AUTH | ISC_REQ_CONNECTION |
                 ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT | 
                 ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY;

  // Assign the target (server) name.
  // wcscpy (szTargetName, TEXT("..."));

  // Get the authentication token from the security package to send to
  // the server to request an authenticated token.
  status = (*pSecurityInterface->InitializeSecurityContext)(
                                            &hCredential,
                                            NULL,
                                            szTargetName,
                                            ulContextReq,
                                            0,
                                            SECURITY_NATIVE_DREP,
                                            NULL,
                                            0,
                                            &hNewContext,
                                            &OutBufferDesc,
                                            &ulContextAttributes,
                                            &tsExpiry);

  if (status == SEC_I_CONTINUE_NEEDED)
  {
    SOCKET Socket = INVALID_SOCKET;         // Server socket 
  
    // Add code here to connect to server. Get the server socket.
    // ...

    // Send hCredential to server
    if (send (Socket, (const char *)OutSecBuffer.pvBuffer, 
              OutSecBuffer.cbBuffer, 0) == SOCKET_ERROR)
    {
      wsprintf (szError, 
                TEXT("Failed in sending hCredential to the server: %d"),
                WSAGetLastError ());
      goto exit;
    }

    // Add code here to make the second call to the 
    // InitializeSecurityContext function.
    // ...
  }
  else 
  {
    if (status != SEC_E_OK)
    {
      wsprintf (szError, 
                TEXT("Failed in initiating the outbound security ")
                TEXT("context: %x"),
                status);
      goto exit;
    }
  }

  bReturn = TRUE;

exit:

  if (pszOutBuffer) 
    delete[] pszOutBuffer;

  if (pSecurityInterface)
  {
    (*pSecurityInterface->FreeCredentialHandle)(&hCredential);
    (*pSecurityInterface->DeleteSecurityContext)(&hNewContext);
    (*pSecurityInterface->FreeContextBuffer)(&OutBufferDesc);
  }

  return bReturn;
}