You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
493 lines
12 KiB
493 lines
12 KiB
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <stdio.h>
|
|
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
|
|
#define SECURITY_WIN32
|
|
#include <security.h>
|
|
#include <sspi.h>
|
|
#include <ntsecapi.h>
|
|
#include <ntrtl.h>
|
|
#include <schannel.h>
|
|
#include <sslcache.h>
|
|
|
|
#define LIST_CACHE_ENTRIES 1
|
|
#define LIST_ENTRIES_INTERACTIVE 2
|
|
#define PURGE_CACHE_ENTRIES 3
|
|
|
|
DWORD dwOperation = LIST_CACHE_ENTRIES;
|
|
BOOL fIncludeClient = FALSE;
|
|
BOOL fIncludeServer = FALSE;
|
|
BOOL fIncludeMappedEntries = FALSE;
|
|
LPSTR pszServerName = NULL;
|
|
|
|
void
|
|
DisplayCacheInfo(
|
|
HANDLE LsaHandle,
|
|
DWORD PackageNumber,
|
|
BOOL fClient,
|
|
BOOL fServer);
|
|
|
|
void
|
|
PurgeCacheEntries(
|
|
HANDLE LsaHandle,
|
|
DWORD PackageNumber);
|
|
|
|
void
|
|
DisplayCacheInfoInteractive(
|
|
HANDLE LsaHandle,
|
|
DWORD PackageNumber);
|
|
|
|
void Usage(void)
|
|
{
|
|
printf("USAGE: sslcache [ operation ] [ flags ]\n");
|
|
printf("\n");
|
|
printf(" OPERATIONS:\n");
|
|
printf(" -l List cache entries (default)\n");
|
|
printf(" -i List cache entries interactively\n");
|
|
printf(" -p Purge cache entries\n");
|
|
printf("\n");
|
|
printf(" FLAGS:\n");
|
|
printf(" -c Include client entries (default)\n");
|
|
printf(" -s Include server entries\n");
|
|
printf(" -S Include IIS mapped server entries (purge only)\n");
|
|
}
|
|
|
|
void _cdecl main(int argc, char *argv[])
|
|
{
|
|
DWORD Status;
|
|
HANDLE LsaHandle;
|
|
DWORD PackageNumber;
|
|
LSA_STRING PackageName;
|
|
BOOLEAN Trusted = TRUE;
|
|
BOOLEAN WasEnabled;
|
|
STRING Name;
|
|
ULONG Dummy;
|
|
|
|
INT i;
|
|
INT iOption;
|
|
PCHAR pszOption;
|
|
|
|
//
|
|
// Parse user-supplied parameters.
|
|
//
|
|
|
|
for(i = 1; i < argc; i++)
|
|
{
|
|
if(argv[i][0] == '/') argv[i][0] = '-';
|
|
|
|
if(argv[i][0] != '-')
|
|
{
|
|
printf("**** Invalid argument \"%s\"\n", argv[i]);
|
|
Usage();
|
|
return;
|
|
}
|
|
|
|
iOption = argv[i][1];
|
|
pszOption = &argv[i][2];
|
|
|
|
switch(iOption)
|
|
{
|
|
case 'l':
|
|
dwOperation = LIST_CACHE_ENTRIES;
|
|
break;
|
|
|
|
case 'i':
|
|
dwOperation = LIST_ENTRIES_INTERACTIVE;
|
|
break;
|
|
|
|
case 'p':
|
|
dwOperation = PURGE_CACHE_ENTRIES;
|
|
break;
|
|
|
|
case 'c':
|
|
fIncludeClient = TRUE;
|
|
break;
|
|
|
|
case 's':
|
|
if(*pszOption == '\0')
|
|
{
|
|
fIncludeServer = TRUE;
|
|
}
|
|
else
|
|
{
|
|
pszServerName = pszOption;
|
|
fIncludeClient = TRUE;
|
|
}
|
|
break;
|
|
|
|
case 'S':
|
|
fIncludeMappedEntries = TRUE;
|
|
fIncludeServer = TRUE;
|
|
break;
|
|
|
|
default:
|
|
printf("**** Invalid option \"%s\"\n", argv[i]);
|
|
Usage();
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// If neither client nor server was specified by user set appropriate default.
|
|
//
|
|
|
|
if(!fIncludeClient && !fIncludeServer)
|
|
{
|
|
if(dwOperation == PURGE_CACHE_ENTRIES)
|
|
{
|
|
fIncludeClient = TRUE;
|
|
}
|
|
else
|
|
{
|
|
fIncludeClient = TRUE;
|
|
fIncludeServer = TRUE;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Get handle to schannel security package.
|
|
//
|
|
|
|
Status = RtlAdjustPrivilege(SE_TCB_PRIVILEGE, TRUE, FALSE, &WasEnabled);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
Trusted = FALSE;
|
|
}
|
|
RtlInitString(
|
|
&Name,
|
|
"sslcache");
|
|
|
|
if(Trusted)
|
|
{
|
|
Status = LsaRegisterLogonProcess(
|
|
&Name,
|
|
&LsaHandle,
|
|
&Dummy);
|
|
|
|
if(FAILED(Status))
|
|
{
|
|
printf("**** Error 0x%x returned by LsaRegisterLogonProcess\n", Status);
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Status = LsaConnectUntrusted(&LsaHandle);
|
|
|
|
if(FAILED(Status))
|
|
{
|
|
printf("**** Error 0x%x returned by LsaConnectUntrusted\n", Status);
|
|
return;
|
|
}
|
|
}
|
|
|
|
PackageName.Buffer = UNISP_NAME_A;
|
|
PackageName.Length = (USHORT)strlen(PackageName.Buffer);
|
|
PackageName.MaximumLength = PackageName.Length + 1;
|
|
|
|
Status = LsaLookupAuthenticationPackage(
|
|
LsaHandle,
|
|
&PackageName,
|
|
&PackageNumber);
|
|
if(FAILED(Status))
|
|
{
|
|
printf("**** Error 0x%x returned by LsaLookupAuthenticationPackage\n", Status);
|
|
CloseHandle(LsaHandle);
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Perform specified operation.
|
|
//
|
|
|
|
if(dwOperation == LIST_CACHE_ENTRIES)
|
|
{
|
|
printf("\nDISPLAY CACHE ENTRIES\n");
|
|
printf("\n");
|
|
|
|
if(fIncludeClient)
|
|
{
|
|
printf("--CLIENT--\n");
|
|
DisplayCacheInfo(LsaHandle, PackageNumber, TRUE, FALSE);
|
|
}
|
|
|
|
if(fIncludeServer)
|
|
{
|
|
printf("--SERVER--\n");
|
|
DisplayCacheInfo(LsaHandle, PackageNumber, FALSE, TRUE);
|
|
}
|
|
|
|
if(fIncludeClient && fIncludeServer)
|
|
{
|
|
printf("--TOTAL--\n");
|
|
DisplayCacheInfo(LsaHandle, PackageNumber, TRUE, TRUE);
|
|
}
|
|
}
|
|
else if(dwOperation == LIST_ENTRIES_INTERACTIVE)
|
|
{
|
|
DisplayCacheInfoInteractive(LsaHandle, PackageNumber);
|
|
}
|
|
else
|
|
{
|
|
PurgeCacheEntries(LsaHandle, PackageNumber);
|
|
}
|
|
|
|
|
|
CloseHandle(LsaHandle);
|
|
}
|
|
|
|
|
|
void
|
|
PurgeCacheEntries(
|
|
HANDLE LsaHandle,
|
|
DWORD PackageNumber)
|
|
{
|
|
PSSL_PURGE_SESSION_CACHE_REQUEST pRequest;
|
|
DWORD cchServerName;
|
|
DWORD cbServerName;
|
|
DWORD SubStatus;
|
|
DWORD Status;
|
|
|
|
printf("\nPURGE CACHE ENTRIES\n");
|
|
printf("Client:%s\n", fIncludeClient ? "yes" : "no");
|
|
printf("Server:%s\n", fIncludeServer ? "yes" : "no");
|
|
|
|
if(pszServerName == NULL)
|
|
{
|
|
cbServerName = 0;
|
|
|
|
pRequest = (PSSL_PURGE_SESSION_CACHE_REQUEST)LocalAlloc(LPTR, sizeof(SSL_PURGE_SESSION_CACHE_REQUEST));
|
|
if(pRequest == NULL)
|
|
{
|
|
printf("**** Out of memory\n");
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
cchServerName = MultiByteToWideChar(CP_ACP, 0, pszServerName, -1, NULL, 0);
|
|
cbServerName = (cchServerName + 1) * sizeof(WCHAR);
|
|
|
|
pRequest = LocalAlloc(LPTR, sizeof(SSL_PURGE_SESSION_CACHE_REQUEST) + cbServerName);
|
|
if(pRequest == NULL)
|
|
{
|
|
printf("**** Out of memory\n");
|
|
return;
|
|
}
|
|
|
|
cchServerName = MultiByteToWideChar(CP_ACP, 0, pszServerName, -1, (LPWSTR)(pRequest + 1), cchServerName);
|
|
if(cchServerName == 0)
|
|
{
|
|
printf("**** Error converting server name\n");
|
|
return;
|
|
}
|
|
|
|
|
|
pRequest->ServerName.Buffer = (LPWSTR)(pRequest + 1);
|
|
pRequest->ServerName.Length = (WORD)(cchServerName * sizeof(WCHAR));
|
|
pRequest->ServerName.MaximumLength = (WORD)cbServerName;
|
|
}
|
|
|
|
pRequest->MessageType = SslPurgeSessionCacheMessage;
|
|
|
|
if(fIncludeClient)
|
|
{
|
|
pRequest->Flags |= SSL_PURGE_CLIENT_ENTRIES;
|
|
}
|
|
if(fIncludeServer)
|
|
{
|
|
pRequest->Flags |= SSL_PURGE_SERVER_ENTRIES | SSL_PURGE_SERVER_ALL_ENTRIES;
|
|
}
|
|
if(fIncludeMappedEntries)
|
|
{
|
|
pRequest->Flags |= SSL_PURGE_SERVER_ENTRIES_DISCARD_LOCATORS;
|
|
}
|
|
|
|
|
|
Status = LsaCallAuthenticationPackage(
|
|
LsaHandle,
|
|
PackageNumber,
|
|
pRequest,
|
|
sizeof(SSL_PURGE_SESSION_CACHE_REQUEST) + cbServerName,
|
|
NULL,
|
|
NULL,
|
|
&SubStatus);
|
|
if(FAILED(Status))
|
|
{
|
|
printf("**** Error 0x%x returned by LsaCallAuthenticationPackage\n", Status);
|
|
return;
|
|
}
|
|
|
|
if(FAILED(SubStatus))
|
|
{
|
|
if(SubStatus == 0xC0000061)
|
|
{
|
|
printf("**** The TCB privilege is required to perform this operation.\n");
|
|
}
|
|
else
|
|
{
|
|
printf("**** Error 0x%x occurred while purging cache entries.\n", SubStatus);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void
|
|
DisplayCacheInfo(
|
|
HANDLE LsaHandle,
|
|
DWORD PackageNumber,
|
|
BOOL fClient,
|
|
BOOL fServer)
|
|
{
|
|
PSSL_SESSION_CACHE_INFO_REQUEST pRequest = NULL;
|
|
PSSL_SESSION_CACHE_INFO_RESPONSE pResponse = NULL;
|
|
DWORD cbResponse = 0;
|
|
DWORD SubStatus;
|
|
DWORD Status;
|
|
|
|
pRequest = (PSSL_SESSION_CACHE_INFO_REQUEST)LocalAlloc(LPTR, sizeof(SSL_SESSION_CACHE_INFO_REQUEST));
|
|
if(pRequest == NULL)
|
|
{
|
|
printf("**** Out of memory\n");
|
|
goto cleanup;
|
|
}
|
|
|
|
pRequest->MessageType = SslSessionCacheInfoMessage;
|
|
|
|
if(fClient)
|
|
{
|
|
pRequest->Flags |= SSL_RETRIEVE_CLIENT_ENTRIES;
|
|
}
|
|
if(fServer)
|
|
{
|
|
pRequest->Flags |= SSL_RETRIEVE_SERVER_ENTRIES;
|
|
}
|
|
|
|
|
|
Status = LsaCallAuthenticationPackage(
|
|
LsaHandle,
|
|
PackageNumber,
|
|
pRequest,
|
|
sizeof(SSL_SESSION_CACHE_INFO_REQUEST),
|
|
&pResponse,
|
|
&cbResponse,
|
|
&SubStatus);
|
|
if(FAILED(Status))
|
|
{
|
|
printf("**** Error 0x%x returned by LsaCallAuthenticationPackage\n", Status);
|
|
goto cleanup;
|
|
}
|
|
|
|
if(FAILED(SubStatus))
|
|
{
|
|
printf("**** Error 0x%x occurred while reading cache entries.\n", SubStatus);
|
|
}
|
|
|
|
printf("CacheSize: %d \n", pResponse->CacheSize);
|
|
printf("Entries: %d \n", pResponse->Entries);
|
|
printf("ActiveEntries: %d \n", pResponse->ActiveEntries);
|
|
printf("Zombies: %d \n", pResponse->Zombies);
|
|
printf("ExpiredZombies: %d \n", pResponse->ExpiredZombies);
|
|
printf("AbortedZombies: %d \n", pResponse->AbortedZombies);
|
|
printf("DeletedZombies: %d \n", pResponse->DeletedZombies);
|
|
printf("\n");
|
|
|
|
cleanup:
|
|
|
|
if(pRequest)
|
|
{
|
|
LocalFree(pRequest);
|
|
}
|
|
|
|
if (pResponse != NULL)
|
|
{
|
|
LsaFreeReturnBuffer(pResponse);
|
|
}
|
|
}
|
|
|
|
void cls(HANDLE hConsole)
|
|
{
|
|
COORD coordScreen = { 0, 0 }; /* here's where we'll home the
|
|
cursor */
|
|
BOOL bSuccess;
|
|
DWORD cCharsWritten;
|
|
CONSOLE_SCREEN_BUFFER_INFO csbi; /* to get buffer info */
|
|
DWORD dwConSize; /* number of character cells in
|
|
the current buffer */
|
|
|
|
/* get the number of character cells in the current buffer */
|
|
|
|
bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
|
|
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
|
|
|
|
/* fill the entire screen with blanks */
|
|
|
|
bSuccess = FillConsoleOutputCharacter( hConsole, (TCHAR) ' ',
|
|
dwConSize, coordScreen, &cCharsWritten );
|
|
|
|
/* get the current text attribute */
|
|
|
|
bSuccess = GetConsoleScreenBufferInfo( hConsole, &csbi );
|
|
|
|
/* now set the buffer's attributes accordingly */
|
|
|
|
bSuccess = FillConsoleOutputAttribute( hConsole, csbi.wAttributes,
|
|
dwConSize, coordScreen, &cCharsWritten );
|
|
|
|
/* put the cursor at (0, 0) */
|
|
|
|
bSuccess = SetConsoleCursorPosition( hConsole, coordScreen );
|
|
}
|
|
|
|
void home(HANDLE hConsole)
|
|
{
|
|
COORD coordScreen = { 0, 0 }; /* here's where we'll home the
|
|
cursor */
|
|
BOOL bSuccess;
|
|
|
|
/* put the cursor at (0, 0) */
|
|
bSuccess = SetConsoleCursorPosition( hConsole, coordScreen );
|
|
}
|
|
|
|
void
|
|
DisplayCacheInfoInteractive(
|
|
HANDLE LsaHandle,
|
|
DWORD PackageNumber)
|
|
{
|
|
HANDLE hConsoleOut;
|
|
|
|
hConsoleOut = GetStdHandle( STD_OUTPUT_HANDLE );
|
|
|
|
cls(hConsoleOut);
|
|
|
|
while(TRUE)
|
|
{
|
|
home(hConsoleOut);
|
|
|
|
if(fIncludeClient)
|
|
{
|
|
printf("--CLIENT--\n");
|
|
DisplayCacheInfo(LsaHandle, PackageNumber, TRUE, FALSE);
|
|
}
|
|
|
|
if(fIncludeServer)
|
|
{
|
|
printf("--SERVER--\n");
|
|
DisplayCacheInfo(LsaHandle, PackageNumber, FALSE, TRUE);
|
|
}
|
|
|
|
if(fIncludeClient && fIncludeServer)
|
|
{
|
|
printf("--TOTAL--\n");
|
|
DisplayCacheInfo(LsaHandle, PackageNumber, TRUE, TRUE);
|
|
}
|
|
|
|
Sleep(2000);
|
|
}
|
|
}
|