Windows2003-3790/inetcore/wininet/auth/sspspm.c
2020-09-30 16:53:55 +02:00

515 lines
15 KiB
C

/*#----------------------------------------------------------------------------
**
** File: sspspm.c
**
** Synopsis: Security Protocol Module for SSPI Authentication providers.
**
** This module contains major funtions of the SEC_SSPI.DLL which
** allows the Internet Explorer to use SSPI providers for authentication.
** The function exported to the Internet Explorer is Ssp_Load() which
** passes the address of the Ssp__DownCall() function to the Explorer.
** Then the Explorer will call Ssp__DownCall() when it needs service from
** this SPM DLL. The two major functions called by Ssp__DownCall() to
** service Explorer's request are Ssp__PreProcessRequest() and
** Ssp__ProcessResponse(). In brief, Ssp__PreProcessRequest() is
** called before the Explorer sends out a request which does not have
** any 'Authorization' header yet. And Ssp__ProcessResponse() is called
** whenever the Explorer receives an 401 'Unauthorized' response from the
** server. This SPM DLL supports all SSPI packages which are installed
** on the machine. However, MSN will be given higher priority over the
** other SSPI packages if the user already logon to MSN; in that case,
** Ssp__PreProcessRequest() will always attach MSN authentication header
** to the out-going request.
**
** This SPM DLL is called by the Internet Explorer only for its
** The Internet Explorer only calls this SPM DLL when it needs
** authentication data in its request/response. In other words, the
** Explorer never calls this SPM DLL when an authentication succeeded;
** it never calls this DLL when it decide to give up on a connection
** because of server response timeout. Because of this fact, this SPM
** DLL never has sufficient information on the state of each server
** connection; it only know its state based on the content of the last
** request and the content of the current response. For this reason, this
** SPM DLL does not keep state information for each host it has visited
** unless the information is essential.
** The security context handle returned from the first call of
** InitializeSecurityContext() for NEGOTIATE message generation is
** always the identical for a SSPI package when the same server host is
** passed. Since the server host name is always in the request/response
** header, the only information essential in generating a NEGOTIATE or
** RESPONSE is already available in the header. So unlike most SSPI
** application, this DLL will not keep the security context handle which
** it received from the SSPI function calls. Whenever it needs to call
** the SSPI function for generating a RESPONSE, it will first call the
** SSPI function without the CHALLENGE to get a security context handle.
** Then it calls the SSPI function again with the CHALLENGE to generate
** a RESPONSE.
**
**
** Copyright (C) 1995 Microsoft Corporation. All Rights Reserved.
**
** Authors: LucyC Created 25 Sept. 1995
**
**---------------------------------------------------------------------------*/
#include "msnspmh.h"
#include <ntverp.h>
//
// Global variable where all the SSPI Pkgs data is collected
//
SspData *g_pSspData;
HINSTANCE g_hSecLib;
BOOL g_fIsWhistler = FALSE;
BOOL g_fCanUseCredMgr = FALSE;
/*-----------------------------------------------------------------------------
**
** Function: SpmAddSSPIPkg
**
** Synopsis: This function adds a SSPI package to the SPM's package list.
**
** Arguments: pData - Points to the private SPM data structure containing
** the package list and the package info.
** pPkgName - package name
** cbMaxToken - max size of security token
**
** Returns: The index in the package list where this new package is added.
** If failed to add the new package, SSPPKG_ERROR is returned.
**
** History: LucyC Created 21 Oct. 1995
**
**---------------------------------------------------------------------------*/
UCHAR
SpmAddSSPIPkg (
SspData *pData,
LPTSTR pPkgName,
ULONG cbMaxToken
)
{
if ( !(pData->PkgList[pData->PkgCnt] =
LocalAlloc(0, sizeof(SSPAuthPkg))))
{
return SSPPKG_ERROR;
}
if ( !(pData->PkgList[pData->PkgCnt]->pName =
LocalAlloc(0, lstrlen(pPkgName)+1)))
{
LocalFree(pData->PkgList[pData->PkgCnt]);
pData->PkgList[pData->PkgCnt] = NULL;
return SSPPKG_ERROR;
}
lstrcpy (pData->PkgList[pData->PkgCnt]->pName, pPkgName);
pData->PkgList[ pData->PkgCnt ]->Capabilities = 0 ;
pData->PkgList[ pData->PkgCnt ]->cbMaxToken = cbMaxToken;
//
// Determine if this package supports anything of interest to
// us.
//
if ( lstrcmpi( pPkgName, NTLMSP_NAME_A ) == 0 )
{
//
// NTLM supports the standard credential structure
//
pData->PkgList[ pData->PkgCnt ]->Capabilities |= SSPAUTHPKG_SUPPORT_NTLM_CREDS ;
}
else if ( lstrcmpi( pPkgName, "Negotiate" ) == 0 )
{
//
// Negotiate supports that cred structure too
//
pData->PkgList[ pData->PkgCnt ]->Capabilities |= SSPAUTHPKG_SUPPORT_NTLM_CREDS ;
}
else
{
//
// Add more comparisons here, eventually.
//
;
}
pData->PkgCnt++;
return (pData->PkgCnt - 1);
}
/*-----------------------------------------------------------------------------
**
** Function: SpmFreePkgList
**
** Synopsis: This function frees memory allocated for the package list.
**
** Arguments: pData - Points to the private SPM data structure containing
** the package list and the package info.
**
** Returns: void.
**
** History: LucyC Created 21 Oct. 1995
**
**---------------------------------------------------------------------------*/
VOID
SpmFreePkgList (
SspData *pData
)
{
int ii;
for (ii = 0; ii < pData->PkgCnt; ii++)
{
LocalFree(pData->PkgList[ii]->pName);
LocalFree(pData->PkgList[ii]);
}
LocalFree(pData->PkgList);
}
/*-----------------------------------------------------------------------------
**
** Function: Ssp__Unload
**
** Synopsis: This function is called by the Internet Explorer before
** the SPM DLL is unloaded from the memory.
**
** Arguments: fpUI - From Explorer for making all UI_SERVICE call
** pvOpaqueOS - From Explorer for making all UI_SERVICE call
** htspm - the SPM structure which contains the global data
** storage for this SPM DLL.
**
** Returns: always returns SPM_STATUS_OK, which means successful.
**
** History: LucyC Created 25 Sept. 1995
**
**---------------------------------------------------------------------------*/
DWORD SSPI_Unload()
{
if (g_pSspData != NULL)
{
SpmFreePkgList(g_pSspData);
LocalFree(g_pSspData);
g_pSspData = NULL;
}
if (g_hSecLib)
{
FreeLibrary (g_hSecLib);
g_hSecLib = NULL;
}
return SPM_STATUS_OK;
}
/*-----------------------------------------------------------------------------
**
** Function: SspSPM_InitData
**
** Synopsis: This function allocates and initializes global data structure
** of the SPM DLL.
**
** Arguments:
**
** Returns: Pointer to the allocated global data structure.
**
** History: LucyC Created 25 Sept. 1995
**
**---------------------------------------------------------------------------*/
LPVOID SSPI_InitGlobals(void)
{
SspData *pData = NULL;
OSVERSIONINFO VerInfo;
UCHAR lpszDLL[SSP_SPM_DLL_NAME_SIZE];
INIT_SECURITY_INTERFACE addrProcISI = NULL;
SECURITY_STATUS sstat;
ULONG ii, cntPkg;
PSecPkgInfo pPkgInfo = NULL;
PSecurityFunctionTable pFuncTbl = NULL;
if (g_pSspData)
return g_pSspData;
//
// Setup registry to enable MSN authentication package
// MSNSetupSspiReg();
//
//
// Initialize SSP SPM Global Data
//
//
// Find out which security DLL to use, depending on
// whether we are on NT or Win95
//
VerInfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
if (!GetVersionEx (&VerInfo)) // If this fails, something has gone wrong
{
return (NULL);
}
if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)
{
lstrcpy (lpszDLL, SSP_SPM_NT_DLL);
if ((VerInfo.dwMajorVersion >= 5) &&
(VerInfo.dwMinorVersion >= 1))
{
DWORD dwMaximumPersist = 0;
g_fIsWhistler = TRUE;
}
else
{
g_fIsWhistler = FALSE;
}
}
else if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
{
lstrcpy (lpszDLL, SSP_SPM_WIN95_DLL);
}
else if (VerInfo.dwPlatformId == VER_PLATFORM_WIN32_UNIX)
{
lstrcpy (lpszDLL, SSP_SPM_UNIX_DLL);
}
else
{
return (NULL);
}
if (!(pData = (SspData *) LocalAlloc(0, sizeof(SspData)))) {
return(NULL);
}
//
// Keep these information in global SPM
//
ZeroMemory (pData, sizeof(SspData));
pData->MsnPkg = SSPPKG_NO_PKG;
//
// Load Security DLL
//
g_hSecLib = LoadLibrary (lpszDLL);
if (g_hSecLib == NULL)
{
// This should never happen.
goto Cleanup;
}
#ifdef UNIX
// A hack to undo the mistake in the sspi.h file. The change should be made
// to sspi.h
#if !defined(_UNICODE)
#undef SECURITY_ENTRYPOINT_ANSI
#define SECURITY_ENTRYPOINT_ANSI "InitSecurityInterfaceA"
#endif
addrProcISI = (INIT_SECURITY_INTERFACE) GetProcAddress( g_hSecLib,
SECURITY_ENTRYPOINT_ANSI);
#else
addrProcISI = (INIT_SECURITY_INTERFACE) GetProcAddress( g_hSecLib,
SECURITY_ENTRYPOINT);
#endif /* UNIX */
if (addrProcISI == NULL)
{
goto Cleanup;
}
//
// Get the SSPI function table
//
pFuncTbl = (*addrProcISI)();
//
// If we already loaded MSNSSPC.DLL explicitly, PkgCnt will not be zero;
// in that case, we only support MSN SSPI and do not need to call
// EnumerateSecurityPackages.
//
// So if we did not load MSNSSPC.DLL (i.e. PkgCnt is zero), we need to
// get the list of SSPI packages which we support from
// EnumerateSecurityPackages.
//
if (pData->PkgCnt == 0)
{
//
// Get list of packages supported
//
sstat = (*(pFuncTbl->EnumerateSecurityPackages))(&cntPkg, &pPkgInfo);
if (sstat != SEC_E_OK || pPkgInfo == NULL)
{
//
// ??? Should we give up here ???
// EnumerateSecurityPackage() failed
//
goto Cleanup;
}
if (cntPkg)
{
//
// Create the package list
//
if (!(pData->PkgList = (PSSPAuthPkg *)LocalAlloc(0,
cntPkg*sizeof(PSSPAuthPkg))))
{
goto Cleanup;
}
}
for (ii = 0; ii < cntPkg; ii++)
{
if (lstrcmp (pPkgInfo[ii].Name, MSNSP_NAME) == 0)
{
//DebugTrace(SSPSPMID, "Found MSN SSPI package\n");
pData->MsnPkg = SpmAddSSPIPkg (
pData,
MSNSP_NAME,
MAX_AUTH_MSG_SIZE // 11000 hard-coded
);
if (pData->MsnPkg == SSPPKG_ERROR)
{
goto Cleanup;
}
}
else
{
//DebugTrace(SSPSPMID, "Found %s SSPI package\n",
// pPkgInfo[ii].Name);
if (SpmAddSSPIPkg (pData,
pPkgInfo[ii].Name,
pPkgInfo[ii].cbMaxToken
) == SSPPKG_ERROR)
{
goto Cleanup;
}
}
}
}
pData->pFuncTbl = pFuncTbl;
pData->bKeepList = TRUE; // By default, keep a list of non-MSN servers
if (pData->PkgCnt == 0)
{
goto Cleanup;
}
g_pSspData = pData;
pData = NULL;
Cleanup:
if( pPkgInfo != NULL )
{
//
// Free buffer returned by the enumerate security package function
//
(*(pFuncTbl->FreeContextBuffer))(pPkgInfo);
}
if( pData != NULL )
{
SpmFreePkgList (pData);
}
return (g_pSspData);
}
INT
GetPkgId(LPTSTR lpszPkgName)
{
int ii;
if ( g_pSspData == NULL )
{
return -1;
}
for (ii = 0; ii < g_pSspData->PkgCnt; ii++)
{
#ifdef UNIX
if (!lstrcmpi(g_pSspData->PkgList[ii]->pName, lpszPkgName))
#else
if (!lstrcmp(g_pSspData->PkgList[ii]->pName, lpszPkgName))
#endif /* UNIX */
{
return(ii);
}
}
return(-1);
}
DWORD
GetPkgCapabilities(
INT Package
)
{
if ( Package < g_pSspData->PkgCnt )
{
return g_pSspData->PkgList[ Package ]->Capabilities ;
}
else
return 0 ;
}
ULONG
GetPkgMaxToken(
INT Package
)
{
if ( Package < g_pSspData->PkgCnt )
{
return g_pSspData->PkgList[ Package ]->cbMaxToken;
}
else {
// be compatible with old static buffer size
return MAX_AUTH_MSG_SIZE;
}
}
//
// Calls to this function are serialized
//
DWORD_PTR SSPI_InitScheme (LPCSTR lpszScheme)
{
int ii;
if (!SSPI_InitGlobals())
return 0;
// Once initialized, check to see if this scheme is installed
for (ii = 0; ii < g_pSspData->PkgCnt &&
#ifdef UNIX
lstrcmpi (g_pSspData->PkgList[ii]->pName, lpszScheme); ii++);
#else
lstrcmp (g_pSspData->PkgList[ii]->pName, lpszScheme); ii++);
#endif /* UNIX */
if (ii >= g_pSspData->PkgCnt)
{
// This scheme is not installed on this machine
return (0);
}
return ((DWORD_PTR)g_pSspData);
}