#include #include #include #include #include #include #define SECURITY_WIN32 #include #include #include #include #include #include #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); } }