//-------------------------------------------------------------------------- // Sicily.cpp //-------------------------------------------------------------------------- #include "pch.hxx" #include "imnxport.h" #include "sicily.h" #include "dllmain.h" #include "resource.h" #include "imnxport.h" #include "strconst.h" #include #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); }