|
|
//--------------------------------------------------------------------------
// Sicily.cpp
//--------------------------------------------------------------------------
#include "pch.hxx"
#include "imnxport.h"
#include "sicily.h"
#include "dllmain.h"
#include "resource.h"
#include "imnxport.h"
#include "strconst.h"
#include <shlwapi.h>
#include "demand.h"
//--------------------------------------------------------------------------
// NTLMSSP_SIGNATURE
//--------------------------------------------------------------------------
#define NTLMSSP_SIGNATURE "NTLMSSP"
//--------------------------------------------------------------------------
// NegotiateFlags
//--------------------------------------------------------------------------
#define NTLMSSP_NEGOTIATE_UNICODE 0x0001 // Text strings are in unicode
//--------------------------------------------------------------------------
// Security Buffer Counts
//--------------------------------------------------------------------------
#define SEC_BUFFER_NUM_NORMAL_BUFFERS 1
//--------------------------------------------------------------------------
// Security Buffer Indexes
//--------------------------------------------------------------------------
#define SEC_BUFFER_CHALLENGE_INDEX 0
#define SEC_BUFFER_USERNAME_INDEX 1
#define SEC_BUFFER_PASSWORD_INDEX 2
#define SEC_BUFFER_NUM_EXTENDED_BUFFERS 3
//--------------------------------------------------------------------------
// NTLM_MESSAGE_TYPE
//--------------------------------------------------------------------------
typedef enum { NtLmNegotiate = 1, NtLmChallenge, NtLmAuthenticate, NtLmUnknown } NTLM_MESSAGE_TYPE;
//--------------------------------------------------------------------------
// STRING
//--------------------------------------------------------------------------
typedef struct _STRING { USHORT Length; USHORT MaximumLength; PWCHAR Buffer; } STRING, *PSTRING;
//--------------------------------------------------------------------------
// AUTHENTICATE_MESSAGE
//--------------------------------------------------------------------------
typedef struct _AUTHENTICATE_MESSAGE { UCHAR Signature[sizeof(NTLMSSP_SIGNATURE)]; NTLM_MESSAGE_TYPE MessageType; STRING LmChallengeResponse; STRING NtChallengeResponse; STRING DomainName; STRING UserName; STRING Workstation; STRING SessionKey; ULONG NegotiateFlags; } AUTHENTICATE_MESSAGE, *PAUTHENTICATE_MESSAGE;
//--------------------------------------------------------------------------
// Constants
//--------------------------------------------------------------------------
#define CCHMAX_NTLM_DOMAIN 255
#define LOGON_OK 10000
//--------------------------------------------------------------------------
// String Constants
//--------------------------------------------------------------------------
static const CHAR c_szSecurityDLL[] = "security.dll"; static const CHAR c_szSecur32DLL[] = "secur32.dll";
//--------------------------------------------------------------------------
// MSN/DPA CleareCredentialsCache Function Prototype
//--------------------------------------------------------------------------
typedef BOOL (WINAPI * PFNCLEANUPCREDENTIALCACHE)(void);
//--------------------------------------------------------------------------
// CREDENTIAL
//--------------------------------------------------------------------------
typedef struct tagCREDENTIAL *LPCREDENTIAL; typedef struct tagCREDENTIAL { CHAR szServer[CCHMAX_SERVER_NAME]; CHAR szUserName[CCHMAX_USERNAME]; CHAR szPassword[CCHMAX_PASSWORD]; CHAR szDomain[CCHMAX_NTLM_DOMAIN]; DWORD cRetry; LPCREDENTIAL pNext; } CREDENTIAL;
//--------------------------------------------------------------------------
// SSPIPROMPTINFO
//--------------------------------------------------------------------------
typedef struct tagSSPIPROMPTINFO { HRESULT hrResult; LPSSPICONTEXT pContext; ULONG fContextAttrib; PSecBufferDesc pInDescript; PSecBufferDesc pOutDescript; TimeStamp tsExpireTime; PCtxtHandle phCtxCurrent; DWORD dwFlags; } SSPIPROMPTINFO, *LPSSPIPROMPTINFO;
//--------------------------------------------------------------------------
// SSPILOGON
//--------------------------------------------------------------------------
typedef struct tagSSPILOGON { LPCREDENTIAL pCredential; LPSSPICONTEXT pContext; } SSPILOGON, *LPSSPILOGON;
//--------------------------------------------------------------------------
// SSPILOGONFLAGS
//--------------------------------------------------------------------------
typedef DWORD SSPILOGONFLAGS; #define SSPI_LOGON_RETRY 0x00000001
#define SSPI_LOGON_FLUSH 0x00000002
//--------------------------------------------------------------------------
// Globals
//--------------------------------------------------------------------------
static PSecurityFunctionTable g_pFunctions = NULL; static HINSTANCE g_hInstSSPI = NULL; static LPCREDENTIAL g_pCredentialHead=NULL; static LPSSPIPACKAGE g_prgPackage=NULL; static DWORD g_cPackages=0;
//--------------------------------------------------------------------------
// base642six
//--------------------------------------------------------------------------
static const int base642six[256] = { 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63, 52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9, 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27, 28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64 };
//--------------------------------------------------------------------------
// six2base64
//--------------------------------------------------------------------------
static const char six2base64[64] = { 'A','B','C','D','E','F','G','H','I','J','K','L','M', 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 'a','b','c','d','e','f','g','h','i','j','k','l','m', 'n','o','p','q','r','s','t','u','v','w','x','y','z', '0','1','2','3','4','5','6','7','8','9','+','/' };
//--------------------------------------------------------------------------
// uu2six
//--------------------------------------------------------------------------
const int uu2six[256] = { 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15, 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39, 40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63, 0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, 64,64,64,64,64,64,64,64,64,64,64,64,64 }; //--------------------------------------------------------------------------
// six2uu
//--------------------------------------------------------------------------
static const char six2uu[64] = { '`','!','"','#','$','%','&','\'','(',')','*','+',',', '-','.','/','0','1','2','3','4','5','6','7','8','9', ':',';','<','=','>','?','@','A','B','C','D','E','F', 'G','H','I','J','K','L','M','N','O','P','Q','R','S', 'T','U','V','W','X','Y','Z','[','\\',']','^','_' };
//--------------------------------------------------------------------------
// Prototypes
//--------------------------------------------------------------------------
HRESULT SSPIFlushMSNCredentialCache(void);
//--------------------------------------------------------------------------
// SSPISetBuffer
//--------------------------------------------------------------------------
HRESULT SSPISetBuffer(LPCSTR pszString, SSPIBUFFERTYPE tyBuffer, DWORD cbBuffer, LPSSPIBUFFER pBuffer) { // Trace
TraceCall("SSPISetBuffer");
// No Length Passed In ?
if (SSPI_STRING == tyBuffer) { // Get the Length
pBuffer->cbBuffer = lstrlen(pszString) + 1;
// Too Long
if (pBuffer->cbBuffer > CBMAX_SSPI_BUFFER) pBuffer->cbBuffer = CBMAX_SSPI_BUFFER;
// Copy the data
CopyMemory(pBuffer->szBuffer, pszString, pBuffer->cbBuffer);
// Stuff a Null
pBuffer->szBuffer[pBuffer->cbBuffer - 1] = '\0';
// Loop
while (pBuffer->cbBuffer >= 2) { // Not a CRLF
if ('\r' != pBuffer->szBuffer[pBuffer->cbBuffer - 2] && '\n' != pBuffer->szBuffer[pBuffer->cbBuffer - 2]) break;
// Decrement Length
pBuffer->cbBuffer--;
// Null Terminate
pBuffer->szBuffer[pBuffer->cbBuffer - 1] = '\0'; } }
// Otherwise, set cbBuffer
else { // Set cbBuffer
pBuffer->cbBuffer = min(cbBuffer + 1, CBMAX_SSPI_BUFFER);
// Null Terminate
pBuffer->szBuffer[pBuffer->cbBuffer - 1] = '\0';
// Copy the data
CopyMemory(pBuffer->szBuffer, pszString, pBuffer->cbBuffer); }
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// GetCredentialDlgProc
//--------------------------------------------------------------------------
INT_PTR CALLBACK GetCredentialDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { // Locals
LPSSPILOGON pLogon=(LPSSPILOGON)GetWndThisPtr(hwnd); CHAR szRes[CCHMAX_RES]; CHAR szTitle[CCHMAX_RES + CCHMAX_SERVER_NAME];
// Trace
TraceCall("GetCredentialDlgProc"); // Handle Message
switch (uMsg) { case WM_INITDIALOG: // Get the pointer
pLogon = (LPSSPILOGON)lParam; Assert(pLogon);
// Set pContext hwndLogon
pLogon->pContext->hwndLogon = hwnd;
// Set myself to the foreground
SetForegroundWindow(hwnd);
// Center remember location
CenterDialog(hwnd);
// Limit Text
Edit_LimitText(GetDlgItem(hwnd, IDE_USERNAME), CCHMAX_USERNAME - 1); Edit_LimitText(GetDlgItem(hwnd, IDE_PASSWORD), CCHMAX_PASSWORD - 1); Edit_LimitText(GetDlgItem(hwnd, IDE_DOMAIN), CCHMAX_NTLM_DOMAIN - 1);
// Set Window Title
GetWindowText(hwnd, szRes, ARRAYSIZE(szRes)); wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s - %s", szRes, pLogon->pCredential->szServer); SetWindowText(hwnd, szTitle);
// Set User Name
Edit_SetText(GetDlgItem(hwnd, IDE_USERNAME), pLogon->pCredential->szUserName); Edit_SetText(GetDlgItem(hwnd, IDE_PASSWORD), pLogon->pCredential->szPassword); Edit_SetText(GetDlgItem(hwnd, IDE_DOMAIN), pLogon->pCredential->szDomain);
// Focus
if (pLogon->pCredential->szUserName[0] == '\0') SetFocus(GetDlgItem(hwnd, IDE_USERNAME)); else SetFocus(GetDlgItem(hwnd, IDE_PASSWORD));
// Save the pointer
SetWndThisPtr(hwnd, pLogon);
// Done
return(FALSE);
case WM_COMMAND: switch(GET_WM_COMMAND_ID(wParam,lParam)) { case IDCANCEL: if (pLogon) pLogon->pContext->hwndLogon = NULL; EndDialog(hwnd, IDCANCEL); return(TRUE);
case IDOK: Assert(pLogon); if (pLogon) { Edit_GetText(GetDlgItem(hwnd, IDE_USERNAME), pLogon->pCredential->szUserName, CCHMAX_USERNAME); Edit_GetText(GetDlgItem(hwnd, IDE_PASSWORD), pLogon->pCredential->szPassword, CCHMAX_PASSWORD); Edit_GetText(GetDlgItem(hwnd, IDE_DOMAIN), pLogon->pCredential->szDomain, CCHMAX_NTLM_DOMAIN); pLogon->pContext->hwndLogon = NULL; } EndDialog(hwnd, LOGON_OK); return(TRUE); } break;
case WM_DESTROY: // This is here because when OE shuts down and this dialog is displayed, a WM_QUIT is posted to the thread
// that this dialog lives on. WM_QUIT causes a WM_DESTROY dialog to get sent to this dialog, but the parent
// doesn't seem to get re-enabled
EnableWindow(GetParent(hwnd), TRUE);
// Null out the this pointer
SetWndThisPtr(hwnd, NULL);
// Set pContext hwndLogon
if (pLogon) pLogon->pContext->hwndLogon = NULL;
// Done
return(FALSE); }
// Done
return(FALSE); }
//--------------------------------------------------------------------------
// SSPIFillAuth
//--------------------------------------------------------------------------
HRESULT SSPIFillAuth(LPCSTR pszUserName, LPCSTR pszPassword, LPCSTR pszDomain, SEC_WINNT_AUTH_IDENTITY *pAuth) { // Set Flags
pAuth->Flags = SEC_WINNT_AUTH_IDENTITY_ANSI;
// Fill It
pAuth->User = (unsigned char *)(pszUserName ? pszUserName : c_szEmpty); pAuth->UserLength = lstrlen((LPSTR)pAuth->User); pAuth->Domain = (unsigned char *)(pszDomain ? pszDomain : c_szEmpty); pAuth->DomainLength = lstrlen((LPSTR)pAuth->Domain); pAuth->Password = (unsigned char *)(pszPassword ? pszPassword : c_szEmpty); pAuth->PasswordLength = lstrlen((LPSTR)pAuth->Password);
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// SSPIAuthFromCredential
//--------------------------------------------------------------------------
HRESULT SSPIAuthFromCredential(LPCREDENTIAL pCredential, SEC_WINNT_AUTH_IDENTITY *pAuth) { // Fill It
SSPIFillAuth(pCredential->szUserName, pCredential->szPassword, pCredential->szDomain, pAuth);
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// SSPIFindCredential
//--------------------------------------------------------------------------
HRESULT SSPIFindCredential(LPSSPICONTEXT pContext, ITransportCallback *pCallback) { // Locals
HRESULT hr=S_OK; LPCREDENTIAL pCurrent; LPCREDENTIAL pPrevious=NULL; LPCREDENTIAL pNew=NULL; SSPILOGON Logon; HWND hwndParent=NULL; ITransportCallbackService *pService=NULL;
// Trace
TraceCall("SSPIFindCredential");
// Invalid Arg
Assert(pContext->pszServer && pCallback);
// No Callback
if (NULL == pCallback) return TraceResult(E_INVALIDARG);
// Thread Safety
EnterCriticalSection(&g_csDllMain);
// Search the list for cached credentials...
for (pCurrent=g_pCredentialHead; pCurrent!=NULL; pCurrent=pCurrent->pNext) { // Is this It ?
if (lstrcmpi(pContext->pszServer, pCurrent->szServer) == 0) break;
// Save Previous
pPrevious = pCurrent; }
// If we found one and there are no retries...
if (pCurrent) { // If no retries, then use this
if (0 == pCurrent->cRetry) { // Reset pContext ?
SafeMemFree(pContext->pszUserName); SafeMemFree(pContext->pszPassword); SafeMemFree(pContext->pszDomain);
// Duplicate the good stuff
IF_NULLEXIT(pContext->pszUserName = PszDupA((LPSTR)pCurrent->szUserName)); IF_NULLEXIT(pContext->pszDomain = PszDupA((LPSTR)pCurrent->szDomain)); IF_NULLEXIT(pContext->pszPassword = PszDupA((LPSTR)pCurrent->szPassword));
// Increment retry count
pCurrent->cRetry++;
// Thread Safety
LeaveCriticalSection(&g_csDllMain);
// Done
goto exit; }
// Unlink pCurrent from the list
if (pPrevious) { Assert(pPrevious->pNext == pCurrent); pPrevious->pNext = pCurrent->pNext; } else { Assert(g_pCredentialHead == pCurrent); g_pCredentialHead = pCurrent->pNext; } }
// Thread Safety
LeaveCriticalSection(&g_csDllMain);
// Didn't find anything...allocate one
if (NULL == pCurrent) { // Allocate
IF_NULLEXIT(pNew = (LPCREDENTIAL)g_pMalloc->Alloc(sizeof(CREDENTIAL)));
// Zero
ZeroMemory(pNew, sizeof(CREDENTIAL));
// Set pCurrent
pCurrent = pNew;
// Store the Server Name
StrCpyN(pCurrent->szServer, pContext->pszServer, ARRAYSIZE(pCurrent->szServer)); }
// No pNext
pCurrent->pNext = NULL;
// QI pTransport for ITransportCallbackService
hr = pCallback->QueryInterface(IID_ITransportCallbackService, (LPVOID *)&pService); if (FAILED(hr)) { // Raid-69382 (2/5/99): CDO: loop in ISMTPTransport/INNTPTransport when Sicily authentication fails
// Clients who don't support this interface, I will treat them as a cancel.
pContext->fPromptCancel = TRUE; TraceResult(hr); goto exit; }
// Get a Window Handle
hr = pService->GetParentWindow(0, &hwndParent); if (FAILED(hr)) { // Raid-69382 (2/5/99): CDO: loop in ISMTPTransport/INNTPTransport when Sicily authentication fails
// Clients who don't support this interface, I will treat them as a cancel.
pContext->fPromptCancel = TRUE; TraceResult(hr); goto exit; }
// No Parent...
if (NULL == hwndParent || FALSE == IsWindow(hwndParent)) { hr = TraceResult(E_FAIL); goto exit; }
// Bring to the foreground
ShowWindow(hwndParent, SW_SHOW); SetForegroundWindow(hwndParent);
// Clear the password
*pCurrent->szPassword = '\0';
// Initialize Current...
if (pContext->pszUserName) StrCpyN(pCurrent->szUserName, pContext->pszUserName, ARRAYSIZE(pCurrent->szUserName)); if (pContext->pszDomain) StrCpyN(pCurrent->szDomain, pContext->pszDomain, ARRAYSIZE(pCurrent->szDomain));
// Set Logon
Logon.pCredential = pCurrent; Logon.pContext = pContext;
// Do the Dialog Box
if (LOGON_OK != DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(IDD_NTLMPROMPT), hwndParent, GetCredentialDlgProc, (LPARAM)&Logon)) { pContext->fPromptCancel = TRUE; hr = TraceResult(E_FAIL); goto exit; }
// Not cancel
pContext->fPromptCancel = FALSE;
// Reset pContext ?
SafeMemFree(pContext->pszUserName); SafeMemFree(pContext->pszPassword); SafeMemFree(pContext->pszDomain);
// Duplicate the good stuff
IF_NULLEXIT(pContext->pszUserName = PszDupA((LPSTR)pCurrent->szUserName)); IF_NULLEXIT(pContext->pszDomain = PszDupA((LPSTR)pCurrent->szDomain)); IF_NULLEXIT(pContext->pszPassword = PszDupA((LPSTR)pCurrent->szPassword));
// Set Next
pCurrent->pNext = g_pCredentialHead;
// Reset Head
g_pCredentialHead = pCurrent;
// Set Retry Count
pCurrent->cRetry++;
// Don't Free It
pNew = NULL;
exit: // Cleanup
SafeMemFree(pNew); SafeRelease(pService);
// Done
return(hr); }
//--------------------------------------------------------------------------
// SSPIFreeCredentialList
//--------------------------------------------------------------------------
HRESULT SSPIFreeCredentialList(void) { // Locals
LPCREDENTIAL pCurrent; LPCREDENTIAL pNext;
// Trace
TraceCall("SSPIFreeCredentialList");
// Thread Safety
EnterCriticalSection(&g_csDllMain);
// Set pCurrent
pCurrent = g_pCredentialHead;
// While we have a node
while (pCurrent) { // Save pNext
pNext = pCurrent->pNext;
// Free pCurrent
g_pMalloc->Free(pCurrent);
// Goto Next
pCurrent = pNext; }
// Clear the header
g_pCredentialHead = NULL;
// Thread Safety
LeaveCriticalSection(&g_csDllMain);
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// SSPIUninitialize
//--------------------------------------------------------------------------
HRESULT SSPIUninitialize(void) { // Trace
TraceCall("SSPIUninitialize");
// If we have loaded the dll...
if (g_hInstSSPI) { // Free the Lib
FreeLibrary(g_hInstSSPI); }
// Free Credential List
SSPIFreeCredentialList();
// Free Packages
if (g_prgPackage) { // Loop through Packages
for (DWORD i = 0; i < g_cPackages; i++) { // Free pszName
SafeMemFree(g_prgPackage[i].pszName);
// Free pszComment
SafeMemFree(g_prgPackage[i].pszComment); }
// Free packages
SafeMemFree(g_prgPackage);
// No Packages
g_cPackages = 0; }
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// SSPIIsInstalled
//--------------------------------------------------------------------------
HRESULT SSPIIsInstalled(void) { // Locals
HRESULT hr=S_FALSE; INIT_SECURITY_INTERFACE addrProcISI = NULL;
// Trace
TraceCall("SSPIIsInstalled");
// Thread Safety
EnterCriticalSection(&g_csDllMain);
// Already Loaded ?
if (g_hInstSSPI) { hr = S_OK; goto exit; }
// Load Security DLL
if (S_OK == IsPlatformWinNT()) g_hInstSSPI = LoadLibrary(c_szSecurityDLL); else g_hInstSSPI = LoadLibrary(c_szSecur32DLL);
// Could not be loaded
if (NULL == g_hInstSSPI) { TraceInfo("SSPI: LoadLibrary failed."); goto exit; }
// Load the function table
addrProcISI = (INIT_SECURITY_INTERFACE)GetProcAddress(g_hInstSSPI, SECURITY_ENTRYPOINT); if (NULL == addrProcISI) { TraceInfo("SSPI: GetProcAddress failed failed."); goto exit; }
// Get the SSPI function table
g_pFunctions = (*addrProcISI)();
// If the didn't work
if (NULL == g_pFunctions) { // Free the library
FreeLibrary(g_hInstSSPI);
// Null the handle
g_hInstSSPI = NULL;
// Failed to get the function table
TraceInfo("SSPI: Load Function Table failed.");
// Done
goto exit; }
// Woo-hoo
hr = S_OK;
exit: // Thread Safety
LeaveCriticalSection(&g_csDllMain);
// Done
return(hr); }
//--------------------------------------------------------------------------
// SSPIGetPackages
//--------------------------------------------------------------------------
HRESULT SSPIGetPackages(LPSSPIPACKAGE *pprgPackage, LPDWORD pcPackages) { // Locals
SECURITY_STATUS hr=SEC_E_OK; PSecPkgInfo prgPackage=NULL; ULONG i;
// Trace
TraceCall("SSPIGetPackages");
// Check Params
if (NULL == pprgPackage || NULL == pcPackages) return TraceResult(E_INVALIDARG);
// Not Initialized
if (NULL == g_hInstSSPI || NULL == g_pFunctions) return TraceResult(E_UNEXPECTED);
// Init
*pprgPackage = NULL; *pcPackages = 0;
// Already have packages ?
EnterCriticalSection(&g_csDllMain);
// Do I already have the packages ?
if (NULL == g_prgPackage) { // Enumerate security packages
IF_FAILEXIT(hr = (*(g_pFunctions->EnumerateSecurityPackages))(&g_cPackages, &prgPackage));
// RAID - 29645 - EnumerateSecurityPackages seems to return cSec = Rand and pSec == NULL, so, I need to return at this point if cSec == 0 or pSec == NULL
if (0 == g_cPackages || NULL == prgPackage) { hr = TraceResult(E_FAIL); goto exit; }
// Allocate pprgPackage
IF_NULLEXIT(g_prgPackage = (LPSSPIPACKAGE)ZeroAllocate(g_cPackages * sizeof(SSPIPACKAGE)));
// Copy data into ppPackages
for (i = 0; i < g_cPackages; i++) { g_prgPackage[i].ulCapabilities = prgPackage[i].fCapabilities; g_prgPackage[i].wVersion = prgPackage[i].wVersion; g_prgPackage[i].cbMaxToken = prgPackage[i].cbMaxToken; g_prgPackage[i].pszName = PszDupA(prgPackage[i].Name); g_prgPackage[i].pszComment = PszDupA(prgPackage[i].Comment); } }
// Return Global
*pprgPackage = g_prgPackage; *pcPackages = g_cPackages;
exit: // Already have packages ?
LeaveCriticalSection(&g_csDllMain);
// Free the package
if (prgPackage) { // Free the Array
(*(g_pFunctions->FreeContextBuffer))(prgPackage); }
// Done
return(hr); }
//--------------------------------------------------------------------------
// SSPILogon
//--------------------------------------------------------------------------
HRESULT SSPILogon(LPSSPICONTEXT pContext, BOOL fRetry, BOOL fBase64, LPCSTR pszPackage, LPINETSERVER pServer, ITransportCallback *pCallback) { // Locals
SECURITY_STATUS hr = SEC_E_OK; TimeStamp tsLifeTime; SEC_WINNT_AUTH_IDENTITY *pAuth = NULL; SEC_WINNT_AUTH_IDENTITY Auth={0};
// Trace
TraceCall("SSPILogon");
// Validate
Assert(pCallback);
// Invalid Args
if (NULL == pContext || NULL == pszPackage || NULL == pCallback) return TraceResult(E_INVALIDARG);
// Not Initialized
if (NULL == g_hInstSSPI || NULL == g_pFunctions) return TraceResult(E_UNEXPECTED);
// Already have credential
if (pContext->fCredential && SSPI_STATE_USE_CACHED == pContext->tyState) goto exit;
// Installed ?
if (S_FALSE == SSPIIsInstalled()) { hr = TraceResult(IXP_E_LOAD_SICILY_FAILED); goto exit; }
// Reset fPropmtCancel
pContext->fPromptCancel = FALSE;
// No retry
if (NULL == pContext->pCallback) { // Locals
ITransportCallbackService *pService;
// Validate
Assert(!pContext->pszPackage && !pContext->pszServer && !pContext->pCallback && !pContext->pszUserName && !pContext->pszPassword);
// Save fBase64
pContext->fBase64 = fBase64;
// Copy Some Strings
IF_NULLEXIT(pContext->pszPackage = PszDupA(pszPackage)); IF_NULLEXIT(pContext->pszServer = PszDupA(pServer->szServerName)); IF_NULLEXIT(pContext->pszUserName = PszDupA(pServer->szUserName));
// Empty Password
if (FALSE == FIsEmptyA(pServer->szPassword)) { // Copy It
IF_NULLEXIT(pContext->pszPassword = PszDupA(pServer->szPassword)); }
// Assume Callback
pContext->pCallback = pCallback; pContext->pCallback->AddRef();
// Supports Callback Service
if (SUCCEEDED(pContext->pCallback->QueryInterface(IID_ITransportCallbackService, (LPVOID *)&pService))) { // This object supports the Service
pContext->fService = TRUE;
// Release
pService->Release(); }
// Otherwise
else pContext->fService = FALSE; }
// Clear current credential
if (pContext->fCredential) { // Free Credential Handle
(*(g_pFunctions->FreeCredentialHandle))(&pContext->hCredential);
// No Credential
pContext->fCredential = FALSE; }
// Use Cached
if (SSPI_STATE_USE_CACHED == pContext->tyState) { // If not a retry...
if (FALSE == fRetry) { // No Retries
pContext->cRetries = 0;
// Thread Safety
EnterCriticalSection(&g_csDllMain);
// Search the list for cached credentials...
for (LPCREDENTIAL pCurrent=g_pCredentialHead; pCurrent!=NULL; pCurrent=pCurrent->pNext) { // Is this It ?
if (lstrcmpi(pContext->pszServer, pCurrent->szServer) == 0) { pCurrent->cRetry = 0; break; } }
// Thread Safety
LeaveCriticalSection(&g_csDllMain); }
// Otherwise, assume we will need to force a prompt...
else { // Increment Retry Count
pContext->cRetries++;
// Valid Retry States...
Assert(SSPI_STATE_USE_CACHED == pContext->tyRetryState || SSPI_STATE_PROMPT_USE_PACKAGE == pContext->tyRetryState);
// The next phase may be to tell the package to prompt...
pContext->tyState = pContext->tyRetryState; } }
// Use Supplied
else if (SSPI_STATE_USE_SUPPLIED == pContext->tyState) { // Locals
CredHandle hCredential;
// Next State...
pContext->tyState = SSPI_STATE_USE_CACHED;
// Fill It
SSPIFillAuth(NULL, NULL, NULL, &Auth);
// Do some security stuff
if (SUCCEEDED((*(g_pFunctions->AcquireCredentialsHandle))(NULL, (LPSTR)pContext->pszPackage, SECPKG_CRED_OUTBOUND, NULL, &Auth, NULL, NULL, &hCredential, &tsLifeTime))) { // Free the Handle
(*(g_pFunctions->FreeCredentialHandle))(&hCredential); }
// Use Supplied Credentials...
SSPIFillAuth(pContext->pszUserName, pContext->pszPassword, pContext->pszDomain, &Auth);
// Set pAuth
pAuth = &Auth; }
// Otherwise, try to get cached credentials
else if (SSPI_STATE_PROMPT_USE_OWN == pContext->tyState) { // Next State...
pContext->tyState = SSPI_STATE_USE_CACHED;
// Failure
IF_FAILEXIT(hr = SSPIFindCredential(pContext, pCallback));
// Fill and return credentials
SSPIFillAuth(pContext->pszUserName, pContext->pszPassword, pContext->pszDomain, &Auth);
// Set Auth Information
pAuth = &Auth; }
// Do some security stuff
IF_FAILEXIT(hr = (*(g_pFunctions->AcquireCredentialsHandle))(NULL, (LPSTR)pContext->pszPackage, SECPKG_CRED_OUTBOUND, NULL, pAuth, NULL, NULL, &pContext->hCredential, &tsLifeTime));
// We have a credential
pContext->fCredential = TRUE;
exit: // Done
return(hr); }
//--------------------------------------------------------------------------
// SSPIGetNegotiate
//--------------------------------------------------------------------------
HRESULT SSPIGetNegotiate(LPSSPICONTEXT pContext, LPSSPIBUFFER pNegotiate) { // Locals
HRESULT hr=S_OK;
// Trace
TraceCall("SSPIGetNegotiate");
// Invalid Args
if (NULL == pContext || NULL == pNegotiate) return TraceResult(E_INVALIDARG);
// Not Initialized
if (NULL == g_hInstSSPI || NULL == g_pFunctions) return TraceResult(E_UNEXPECTED);
// If the context is currently initialized
if (pContext->fContext) { // Delete this context
(*(g_pFunctions->DeleteSecurityContext))(&pContext->hContext);
// No Context
pContext->fContext = FALSE; }
// Reset this state.
pContext->fUsedSuppliedCreds = FALSE;
// Build Negotiation String
IF_FAILEXIT(hr = SSPIMakeOutboundMessage(pContext, 0, pNegotiate, NULL));
exit: // Done
return(hr); }
//--------------------------------------------------------------------------
// SSPIResponseFromChallenge
//--------------------------------------------------------------------------
HRESULT SSPIResponseFromChallenge(LPSSPICONTEXT pContext, LPSSPIBUFFER pChallenge, LPSSPIBUFFER pResponse) { // Locals
HRESULT hr=S_OK; DWORD nBytesReceived; DWORD dwFlags=0; SecBufferDesc Descript; SecBuffer Buffer[SEC_BUFFER_NUM_EXTENDED_BUFFERS];
// Trace
TraceCall("SSPIResponseFromChallenge");
// Invalid Args
if (NULL == pContext || NULL == pChallenge || NULL == pResponse) return TraceResult(E_INVALIDARG);
// Not Initialized
if (NULL == g_hInstSSPI || NULL == g_pFunctions) return TraceResult(E_UNEXPECTED);
// More Unexpected Stuff
if (FALSE == pContext->fContext || FALSE == pContext->fCredential) return TraceResult(E_UNEXPECTED);
// Decode the Challenge Buffer
IF_FAILEXIT(hr == SSPIDecodeBuffer(pContext->fBase64, pChallenge));
// Fill SecBufferDesc
Descript.ulVersion = 0; Descript.pBuffers = Buffer; Descript.cBuffers = 1;
// Setup the challenge input buffer always (0th buffer)
Buffer[SEC_BUFFER_CHALLENGE_INDEX].pvBuffer = pChallenge->szBuffer; Buffer[SEC_BUFFER_CHALLENGE_INDEX].cbBuffer = pChallenge->cbBuffer - 1; Buffer[SEC_BUFFER_CHALLENGE_INDEX].BufferType = SECBUFFER_TOKEN;
// If Digest
if (FALSE == pContext->fUsedSuppliedCreds && lstrcmpi(pContext->pszPackage, "digest") == 0) { // If we have a user, setup the user buffer (1st buffer)
Buffer[SEC_BUFFER_USERNAME_INDEX].pvBuffer = pContext->pszUserName ? pContext->pszUserName : NULL; Buffer[SEC_BUFFER_USERNAME_INDEX].cbBuffer = pContext->pszUserName ? lstrlen(pContext->pszUserName) : NULL; Buffer[SEC_BUFFER_USERNAME_INDEX].BufferType = SECBUFFER_TOKEN; // If we have a password, setup the password buffer (2nd buffer for
// a total of 3 buffers passed in (challenge + user + pass)
Buffer[SEC_BUFFER_PASSWORD_INDEX].pvBuffer = pContext->pszPassword ? pContext->pszPassword : NULL; Buffer[SEC_BUFFER_PASSWORD_INDEX].cbBuffer = pContext->pszPassword ? lstrlen(pContext->pszPassword) : NULL; Buffer[SEC_BUFFER_PASSWORD_INDEX].BufferType = SECBUFFER_TOKEN;
// If either or both user and pass passed in, set num input buffers to 3 // (SEC_BUFFER_NUM_EXTENDED_BUFFERS)
if (pContext->pszUserName || pContext->pszPassword) Descript.cBuffers = SEC_BUFFER_NUM_EXTENDED_BUFFERS;
// else we're just passing in the one challenge buffer (0th buffer as usual)
else Descript.cBuffers = SEC_BUFFER_NUM_NORMAL_BUFFERS;
// We are supplying creds
pContext->fUsedSuppliedCreds = TRUE;
// Set dwFlags
dwFlags = ISC_REQ_USE_SUPPLIED_CREDS; }
// Prepare for OutMsg
IF_FAILEXIT(hr = SSPIMakeOutboundMessage(pContext, dwFlags, pResponse, &Descript));
exit: // Done
return(hr); }
//--------------------------------------------------------------------------
// SSPIReleaseContext
//--------------------------------------------------------------------------
HRESULT SSPIReleaseContext(LPSSPICONTEXT pContext) { // Was Context Initialized
if (pContext->fContext) { // Delete the Security Context
(*(g_pFunctions->DeleteSecurityContext))(&pContext->hContext);
// No context
pContext->fContext = FALSE; }
// Done
return(S_OK); }
//--------------------------------------------------------------------------
// SSPIFreeContext
//--------------------------------------------------------------------------
HRESULT SSPIFreeContext(LPSSPICONTEXT pContext) { // Locals
SSPICONTEXTSTATE tyState; SSPICONTEXTSTATE tyRetryState; DWORD cRetries;
// Trace
TraceCall("SSPIFreeContext");
// Is the context initialized
if (pContext->fContext) { // Delete It
(*(g_pFunctions->DeleteSecurityContext))(&pContext->hContext);
// No Context
pContext->fContext = FALSE; }
// Credential Handle Initialized
if (pContext->fCredential) { // Free Credential Handle
(*(g_pFunctions->FreeCredentialHandle))(&pContext->hCredential);
// No Context
pContext->fCredential = FALSE; }
// Free Package, Server and Callback
SafeMemFree(pContext->pszPackage); SafeMemFree(pContext->pszUserName); SafeMemFree(pContext->pszPassword); SafeMemFree(pContext->pszServer); SafeRelease(pContext->pCallback);
// Close hMutexUI
if (pContext->hwndLogon) { // Nuke the Window
DestroyWindow(pContext->hwndLogon);
// Null
pContext->hwndLogon = NULL; }
// Save It
tyState = (SSPICONTEXTSTATE)pContext->tyState; tyRetryState = (SSPICONTEXTSTATE)pContext->tyRetryState; cRetries = pContext->cRetries;
// Zero It Out
ZeroMemory(pContext, sizeof(SSPICONTEXT));
// Do Prompt
pContext->tyState = tyState; pContext->tyRetryState = tyRetryState; pContext->cRetries = cRetries;
// Done
return(S_OK); }
// --------------------------------------------------------------------------------
// SSPIPromptThreadEntry
// --------------------------------------------------------------------------------
DWORD SSPIPromptThreadEntry(LPDWORD pdwParam) { // Locals
HRESULT hr=S_OK; LPSSPIPROMPTINFO pPrompt=(LPSSPIPROMPTINFO)pdwParam;
// Trace
TraceCall("SSPIPromptThreadEntry");
// Validate
Assert(pPrompt && pPrompt->pContext);
// Fixup pInDescript
if (pPrompt->pInDescript && pPrompt->pInDescript->cBuffers >= 3 && lstrcmpi(pPrompt->pContext->pszPackage, "digest") == 0) { // Raid-66013: Make sure the password is empty or digest will crash
pPrompt->pInDescript->pBuffers[SEC_BUFFER_PASSWORD_INDEX].pvBuffer = NULL; pPrompt->pInDescript->pBuffers[SEC_BUFFER_PASSWORD_INDEX].cbBuffer = 0; //pPrompt->pInDescript->cBuffers = 2;
}
// Try to get the package to prompt for credentials...
pPrompt->hrResult = (*(g_pFunctions->InitializeSecurityContext))( &pPrompt->pContext->hCredential, pPrompt->phCtxCurrent, pPrompt->pContext->pszServer, pPrompt->dwFlags | ISC_REQ_PROMPT_FOR_CREDS, 0, SECURITY_NATIVE_DREP, pPrompt->pInDescript, 0, &pPrompt->pContext->hContext, pPrompt->pOutDescript, &pPrompt->fContextAttrib, &pPrompt->tsExpireTime);
// Trace
TraceResultSz(pPrompt->hrResult, "SSPIPromptThreadEntry");
// Done
return(0); }
//--------------------------------------------------------------------------
// SSPISetAccountUserName
//--------------------------------------------------------------------------
HRESULT SSPISetAccountUserName(LPCSTR pszName, LPSSPICONTEXT pContext) { // Locals
HRESULT hr=S_OK; DWORD dwServerType; IImnAccount *pAccount=NULL; ITransportCallbackService *pService=NULL;
// Trace
TraceCall("SSPISetAccountUserName");
// Validate Args
Assert(pszName); Assert(pContext); Assert(pContext->pCallback);
// Get ITransportCallbackService
IF_FAILEXIT(hr = pContext->pCallback->QueryInterface(IID_ITransportCallbackService, (LPVOID *)&pService));
// Get the Account
IF_FAILEXIT(hr = pService->GetAccount(&dwServerType, &pAccount));
// SRV_POP3
if (ISFLAGSET(dwServerType, SRV_POP3)) { // Set the UserName
IF_FAILEXIT(hr = pAccount->SetPropSz(AP_POP3_USERNAME, (LPSTR)pszName)); }
// SRV_SMTP
else if (ISFLAGSET(dwServerType, SRV_SMTP)) { // Set the UserName
IF_FAILEXIT(hr = pAccount->SetPropSz(AP_SMTP_USERNAME, (LPSTR)pszName)); }
// SRV_IMAP
else if (ISFLAGSET(dwServerType, SRV_IMAP)) { // Set the UserName
IF_FAILEXIT(hr = pAccount->SetPropSz(AP_IMAP_USERNAME, (LPSTR)pszName)); }
// SRV_NNTP
else if (ISFLAGSET(dwServerType, SRV_NNTP)) { // Set the UserName
IF_FAILEXIT(hr = pAccount->SetPropSz(AP_NNTP_USERNAME, (LPSTR)pszName)); }
// Save Changes
pAccount->SaveChanges();
exit: // Cleanup
SafeRelease(pService); SafeRelease(pAccount);
// Done
return(hr); }
//--------------------------------------------------------------------------
// SSPIMakeOutboundMessage
//--------------------------------------------------------------------------
HRESULT SSPIMakeOutboundMessage(LPSSPICONTEXT pContext, DWORD dwFlags, LPSSPIBUFFER pBuffer, PSecBufferDesc pInDescript) { // Locals
SECURITY_STATUS hr=S_OK; SSPIPROMPTINFO Prompt={0}; SecBuffer OutBuffer; SecBufferDesc OutDescript; ULONG fContextAttrib; TimeStamp tsExpireTime; HANDLE hPromptThread; DWORD dwThreadId; DWORD dwWait; MSG msg; PCtxtHandle phCtxCurrent=NULL; PAUTHENTICATE_MESSAGE pAuthMsg; LPSTR pszName=NULL;
// Invalid Args
if (NULL == pContext || NULL == pBuffer) return TraceResult(E_INVALIDARG);
// Bad Context
if (NULL == pContext->pszPackage) return TraceResult(E_INVALIDARG);
// Bad Context
if (NULL == pContext->pszServer) return TraceResult(E_INVALIDARG);
// Bad Context
if (NULL == pContext->pCallback) return TraceResult(E_INVALIDARG);
// Not Initialized
if (NULL == g_hInstSSPI || NULL == g_pFunctions) return TraceResult(E_UNEXPECTED);
// Bad State
if (FALSE == pContext->fCredential) return TraceResult(E_UNEXPECTED);
// Validate
Assert(pInDescript == NULL ? FALSE == pContext->fContext : TRUE);
// Initialize Out Descriptor
OutDescript.ulVersion = 0; OutDescript.cBuffers = 1; OutDescript.pBuffers = &OutBuffer;
// Initialize Output Buffer
OutBuffer.cbBuffer = CBMAX_SSPI_BUFFER - 1; OutBuffer.BufferType = SECBUFFER_TOKEN; OutBuffer.pvBuffer = pBuffer->szBuffer;
// phCtxCurrent
if (pInDescript) { // Set Current Context
phCtxCurrent = &pContext->hContext; }
// First Retry ?
if (SSPI_STATE_PROMPT_USE_PACKAGE == pContext->tyState && (0 != lstrcmpi(pContext->pszPackage, "digest") || pInDescript)) { // Force failure to do the prompt
hr = SEC_E_NO_CREDENTIALS; }
// Otherwise, do the next security context
else { // Generate a negotiate/authenticate message to be sent to the server.
hr = (*(g_pFunctions->InitializeSecurityContext))(&pContext->hCredential, phCtxCurrent, pContext->pszServer, dwFlags, 0, SECURITY_NATIVE_DREP, pInDescript, 0, &pContext->hContext, &OutDescript, &fContextAttrib, &tsExpireTime); }
// Set Retry State...
pContext->tyRetryState = SSPI_STATE_PROMPT_USE_PACKAGE;
// Failure
if (FAILED(hr)) { // Trace
TraceResult(hr);
// No credentials ? lets do it again and get some credentials
if (SEC_E_NO_CREDENTIALS != hr) goto exit;
// If no retries yet...
if (TRUE == pContext->fService && 0 == lstrcmpi(pContext->pszPackage, "MSN") && 0 == pContext->cRetries) { // Don't retry again...
pContext->tyState = SSPI_STATE_USE_SUPPLIED;
// Do the logon Now...
hr = SSPILogon(pContext, FALSE, pContext->fBase64, pContext->pszPackage, NULL, pContext->pCallback);
// Cancel ?
Assert(FALSE == pContext->fPromptCancel);
// Success
if (SUCCEEDED(hr)) { // Try Again
hr = (*(g_pFunctions->InitializeSecurityContext))(&pContext->hCredential, NULL, pContext->pszServer, 0, 0, SECURITY_NATIVE_DREP, NULL, 0, &pContext->hContext, &OutDescript, &fContextAttrib, &tsExpireTime); } }
// Still Failed ?
if (FAILED(hr)) { // Fill up the prompt info...
Assert(dwFlags == 0 || dwFlags == ISC_REQ_USE_SUPPLIED_CREDS); Prompt.pContext = pContext; Prompt.pInDescript = pInDescript; Prompt.pOutDescript = &OutDescript; Prompt.phCtxCurrent = phCtxCurrent; Prompt.dwFlags = dwFlags;
// Create the Thread
IF_NULLEXIT(hPromptThread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)SSPIPromptThreadEntry, &Prompt, 0, &dwThreadId));
// Wait for the thread to finish
WaitForSingleObject(hPromptThread, INFINITE);
// This is what I tried to do so that the spooler window would paint, but it caused all sorts of voodo
#if 0
// Wait for the thread to finish
while (1) { // Wait
dwWait = MsgWaitForMultipleObjects(1, &hPromptThread, FALSE, INFINITE, QS_PAINT);
// Done ?
if (dwWait != WAIT_OBJECT_0 + 1) break;
// Pump Messages
while (PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_REMOVE)) { // Translate the Message
TranslateMessage(&msg);
// Dispatch the Message
DispatchMessage(&msg); } } #endif
// Close the Thread
CloseHandle(hPromptThread);
// Set hr
hr = Prompt.hrResult;
// If that failed
if (FAILED(hr)) { // Decide when its no longer needed to continue...
if (SEC_E_NO_CREDENTIALS == hr) goto exit;
// Only do this if on negotiate phase otherwise NTLM prompt comes up twice
if (NULL == pInDescript) { // Do Prompt
pContext->tyState = SSPI_STATE_PROMPT_USE_OWN;
// Do the logon Now...
hr = SSPILogon(pContext, TRUE, pContext->fBase64, pContext->pszPackage, NULL, pContext->pCallback);
// Cancel ?
if (pContext->fPromptCancel) { hr = TraceResult(E_FAIL); goto exit; }
// Success
if (SUCCEEDED(hr)) { // Try Again
hr = (*(g_pFunctions->InitializeSecurityContext))(&pContext->hCredential, phCtxCurrent, pContext->pszServer, 0, 0, SECURITY_NATIVE_DREP, pInDescript, 0, &pContext->hContext, &OutDescript, &fContextAttrib, &tsExpireTime); } } } } }
// Success
if (SUCCEEDED(hr)) { // We have a context
pContext->fContext = TRUE;
// If MSN or NTLM...
if (TRUE == pContext->fService && 0 == lstrcmpi(pContext->pszPackage, "MSN")) { // Look at the buffer...
pAuthMsg = (PAUTHENTICATE_MESSAGE)pBuffer->szBuffer;
// Validate Signature
Assert(0 == StrCmpNI((LPCSTR)pAuthMsg->Signature, NTLMSSP_SIGNATURE, sizeof(NTLMSSP_SIGNATURE)));
// Right Phase ?
if (NtLmAuthenticate == pAuthMsg->MessageType) { // Allocate
IF_NULLEXIT(pszName = (LPSTR)g_pMalloc->Alloc(pAuthMsg->UserName.Length + sizeof(CHAR)));
// Copy the name
CopyMemory(pszName, (LPBYTE)pBuffer->szBuffer + PtrToUlong(pAuthMsg->UserName.Buffer), pAuthMsg->UserName.Length);
// Stuff a Null....
pszName[pAuthMsg->UserName.Length] = '\0';
// If Context UserName is empty, lets store pszName into the account
if ('\0' == *pContext->pszUserName) { // Put pszName as the username for this account
if (SUCCEEDED(SSPISetAccountUserName(pszName, pContext))) { // Reset the UserName
SafeMemFree(pContext->pszUserName);
// Copy the new username
IF_NULLEXIT(pContext->pszUserName = PszDupA(pszName)); } }
// Name Change
if (lstrcmpi(pszName, pContext->pszUserName) != 0) { // Don't retry again...
pContext->tyState = SSPI_STATE_USE_SUPPLIED;
// Set Retry State...
pContext->tyRetryState = SSPI_STATE_USE_CACHED;
// Do the logon Now...
hr = SSPILogon(pContext, FALSE, pContext->fBase64, pContext->pszPackage, NULL, pContext->pCallback);
// Cancel ?
Assert(FALSE == pContext->fPromptCancel);
// Success
if (SUCCEEDED(hr)) { // Try Again
hr = (*(g_pFunctions->InitializeSecurityContext))(&pContext->hCredential, NULL, pContext->pszServer, 0, 0, SECURITY_NATIVE_DREP, NULL, 0, &pContext->hContext, &OutDescript, &fContextAttrib, &tsExpireTime); }
// Fail, but continue...
if (FAILED(hr)) { // We are going to need to prompt...
pContext->tyState = SSPI_STATE_PROMPT_USE_PACKAGE;
// Trace
TraceResult(hr);
// Always Succeed, but cause authentication to fail...
hr = S_OK;
// Reset Length
OutBuffer.cbBuffer = 0; } } } } }
// Otherwise...
else { // Trace
TraceResult(hr);
// Always Succeed, but cause authentication to fail...
hr = S_OK;
// Reset Length
OutBuffer.cbBuffer = 0; }
// Continue required
pBuffer->fContinue = (SEC_I_CONTINUE_NEEDED == hr) ? TRUE : FALSE;
// Set cbBuffer
pBuffer->cbBuffer = OutBuffer.cbBuffer + 1;
// Null Terminate
pBuffer->szBuffer[pBuffer->cbBuffer - 1] = '\0';
// need to encode the blob before send out
IF_FAILEXIT(hr == SSPIEncodeBuffer(pContext->fBase64, pBuffer));
// All Good
hr = S_OK;
exit: // Cleanup
SafeMemFree(pszName);
// Done
return(hr); }
//-------------------------------------------------------------------------------------------
// SSPIEncodeBuffer
//-------------------------------------------------------------------------------------------
HRESULT SSPIEncodeBuffer(BOOL fBase64, LPSSPIBUFFER pBuffer) { // Locals
LPBYTE pbIn=(LPBYTE)pBuffer->szBuffer; DWORD cbIn=pBuffer->cbBuffer - 1; BYTE rgbOut[CBMAX_SSPI_BUFFER - 1]; LPBYTE pbOut=rgbOut; DWORD i;
// Trace
TraceCall("SSPIEncodeBuffer");
// Validate
Assert(pBuffer->szBuffer[pBuffer->cbBuffer - 1] == '\0');
// Set the lookup table to use to encode
LPCSTR rgchDict = (fBase64 ? six2base64 : six2uu);
// Loop
for (i = 0; i < cbIn; i += 3) { // Encode
*(pbOut++) = rgchDict[*pbIn >> 2]; *(pbOut++) = rgchDict[((*pbIn << 4) & 060) | ((pbIn[1] >> 4) & 017)]; *(pbOut++) = rgchDict[((pbIn[1] << 2) & 074) | ((pbIn[2] >> 6) & 03)]; *(pbOut++) = rgchDict[pbIn[2] & 077];
// Increment pbIn
pbIn += 3; }
// If nbytes was not a multiple of 3, then we have encoded too many characters. Adjust appropriately.
if (i == cbIn + 1) { // There were only 2 bytes in that last group
pbOut[-1] = '='; }
// There was only 1 byte in that last group
else if (i == cbIn + 2) { pbOut[-1] = '='; pbOut[-2] = '='; }
// Null Terminate
*pbOut = '\0';
// Copy Back into pBuffer
SSPISetBuffer((LPCSTR)rgbOut, SSPI_STRING, 0, pBuffer);
// Done
return(S_OK); }
//-------------------------------------------------------------------------------------------
// SSPIDecodeBuffer
//-------------------------------------------------------------------------------------------
HRESULT SSPIDecodeBuffer(BOOL fBase64, LPSSPIBUFFER pBuffer) { // Locals
LPSTR pszStart=pBuffer->szBuffer; LPBYTE pbIn=(LPBYTE)pBuffer->szBuffer; DWORD cbIn=pBuffer->cbBuffer - 1; BYTE rgbOut[CBMAX_SSPI_BUFFER - 1]; LPBYTE pbOut=rgbOut; DWORD cbOutLeft = ARRAYSIZE(rgbOut)-1; long cbDecode; DWORD cbOut=0;
// Trace
TraceCall("SSPIDecodeBuffer");
// Validate
Assert(pBuffer->szBuffer[pBuffer->cbBuffer - 1] == '\0');
// Set the lookup table to use to encode
const int *rgiDict = (fBase64 ? base642six : uu2six);
// Strip leading whitespace
while (*pszStart == ' ' || *pszStart == '\t') pszStart++;
// Set pbIn
pbIn = (LPBYTE)pszStart;
// Hmmm, I don't know what this does
while (rgiDict[*(pbIn++)] <= 63) {};
// Actual Number of bytes to encode
cbDecode = (long) ((LPBYTE)pbIn - (LPBYTE)pszStart) - 1;
// Computed length of outbound buffer
cbOut = ((cbDecode + 3) / 4) * 3;
// Reset pbIn
pbIn = (LPBYTE)pszStart;
// Decode
while ((cbDecode > 0) && (3 <= cbOutLeft)) { // Decode
*(pbOut++) = (unsigned char) (rgiDict[*pbIn] << 2 | rgiDict[pbIn[1]] >> 4); *(pbOut++) = (unsigned char) (rgiDict[pbIn[1]] << 4 | rgiDict[pbIn[2]] >> 2); *(pbOut++) = (unsigned char) (rgiDict[pbIn[2]] << 6 | rgiDict[pbIn[3]]); cbOutLeft -= 3; Assert((cbDecode <= 0) || (3 <= cbOutLeft)); // If this happens, then cbDecode was calculated incorrectly and we will overflow the buffer.
// Increment pbIn
pbIn += 4;
// Decrement cbDecode
cbDecode -= 4; }
// Special termination case
if (cbDecode & 03) { if (rgiDict[pbIn[-2]] > 63) cbOut -= 2; else cbOut -= 1; }
// Set the Outbuffer
SSPISetBuffer((LPCSTR)rgbOut, SSPI_BLOB, cbOut, pBuffer);
// Done
return(S_OK); }
//-------------------------------------------------------------------------------------------
// SSPIFlushMSNCredentialCache - This code was given to us by kingra/MSN (see csager)
//-------------------------------------------------------------------------------------------
HRESULT SSPIFlushMSNCredentialCache(void) { // Locals
HRESULT hr=S_OK; HKEY hKey=NULL; DWORD dwType; CHAR szDllName[MAX_PATH]; CHAR szProviders[1024]; DWORD cb=ARRAYSIZE(szProviders); HINSTANCE hInstDll=NULL; PFNCLEANUPCREDENTIALCACHE pfnCleanupCredentialCache;
// Open the HKLM Reg Entry
if (ERROR_SUCCESS != RegOpenKeyEx(HKEY_LOCAL_MACHINE, "System\\CurrentControlSet\\Control\\SecurityProviders", 0, KEY_READ, &hKey)) { hr = TraceResult(E_FAIL); goto exit; }
// Read the Providers
if (ERROR_SUCCESS != RegQueryValueEx(hKey, "SecurityProviders", NULL, &dwType, (LPBYTE)szProviders, &cb)) { hr = TraceResult(E_FAIL); goto exit; }
// Upper Case the Providers
CharUpperBuff(szProviders, (DWORD)min(cb,ARRAYSIZE(szProviders)));
// Map to something...
if (StrStrA(szProviders, "MSAPSSPS.DLL")) StrCpyN(szDllName, "MSAPSSPS.DLL", ARRAYSIZE(szDllName)); else if (StrStrA(szProviders, "MSAPSSPC.DLL")) StrCpyN(szDllName, "MSAPSSPC.DLL", ARRAYSIZE(szDllName)); else { hr = TraceResult(E_FAIL); goto exit; }
// Load the DLL
hInstDll = LoadLibrary(szDllName);
// Failed to Load
if (NULL == hInstDll) { hr = TraceResult(E_FAIL); goto exit; }
// Get the ProcAddress
pfnCleanupCredentialCache = (PFNCLEANUPCREDENTIALCACHE)GetProcAddress(hInstDll, "CleanupCredentialCache");
// Failure ?
if (NULL == pfnCleanupCredentialCache) { hr = TraceResult(E_FAIL); goto exit; }
// Call the function that clears the cache
if (!pfnCleanupCredentialCache()) { hr = TraceResult(E_FAIL); goto exit; } exit: // Cleanup
if (hKey) RegCloseKey(hKey); if (hInstDll) FreeLibrary(hInstDll);
// Done
return(hr); }
|