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.
2101 lines
50 KiB
2101 lines
50 KiB
/*--
|
|
|
|
Copyright (c) 1998 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
kerbtray.c
|
|
|
|
Abstract:
|
|
|
|
Displays a dialog with list of Kerberos tickets for the current user.
|
|
|
|
Author:
|
|
|
|
14-Dec-1998 (jbrezak)
|
|
|
|
Environment:
|
|
|
|
User mode only.
|
|
Requires ANSI C extensions: slash-slash comments, long external names.
|
|
|
|
Revision History:
|
|
|
|
12-Apr-2002 JBrezak Cleanup prefast issues and security review.
|
|
|
|
--*/
|
|
|
|
#define UNICODE
|
|
#define _UNICODE
|
|
#define STRICT
|
|
#include <windows.h>
|
|
#include <stdarg.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <shellapi.h>
|
|
#include <shlwapi.h>
|
|
#include <commctrl.h>
|
|
#include <commdlg.h>
|
|
#include <time.h>
|
|
#include <assert.h>
|
|
#include <string.h>
|
|
#include <malloc.h>
|
|
#define SECURITY_WIN32
|
|
#include <security.h>
|
|
#include <ntsecapi.h>
|
|
|
|
#ifndef NO_CRYPTDLL
|
|
#include "cryptdll.h"
|
|
#endif
|
|
#include "kerbtray.h"
|
|
|
|
#define SEC_SUCCESS(Status) ((Status) >= 0)
|
|
#define TSIZE(b) (sizeof(b)/sizeof(TCHAR))
|
|
|
|
#define IDI_FIRST_CLOCK IDI_0_MIN
|
|
#define IDI_LAST_CLOCK IDI_TICKET
|
|
#define MAX_ICONS (IDI_LAST_CLOCK - IDI_FIRST_CLOCK + 1)
|
|
|
|
#define KWIN_UPDATE_PERIOD 60000 // Every 60 seconds update the screen
|
|
|
|
#define PPAGE_NAMES 0
|
|
#define PPAGE_TIMES 1
|
|
#define PPAGE_FLAGS 2
|
|
#define PPAGE_ETYPES 3
|
|
#define C_PAGES 4
|
|
|
|
#define CX_ICON 20
|
|
#define CY_ICON 20
|
|
|
|
#define TPS (10*1000*1000)
|
|
|
|
typedef struct
|
|
{
|
|
HWND hwndTab;
|
|
HWND hwndDisplay;
|
|
RECT rcDisplay;
|
|
DLGTEMPLATE *apRes[C_PAGES];
|
|
PKERB_QUERY_TKT_CACHE_RESPONSE Tickets;
|
|
} DLGTABHDR;
|
|
|
|
OSVERSIONINFO osvers;
|
|
HWND hWnd, hDlgTickets;
|
|
HINSTANCE hInstance;
|
|
HANDLE hModule;
|
|
#define SHORTSTRING 40
|
|
#define LONGSTRING 256
|
|
TCHAR progname[SHORTSTRING];
|
|
ULONG PackageId;
|
|
HANDLE LogonHandle = NULL;
|
|
HWND hWndUsers;
|
|
HIMAGELIST himl;
|
|
HTREEITEM tgt = NULL;
|
|
|
|
static HICON kwin_icons[MAX_ICONS]; // Icons depicting time
|
|
static INT domain_icon;
|
|
static LPCTSTR dt_output_dhms = TEXT("%d %s %02d:%02d:%02d");
|
|
static LPCTSTR dt_day_plural = TEXT("days");
|
|
static LPCTSTR dt_day_singular = TEXT("day");
|
|
static LPCTSTR dt_output_donly = TEXT("%d %s");
|
|
static LPCTSTR dt_output_hms = TEXT("%d:%02d:%02d");
|
|
static LPCTSTR ftime_default_fmt = TEXT("%02d/%02d/%02d %02d:%02d");
|
|
|
|
#define WM_NOTIFY_ICON (WM_APP+100)
|
|
|
|
#ifndef NO_CRYPTDLL
|
|
typedef NTSTATUS (NTAPI *CDLOCATECSYSTEM)(ULONG dwEtype, PCRYPTO_SYSTEM * ppcsSystem);
|
|
|
|
CDLOCATECSYSTEM pCDLocateCSystem;
|
|
#endif
|
|
|
|
LRESULT CALLBACK MainWndProc(HWND, UINT, WPARAM, LPARAM);
|
|
LRESULT CALLBACK AboutProc(HWND, UINT, WPARAM, LPARAM);
|
|
LRESULT CALLBACK TicketsProc(HWND, UINT, WPARAM, LPARAM);
|
|
void About(void);
|
|
void Tickets(void);
|
|
void PurgeCache(void);
|
|
void PropsheetDisplay(HWND hDlg);
|
|
void SelectTicket(HWND hDlg);
|
|
void FillinTicket(HWND hDlg);
|
|
LPTSTR etype_string(int enctype);
|
|
LPTSTR GetStringRes(int);
|
|
|
|
#ifdef DEBUG
|
|
#define DPRINTF(s) dprintf s
|
|
|
|
int debug = 1;
|
|
|
|
void dprintf(LPCTSTR fmt, ...)
|
|
{
|
|
TCHAR szTemp[512];
|
|
va_list ap;
|
|
|
|
if (!debug)
|
|
return;
|
|
|
|
va_start (ap, fmt);
|
|
#ifdef UNICODE
|
|
_vsnwprintf(szTemp, TSIZE(szTemp), fmt, ap);
|
|
#else
|
|
_vsnprintf(szTemp, TSIZE(szTemp), fmt, ap);
|
|
#endif
|
|
szTemp[TSIZE(szTemp)-1] = 0;
|
|
|
|
OutputDebugString(szTemp);
|
|
va_end (ap);
|
|
}
|
|
#else
|
|
#define DPRINTF(s)
|
|
#endif
|
|
|
|
void
|
|
ShowMessage(int level, LPCTSTR msg)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
if (level)
|
|
MessageBeep(level);
|
|
MessageBox(NULL, msg, progname,
|
|
level | MB_OK | MB_TASKMODAL | MB_SETFOREGROUND);
|
|
}
|
|
|
|
void
|
|
Error(LPCTSTR fmt, ...)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
TCHAR szTemp[512];
|
|
|
|
va_list ap;
|
|
va_start (ap, fmt);
|
|
#ifdef UNICODE
|
|
_vsnwprintf(szTemp, TSIZE(szTemp), fmt, ap);
|
|
#else
|
|
_vsnprintf(szTemp, TSIZE(szTemp), fmt, ap);
|
|
#endif
|
|
szTemp[TSIZE(szTemp)-1] = 0;
|
|
|
|
OutputDebugString(szTemp);
|
|
ShowMessage(MB_ICONINFORMATION, szTemp);
|
|
va_end (ap);
|
|
}
|
|
|
|
void
|
|
ErrorExit(LPCTSTR lpszMessage)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
MessageBox(hWnd, lpszMessage, TEXT("Error"), MB_OK);
|
|
ExitProcess(0);
|
|
}
|
|
|
|
int
|
|
GetIconIndex(long dt)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
int ixicon;
|
|
|
|
dt = dt / 60; // convert to minutes
|
|
if (dt <= 0)
|
|
ixicon = IDI_EXPIRED - IDI_FIRST_CLOCK;
|
|
else if (dt > 60)
|
|
ixicon = IDI_TICKET - IDI_FIRST_CLOCK;
|
|
else
|
|
ixicon = (int)(dt / 5);
|
|
|
|
return ixicon;
|
|
}
|
|
|
|
void
|
|
SetTray(
|
|
HWND hwnd,
|
|
HICON hIcon,
|
|
LPCTSTR tip
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Activate or update the tray icon
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
static tray_inited = 0;
|
|
NOTIFYICONDATA tnd;
|
|
|
|
tnd.cbSize = sizeof(NOTIFYICONDATA);
|
|
tnd.hWnd = hwnd;
|
|
tnd.uID = IDI_KDC;
|
|
tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
|
|
tnd.uCallbackMessage = WM_NOTIFY_ICON;
|
|
tnd.hIcon = hIcon;
|
|
|
|
StrNCpy(tnd.szTip, tip, TSIZE(tnd.szTip));
|
|
|
|
Shell_NotifyIcon((tray_inited)?NIM_MODIFY:NIM_ADD, &tnd);
|
|
|
|
if (tray_inited == 0)
|
|
tray_inited++;
|
|
|
|
DestroyIcon(tnd.hIcon);
|
|
}
|
|
|
|
void
|
|
DeleteTray(HWND hwnd)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Remove the tray icon
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
NOTIFYICONDATA tnd;
|
|
|
|
tnd.cbSize = sizeof(NOTIFYICONDATA);
|
|
tnd.hWnd = hwnd;
|
|
tnd.uID = IDI_KDC;
|
|
tnd.uFlags = NIF_MESSAGE|NIF_ICON|NIF_TIP;
|
|
tnd.uCallbackMessage = WM_NOTIFY_ICON;
|
|
tnd.hIcon = NULL;
|
|
tnd.szTip[0] = '\0';
|
|
|
|
Shell_NotifyIcon(NIM_DELETE, &tnd);
|
|
}
|
|
|
|
BOOL
|
|
UpdateTray(HWND hwnd)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Update the tray icon based on the time to live of the TGT
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HICON hicon;
|
|
TCHAR buf[SHORTSTRING];
|
|
BOOL expired = FALSE;
|
|
NTSTATUS Status, SubStatus;
|
|
KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
|
|
PKERB_RETRIEVE_TKT_RESPONSE TicketEntry = NULL;
|
|
PKERB_EXTERNAL_TICKET Ticket;
|
|
ULONG ResponseSize;
|
|
FILETIME CurrentFileTime;
|
|
LARGE_INTEGER Quad;
|
|
long dt = 0L;
|
|
int days, hours, minutes, seconds;
|
|
DWORD tt;
|
|
TCHAR buf2[SHORTSTRING];
|
|
|
|
StrNCpy(buf, progname, TSIZE(buf));
|
|
|
|
//
|
|
// Get the TGT from the ticket cache
|
|
//
|
|
CacheRequest.MessageType = KerbRetrieveTicketMessage;
|
|
CacheRequest.LogonId.LowPart = 0;
|
|
CacheRequest.LogonId.HighPart = 0;
|
|
|
|
Status = LsaCallAuthenticationPackage(LogonHandle,
|
|
PackageId,
|
|
&CacheRequest,
|
|
sizeof(CacheRequest),
|
|
(PVOID *) &TicketEntry,
|
|
&ResponseSize,
|
|
&SubStatus);
|
|
|
|
//
|
|
// If no TGT, display the correct icon
|
|
//
|
|
if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) {
|
|
hicon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_KDC));
|
|
StrCatBuff(buf, GetStringRes(IDS_NO_CREDS), TSIZE(buf));
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Select the correct icon based on the time left of the TGT
|
|
//
|
|
Ticket = &(TicketEntry->Ticket);
|
|
|
|
GetSystemTimeAsFileTime(&CurrentFileTime);
|
|
|
|
Quad.LowPart = CurrentFileTime.dwLowDateTime;
|
|
Quad.HighPart = CurrentFileTime.dwHighDateTime;
|
|
|
|
dt = (long)((Ticket->EndTime.QuadPart - Quad.QuadPart) / TPS);
|
|
|
|
LsaFreeReturnBuffer(TicketEntry);
|
|
|
|
hicon = kwin_icons[GetIconIndex(dt)];
|
|
|
|
StrCatBuff(buf, TEXT(" - "), TSIZE(buf));
|
|
|
|
if (dt <= 0) {
|
|
StrCatBuff(buf, GetStringRes(IDS_EXPIRED), TSIZE(buf));
|
|
expired = TRUE;
|
|
}
|
|
else {
|
|
|
|
days = (int) (dt / (24*3600l));
|
|
tt = dt % (24*3600l);
|
|
hours = (int) (tt / 3600);
|
|
tt %= 3600;
|
|
minutes = (int) (tt / 60);
|
|
seconds = (int) (tt % 60);
|
|
|
|
if (days) {
|
|
if (hours || minutes || seconds) {
|
|
_snwprintf(buf2, TSIZE(buf2), dt_output_dhms, days,
|
|
(days > 1) ? dt_day_plural : dt_day_singular,
|
|
hours, minutes, seconds);
|
|
}
|
|
else {
|
|
_snwprintf(buf2, TSIZE(buf2), dt_output_donly, days,
|
|
(days > 1) ? dt_day_plural : dt_day_singular);
|
|
}
|
|
}
|
|
else {
|
|
_snwprintf(buf2, TSIZE(buf2), dt_output_hms,
|
|
hours, minutes, seconds);
|
|
}
|
|
_snwprintf(buf, TSIZE(buf), TEXT("%s %s"), progname, buf2);
|
|
}
|
|
}
|
|
|
|
SetTray(hwnd, hicon, buf);
|
|
return(expired);
|
|
}
|
|
|
|
|
|
BOOL
|
|
InitializeApp(
|
|
HANDLE hInstance,
|
|
int nCmdShow
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
LSA_STRING Name;
|
|
NTSTATUS Status;
|
|
WNDCLASSEX wc;
|
|
HWND hwnd;
|
|
int i;
|
|
|
|
//
|
|
// Check for an existing instance
|
|
//
|
|
hwnd = FindWindow(TEXT("MainWindowClass"), TEXT("KerbTray"));
|
|
if (hwnd) {
|
|
//
|
|
// Popup the tickets dialog, if one found
|
|
// Run only one instance of kerbtray
|
|
//
|
|
SendMessage(hwnd, WM_NOTIFY_ICON, 0, WM_LBUTTONDBLCLK);
|
|
ExitProcess(0);
|
|
}
|
|
|
|
hModule = GetModuleHandle(NULL);
|
|
|
|
InitCommonControls();
|
|
|
|
LoadString(hInstance, IDS_KRB5_NAME, progname, TSIZE(progname));
|
|
|
|
//
|
|
// Setup connection for LSA to Kerberos package
|
|
//
|
|
Status = LsaConnectUntrusted(&LogonHandle);
|
|
if (!SEC_SUCCESS(Status)) {
|
|
Error(TEXT("Failed to register as a logon process: 0x%x"), Status);
|
|
return FALSE;
|
|
}
|
|
|
|
Name.Buffer = MICROSOFT_KERBEROS_NAME_A;
|
|
Name.Length = (USHORT) strlen(Name.Buffer);
|
|
Name.MaximumLength = Name.Length + 1;
|
|
|
|
Status = LsaLookupAuthenticationPackage(
|
|
LogonHandle,
|
|
&Name,
|
|
&PackageId
|
|
);
|
|
if (!SEC_SUCCESS(Status)){
|
|
printf("Failed to lookup package %Z: 0x%x\n",&Name, Status);
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create the image list.
|
|
//
|
|
if ((himl = ImageList_Create(CX_ICON, CY_ICON, ILC_COLOR, MAX_ICONS, 0)) == NULL)
|
|
return FALSE;
|
|
|
|
ImageList_SetBkColor(himl, CLR_NONE);
|
|
|
|
for (i = IDI_FIRST_CLOCK; i <= IDI_LAST_CLOCK; i++) {
|
|
#ifndef COLOR_ICONS
|
|
kwin_icons[i - IDI_FIRST_CLOCK] = LoadIcon(hInstance,
|
|
MAKEINTRESOURCE(i));
|
|
#else
|
|
kwin_icons[i - IDI_FIRST_CLOCK] = LoadImage(hInstance,
|
|
MAKEINTRESOURCE(i),
|
|
IMAGE_ICON, 0, 0,
|
|
LR_DEFAULTCOLOR|LR_DEFAULTSIZE|LR_LOADTRANSPARENT|LR_LOADMAP3DCOLORS);
|
|
#endif
|
|
(void) ImageList_AddIcon(himl, kwin_icons[i - IDI_FIRST_CLOCK]);
|
|
}
|
|
|
|
#ifndef COLOR_ICONS
|
|
domain_icon = ImageList_AddIcon(himl,
|
|
LoadIcon(hInstance, MAKEINTRESOURCE(IDI_DOMAIN)));
|
|
#else
|
|
domain_icon = ImageList_AddIcon(himl,
|
|
LoadImage(hInstance, MAKEINTRESOURCE(IDI_DOMAIN),
|
|
IMAGE_ICON, 0, 0,
|
|
LR_DEFAULTCOLOR|LR_DEFAULTSIZE|LR_LOADTRANSPARENT|LR_LOADMAP3DCOLORS));
|
|
#endif
|
|
|
|
//
|
|
// Register a window class for the main window.
|
|
//
|
|
wc.cbSize = sizeof(WNDCLASSEX);
|
|
wc.style = CS_HREDRAW|CS_VREDRAW;
|
|
wc.lpfnWndProc = MainWndProc;
|
|
wc.cbClsExtra = 0;
|
|
wc.cbWndExtra = 0;
|
|
wc.hInstance = hInstance;
|
|
wc.hIcon = LoadIcon(hModule, MAKEINTRESOURCE(IDI_EXPIRED));
|
|
wc.hIconSm = LoadIcon(hModule, MAKEINTRESOURCE(IDI_EXPIRED));
|
|
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
|
|
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
|
|
wc.lpszMenuName = 0;
|
|
wc.lpszClassName = TEXT("MainWindowClass");
|
|
|
|
if (!RegisterClassEx(&wc)) {
|
|
Error(TEXT("RegisterClassEx failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
//
|
|
// Create the main window
|
|
//
|
|
hWnd = CreateWindowEx(WS_EX_APPWINDOW,
|
|
TEXT("MainWindowClass"),
|
|
TEXT("KerbTray"),
|
|
WS_OVERLAPPEDWINDOW,
|
|
0, 0,
|
|
5, 5,
|
|
NULL,
|
|
NULL,
|
|
hModule,
|
|
NULL);
|
|
if (hWnd == NULL) {
|
|
Error(TEXT("CreateWindowEx failed"));
|
|
return FALSE;
|
|
}
|
|
|
|
ShowWindow(hWnd, SW_HIDE);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
int WINAPI
|
|
WinMain(
|
|
HINSTANCE hInst,
|
|
HINSTANCE hPrevInst,
|
|
LPSTR lpszCmdLn,
|
|
int nShowCmd
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
MSG msg;
|
|
HANDLE hAccelTable, hCryptDll;
|
|
|
|
hInstance = hInst;
|
|
hModule = GetModuleHandle(NULL);
|
|
|
|
osvers.dwOSVersionInfoSize = sizeof(osvers);
|
|
GetVersionEx(&osvers);
|
|
|
|
#ifndef NO_CRYPTDLL
|
|
hCryptDll = LoadLibrary(TEXT("CRYPTDLL.DLL"));
|
|
if (!hCryptDll)
|
|
ErrorExit(TEXT("Unable to load cryptdll.dll"));
|
|
|
|
pCDLocateCSystem = (CDLOCATECSYSTEM) GetProcAddress(hCryptDll, "CDLocateCSystem");
|
|
if (!pCDLocateCSystem)
|
|
ErrorExit(TEXT("Unable to link cryptdll.dll::CDLocateCSystem"));
|
|
#endif
|
|
|
|
if (! InitializeApp(hInst, nShowCmd))
|
|
ErrorExit(TEXT("InitializeApp failure"));
|
|
|
|
hAccelTable = LoadAccelerators(hInst, TEXT("KerbTray"));
|
|
|
|
while (GetMessage(&msg, NULL, 0, 0)) {
|
|
if (!IsDialogMessage(hDlgTickets, &msg)) {
|
|
if (!TranslateAccelerator (msg.hwnd, hAccelTable, &msg)) {
|
|
TranslateMessage(&msg);
|
|
DispatchMessage(&msg);
|
|
}
|
|
}
|
|
}
|
|
return 1;
|
|
|
|
UNREFERENCED_PARAMETER(hPrevInst);
|
|
UNREFERENCED_PARAMETER(lpszCmdLn);
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
MainWndProc(HWND hwnd, UINT uiMessage, WPARAM wParam, LPARAM lParam)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
POINT pos;
|
|
static HMENU hPopupMenu;
|
|
|
|
switch (uiMessage) {
|
|
|
|
//
|
|
// Someone clicked the icon
|
|
//
|
|
case WM_NOTIFY_ICON:
|
|
switch (lParam) {
|
|
|
|
case WM_LBUTTONDBLCLK:
|
|
Tickets();
|
|
return 0L;
|
|
|
|
case WM_RBUTTONDOWN:
|
|
if (hPopupMenu) {
|
|
if (GetCursorPos(&pos)) {
|
|
if (TrackPopupMenu(hPopupMenu,
|
|
TPM_RIGHTALIGN|TPM_LEFTBUTTON,
|
|
pos.x, pos.y,
|
|
0, hwnd, NULL) == 0)
|
|
Error(TEXT("TrackPopupMenuFailed: 0x%x"),
|
|
GetLastError());
|
|
}
|
|
}
|
|
return 0L;
|
|
}
|
|
break;
|
|
|
|
//
|
|
// Create a client windows
|
|
//
|
|
case WM_CREATE:
|
|
hPopupMenu = LoadMenu(hInstance, MAKEINTRESOURCE(IDR_MENU));
|
|
if (!hPopupMenu)
|
|
Error(TEXT("LoadMenu failed %d"), GetLastError());
|
|
|
|
hPopupMenu = GetSubMenu(hPopupMenu, 0);
|
|
if (!hPopupMenu)
|
|
Error(TEXT("LoadMenu failed %d"), GetLastError());
|
|
|
|
(void) UpdateTray(hwnd);
|
|
|
|
//
|
|
// Start timer for watching the TGT
|
|
//
|
|
if (!SetTimer(hwnd, 1, KWIN_UPDATE_PERIOD, NULL)) {
|
|
ErrorExit(TEXT("SetTimer failed"));
|
|
}
|
|
return 0L;
|
|
|
|
|
|
//
|
|
// Update the tray icon
|
|
//
|
|
case WM_TIMER:
|
|
(void) UpdateTray(hwnd);
|
|
return(0L);
|
|
|
|
case WM_ENDSESSION:
|
|
return(0L);
|
|
|
|
//
|
|
// Close the main window. First set fKillAll to TRUE to
|
|
// terminate all threads. Then wait for the threads to exit
|
|
// before passing a close message to a default handler. If you
|
|
// don't wait for threads to terminate, process terminates
|
|
// with no chance for thread cleanup.
|
|
//
|
|
case WM_CLOSE:
|
|
exit:;
|
|
{
|
|
DeleteTray(hWnd);
|
|
KillTimer(hWnd, 1);
|
|
PostQuitMessage(0);
|
|
return 0L;
|
|
}
|
|
|
|
//
|
|
// Terminate the process
|
|
//
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
return 0L;
|
|
|
|
|
|
//
|
|
// Handle the menu commands
|
|
//
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case ID_ABOUT:
|
|
About();
|
|
return 0L;
|
|
|
|
case ID_TICKETS:
|
|
Tickets();
|
|
return 0L;
|
|
|
|
case ID_PURGE:
|
|
PurgeCache();
|
|
return 0L;
|
|
|
|
case ID_EXIT:
|
|
goto exit;
|
|
}
|
|
}
|
|
return DefWindowProc(hwnd, uiMessage, wParam, lParam);
|
|
}
|
|
|
|
|
|
LPTSTR
|
|
GetStringRes(int id)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Load a string from the resources
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
static TCHAR buffer[MAX_PATH];
|
|
|
|
buffer[0] = 0;
|
|
LoadString(GetModuleHandle (NULL), id, buffer, MAX_PATH);
|
|
return buffer;
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
AboutProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
static HFONT hfontDlg; // Font for dialog text
|
|
DWORD dwVerInfoSize; // Size of version information block
|
|
LPTSTR lpVersion; // String pointer to 'version' text
|
|
DWORD dwVerHnd = 0; // An 'ignored' parameter, always '0'
|
|
UINT uVersionLen;
|
|
DWORD wRootLen;
|
|
BOOL bRetCode;
|
|
int i;
|
|
TCHAR szFullPath[LONGSTRING];
|
|
TCHAR szResult[LONGSTRING];
|
|
TCHAR szGetName[LONGSTRING];
|
|
TCHAR szVersion[SHORTSTRING];
|
|
DWORD dwResult;
|
|
int resmap[6] = {
|
|
IDC_COMPANY,
|
|
IDC_FILEDESC,
|
|
IDC_PRODVER,
|
|
IDC_COPYRIGHT,
|
|
IDC_OSVERSION,
|
|
};
|
|
LPSTR lpstrVffInfo;
|
|
HANDLE hMem;
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
ShowWindow(hDlg, SW_HIDE);
|
|
hfontDlg = CreateFont(14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
VARIABLE_PITCH | FF_SWISS, TEXT(""));
|
|
GetModuleFileName(hInstance, szFullPath, TSIZE(szFullPath));
|
|
szFullPath[TSIZE(szFullPath) - 1] = 0;
|
|
|
|
//
|
|
// Now lets dive in and pull out the version information:
|
|
//
|
|
dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd);
|
|
if (dwVerInfoSize) {
|
|
|
|
hMem = GlobalAlloc(GMEM_MOVEABLE, dwVerInfoSize);
|
|
|
|
if (!hMem) {
|
|
ErrorExit(TEXT("Unable to allocate memory"));
|
|
}
|
|
lpstrVffInfo = GlobalLock(hMem);
|
|
if (!lpstrVffInfo) {
|
|
ErrorExit(TEXT("Unable to lock memory"));
|
|
}
|
|
|
|
GetFileVersionInfo(szFullPath, dwVerHnd, dwVerInfoSize, lpstrVffInfo);
|
|
//
|
|
// The below 'hex' value looks a little confusing, but
|
|
// essentially what it is, is the hexidecimal representation
|
|
// of a couple different values that represent the language
|
|
// and character set that we are wanting string values for.
|
|
// 040904E4 is a very common one, because it means:
|
|
// US English, Windows MultiLingual characterset
|
|
// Or to pull it all apart:
|
|
// 04------ = SUBLANG_ENGLISH_USA
|
|
// --09---- = LANG_ENGLISH
|
|
// ----04E4 = 1252 = Codepage for Windows:Multilingual
|
|
//
|
|
StrNCpy(szGetName, GetStringRes(IDS_VER_INFO_LANG), TSIZE(szGetName));
|
|
|
|
wRootLen = lstrlen(szGetName); // Save this position
|
|
|
|
//
|
|
// Set the title of the dialog
|
|
//
|
|
StrCatBuff(szGetName, TEXT("ProductName"), TSIZE(szGetName));
|
|
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
|
|
(LPTSTR)szGetName,
|
|
(LPVOID)&lpVersion,
|
|
(UINT *)&uVersionLen);
|
|
StrNCpy(szResult, TEXT("About "), TSIZE(szResult));
|
|
StrCatBuff(szResult, lpVersion, TSIZE(szResult));
|
|
SetWindowText(hDlg, szResult);
|
|
|
|
//
|
|
// Walk through the dialog items that we want to replace
|
|
//
|
|
for (i = 0; i < 6; i++) {
|
|
GetDlgItemText(hDlg, resmap[i], szResult, TSIZE(szResult));
|
|
szGetName[wRootLen] = TEXT('\0');
|
|
StrCatBuff(szGetName, szResult, TSIZE(szGetName));
|
|
uVersionLen = 0;
|
|
lpVersion = NULL;
|
|
bRetCode = VerQueryValue((LPVOID)lpstrVffInfo,
|
|
(LPTSTR)szGetName,
|
|
(LPVOID)&lpVersion,
|
|
(UINT *)&uVersionLen);
|
|
|
|
if ( bRetCode && uVersionLen && lpVersion) {
|
|
// Replace dialog item text with version info
|
|
StrNCpy(szResult, lpVersion, TSIZE(szResult));
|
|
SetDlgItemText(hDlg, resmap[i], szResult);
|
|
} else {
|
|
dwResult = GetLastError();
|
|
_snwprintf(szResult, TSIZE(szResult),
|
|
TEXT("Error %lu"), dwResult);
|
|
SetDlgItemText (hDlg, resmap[i], szResult);
|
|
}
|
|
SendMessage(GetDlgItem(hDlg, resmap[i]), WM_SETFONT,
|
|
(WPARAM)hfontDlg,
|
|
TRUE);
|
|
}
|
|
GlobalUnlock(hMem);
|
|
GlobalFree(hMem);
|
|
|
|
}
|
|
else {
|
|
|
|
// No version information available
|
|
}
|
|
|
|
SendMessage(GetDlgItem (hDlg, IDC_LABEL), WM_SETFONT,
|
|
(WPARAM)hfontDlg,(LPARAM)TRUE);
|
|
|
|
_snwprintf(szVersion, TSIZE(szVersion),
|
|
TEXT("Microsoft Windows %u.%u (Build: %u)"),
|
|
osvers.dwMajorVersion,
|
|
osvers.dwMinorVersion,
|
|
osvers.dwBuildNumber);
|
|
|
|
szVersion[SHORTSTRING - 1] = 0;
|
|
|
|
SetWindowText(GetDlgItem(hDlg, IDC_OSVERSION), szVersion);
|
|
ShowWindow(hDlg, SW_SHOW);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam)) {
|
|
case IDOK:
|
|
case IDCANCEL:
|
|
EndDialog(hDlg, 0);
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
About(void)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DialogBox(hInstance, MAKEINTRESOURCE(IDD_ABOUT), hWnd, AboutProc);
|
|
}
|
|
|
|
#define CheckDlgButtonFlag(b, f) \
|
|
CheckDlgButton(hDlg, b, (flags & f)?BST_CHECKED:BST_UNCHECKED)
|
|
|
|
VOID
|
|
ShowFlags(HWND hDlg, ULONG flags)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
CheckDlgButtonFlag(IDC_FORWARDABLE, KERB_TICKET_FLAGS_forwardable);
|
|
CheckDlgButtonFlag(IDC_FORWARDED, KERB_TICKET_FLAGS_forwarded);
|
|
CheckDlgButtonFlag(IDC_PROXIABLE, KERB_TICKET_FLAGS_proxiable);
|
|
CheckDlgButtonFlag(IDC_PROXY, KERB_TICKET_FLAGS_proxy);
|
|
CheckDlgButtonFlag(IDC_MAY_POSTDATE, KERB_TICKET_FLAGS_may_postdate);
|
|
CheckDlgButtonFlag(IDC_POSTDATED, KERB_TICKET_FLAGS_postdated);
|
|
CheckDlgButtonFlag(IDC_INVALID, KERB_TICKET_FLAGS_invalid);
|
|
CheckDlgButtonFlag(IDC_RENEWABLE, KERB_TICKET_FLAGS_renewable);
|
|
CheckDlgButtonFlag(IDC_INITIAL, KERB_TICKET_FLAGS_initial);
|
|
CheckDlgButtonFlag(IDC_HWAUTH, KERB_TICKET_FLAGS_hw_authent);
|
|
CheckDlgButtonFlag(IDC_PREAUTH, KERB_TICKET_FLAGS_pre_authent);
|
|
CheckDlgButtonFlag(IDC_OK_AS_DELEGATE, KERB_TICKET_FLAGS_ok_as_delegate);
|
|
}
|
|
|
|
LPTSTR
|
|
ETypeString(
|
|
int enctype
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
#ifndef NO_CRYPTDLL
|
|
static PCRYPTO_SYSTEM pcsSystem;
|
|
static TCHAR buf[12] = {0};
|
|
|
|
if (pCDLocateCSystem(enctype, &pcsSystem) == S_OK)
|
|
return pcsSystem->Name;
|
|
else {
|
|
_snwprintf(buf, TSIZE(buf), TEXT("etype %d"), enctype);
|
|
buf[11] = 0;
|
|
return buf;
|
|
}
|
|
#else
|
|
static TCHAR buf[12];
|
|
|
|
switch (enctype) {
|
|
case KERB_ETYPE_NULL:
|
|
return TEXT("NULL");
|
|
break;
|
|
case KERB_ETYPE_DES_CBC_CRC:
|
|
return TEXT("Kerberos DES-CBC-CRC");
|
|
break;
|
|
case KERB_ETYPE_DES_CBC_MD5:
|
|
return TEXT("Kerberos DES-CBC-MD5");
|
|
break;
|
|
case KERB_ETYPE_RC4_MD4:
|
|
return TEXT("RSADSI RC4-MD4");
|
|
break;
|
|
case KERB_ETYPE_RC4_PLAIN2:
|
|
return TEXT("RSADSI RC4-PLAIN");
|
|
break;
|
|
case KERB_ETYPE_RC4_LM:
|
|
return TEXT("RSADSI RC4-LM");
|
|
break;
|
|
case KERB_ETYPE_DES_PLAIN:
|
|
return TEXT("Kerberos DES-Plain");
|
|
break;
|
|
#ifdef KERB_ETYPE_RC4_HMAC
|
|
case KERB_ETYPE_RC4_HMAC:
|
|
return TEXT("RSADSI RC4-HMAC");
|
|
break;
|
|
#endif
|
|
case KERB_ETYPE_RC4_PLAIN:
|
|
return TEXT("RSADSI RC4");
|
|
break;
|
|
#ifdef KERB_ETYPE_RC4_HMAC_EXP
|
|
case KERB_ETYPE_RC4_HMAC_EXP:
|
|
return TEXT("RSADSI RC4-HMAC(Export)");
|
|
break;
|
|
#endif
|
|
case KERB_ETYPE_RC4_PLAIN_EXP:
|
|
return TEXT("RSADSI RC4(Export)");
|
|
break;
|
|
case KERB_ETYPE_DES_CBC_MD5_EXP:
|
|
return TEXT("Kerberos DES-CBC-MD5-EXP(Export)");
|
|
break;
|
|
case KERB_ETYPE_DES_PLAIN_EXP:
|
|
return TEXT("Kerberos DES-Plain(Export)");
|
|
break;
|
|
default:
|
|
_snwprintf(buf, TSIZE(buf), TEXT("etype %d"), enctype);
|
|
buf[11] = 0;
|
|
return buf;
|
|
break;
|
|
}
|
|
#endif
|
|
}
|
|
|
|
LPTSTR
|
|
TimeString(TimeStamp ConvertTime)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Convert a TimeStamp into something readable
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
SYSTEMTIME SystemTime;
|
|
FILETIME LocalFileTime;
|
|
static TCHAR buf[LONGSTRING];
|
|
|
|
if (ConvertTime.HighPart == 0x7FFFFFFF &&
|
|
ConvertTime.LowPart == 0xFFFFFFFF) {
|
|
|
|
return(GetStringRes(IDS_INFINITE));
|
|
}
|
|
|
|
if (FileTimeToLocalFileTime(
|
|
(PFILETIME) &ConvertTime,
|
|
&LocalFileTime) &&
|
|
FileTimeToSystemTime(
|
|
&LocalFileTime,
|
|
&SystemTime)) {
|
|
|
|
_snwprintf(buf, TSIZE(buf), ftime_default_fmt,
|
|
SystemTime.wMonth,
|
|
SystemTime.wDay,
|
|
SystemTime.wYear,
|
|
SystemTime.wHour,
|
|
SystemTime.wMinute);
|
|
|
|
buf[TSIZE(buf)-1] = 0;
|
|
|
|
}
|
|
else
|
|
return(GetStringRes(IDS_INVALID));
|
|
|
|
return(buf);
|
|
}
|
|
|
|
DLGTEMPLATE * WINAPI
|
|
DoLockDlgRes(LPCTSTR lpszResName)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
loads and locks a dialog template resource
|
|
|
|
Arguments:
|
|
|
|
lpszResName - name of the resource
|
|
|
|
Return Value:
|
|
|
|
Returns the address of the locked resource.
|
|
|
|
--*/
|
|
{
|
|
HRSRC hrsrc;
|
|
HGLOBAL hglb;
|
|
DLGTEMPLATE *pDlg;
|
|
|
|
hrsrc = FindResource(NULL, lpszResName, RT_DIALOG);
|
|
if (!hrsrc) {
|
|
Error(TEXT("Unable to locate resource '%s'"), lpszResName);
|
|
ExitProcess(0);
|
|
}
|
|
|
|
hglb = LoadResource(hInstance, hrsrc);
|
|
if (!hglb) {
|
|
Error(TEXT("Unable to load resource '%s'"), lpszResName);
|
|
ExitProcess(0);
|
|
}
|
|
|
|
pDlg = (DLGTEMPLATE *)LockResource(hglb);
|
|
if (!pDlg) {
|
|
Error(TEXT("Unable to lock resource '%s'"), lpszResName);
|
|
ExitProcess(0);
|
|
}
|
|
|
|
return pDlg;
|
|
}
|
|
|
|
|
|
void
|
|
PurgeCache(void)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KERB_PURGE_TKT_CACHE_REQUEST CacheRequest;
|
|
PVOID Response;
|
|
ULONG ResponseSize;
|
|
NTSTATUS Status, SubStatus;
|
|
|
|
memset(&CacheRequest, 0, sizeof(CacheRequest));
|
|
|
|
//
|
|
// Purge all tickets in the cache
|
|
//
|
|
CacheRequest.MessageType = KerbPurgeTicketCacheMessage;
|
|
|
|
Status = LsaCallAuthenticationPackage(LogonHandle,
|
|
PackageId,
|
|
&CacheRequest,
|
|
sizeof(CacheRequest),
|
|
&Response,
|
|
&ResponseSize,
|
|
&SubStatus);
|
|
|
|
if (SEC_SUCCESS(Status) && SEC_SUCCESS(SubStatus)) {
|
|
ShowMessage(MB_ICONINFORMATION, GetStringRes(IDS_PURGED));
|
|
}
|
|
else {
|
|
Error(TEXT("Failed to purge ticket cache - 0x%x"), Status);
|
|
}
|
|
|
|
if (Response != NULL) {
|
|
LsaFreeReturnBuffer(Response);
|
|
}
|
|
}
|
|
|
|
HTREEITEM
|
|
AddOneItem(
|
|
HTREEITEM hParent,
|
|
LPTSTR szText,
|
|
HTREEITEM hInsAfter,
|
|
int iImage,
|
|
HWND hwndTree,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add the item to the specified TreeView
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HTREEITEM hItem;
|
|
TV_ITEM tvI;
|
|
TV_INSERTSTRUCT tvIns;
|
|
|
|
tvI.mask = TVIF_TEXT|TVIF_IMAGE|TVIF_SELECTEDIMAGE|TVIF_PARAM;
|
|
tvI.pszText = szText;
|
|
tvI.cchTextMax = lstrlen(szText);
|
|
tvI.lParam = lParam;
|
|
tvI.iImage = iImage;
|
|
tvI.iSelectedImage = iImage;
|
|
|
|
tvIns.item = tvI;
|
|
tvIns.hInsertAfter = hInsAfter;
|
|
tvIns.hParent = hParent;
|
|
|
|
hItem = TreeView_InsertItem(hwndTree, &tvIns);
|
|
return(hItem);
|
|
}
|
|
|
|
HTREEITEM
|
|
FindDomainByName(LPTSTR name)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find the tree for the specified Domain
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HTREEITEM dom = NULL;
|
|
TVITEM item;
|
|
TCHAR buf[LONGSTRING];
|
|
|
|
dom = TreeView_GetRoot(hWndUsers);
|
|
if (!dom)
|
|
return NULL;
|
|
|
|
do {
|
|
|
|
item.mask = TVIF_TEXT;
|
|
item.pszText = buf;
|
|
item.cchTextMax = sizeof(buf);
|
|
item.hItem = dom;
|
|
if (TreeView_GetItem(hWndUsers, &item)) {
|
|
if (wcscmp(name, buf) == 0) {
|
|
return dom;
|
|
}
|
|
}
|
|
} while (dom = TreeView_GetNextSibling(hWndUsers, dom));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
HTREEITEM
|
|
AddDomain(
|
|
LPTSTR name
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add the named Domain to the tree
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HTREEITEM hItem;
|
|
|
|
if (!(hItem = FindDomainByName(name))) {
|
|
hItem = AddOneItem(NULL, _wcsdup(name), TVI_ROOT,
|
|
domain_icon, hWndUsers, 0);
|
|
}
|
|
return(hItem);
|
|
}
|
|
|
|
HTREEITEM
|
|
FindTicketByName(HTREEITEM lip, LPTSTR name)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Find a ticket by name in the tree
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HTREEITEM tick = NULL;
|
|
TVITEM item;
|
|
TCHAR buf[LONGSTRING];
|
|
|
|
tick = TreeView_GetChild(hWndUsers, lip);
|
|
if (!tick)
|
|
return NULL;
|
|
|
|
do {
|
|
item.mask = TVIF_TEXT;
|
|
item.pszText = buf;
|
|
item.cchTextMax = sizeof(buf);
|
|
item.hItem = tick;
|
|
if (TreeView_GetItem(hWndUsers, &item)) {
|
|
if (wcscmp(name, buf) == 0) {
|
|
return tick;
|
|
}
|
|
}
|
|
} while (tick = TreeView_GetNextSibling(hWndUsers, tick));
|
|
|
|
return NULL;
|
|
}
|
|
|
|
HTREEITEM
|
|
AddTicket(
|
|
HTREEITEM dom,
|
|
LPTSTR name,
|
|
int idx,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Add a ticket to the domain branch.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
HTREEITEM hItem;
|
|
|
|
hItem = AddOneItem(dom, name, TVI_SORT, idx, hWndUsers, lParam);
|
|
TreeView_Expand(hWndUsers, dom, TVE_EXPAND);
|
|
|
|
return(hItem);
|
|
}
|
|
|
|
void
|
|
ShowTicket(
|
|
HWND hDlg,
|
|
PKERB_TICKET_CACHE_INFO tix,
|
|
int i,
|
|
BOOL ShowExpiredTickets
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Updates a Ticket for display
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
TCHAR sname[LONGSTRING];
|
|
HTREEITEM dom, tick;
|
|
FILETIME CurrentFileTime;
|
|
LARGE_INTEGER Quad;
|
|
long dt = 0L;
|
|
|
|
memset(sname, 0, sizeof(sname));
|
|
|
|
//
|
|
// Calculate ticket lifetime
|
|
//
|
|
GetSystemTimeAsFileTime(&CurrentFileTime);
|
|
|
|
Quad.LowPart = CurrentFileTime.dwLowDateTime;
|
|
Quad.HighPart = CurrentFileTime.dwHighDateTime;
|
|
|
|
dt = (long)((tix->EndTime.QuadPart - Quad.QuadPart) / TPS);
|
|
|
|
//
|
|
// Only display valid tickets
|
|
//
|
|
if (dt > 0 || ShowExpiredTickets)
|
|
{
|
|
//
|
|
// Add realm to tree control
|
|
//
|
|
swprintf(sname, TEXT("%wZ"), &tix->RealmName);
|
|
dom = AddDomain(sname);
|
|
|
|
//
|
|
// Add ticket under realm
|
|
//
|
|
swprintf(sname, TEXT("%wZ"), &tix->ServerName);
|
|
|
|
tick = AddTicket(dom, sname, GetIconIndex(dt), (LPARAM)tix);
|
|
|
|
//
|
|
// Look for initial TGT
|
|
//
|
|
if (tix->TicketFlags & KERB_TICKET_FLAGS_initial)
|
|
tgt = tick;
|
|
}
|
|
}
|
|
|
|
void
|
|
DisplayCreds(
|
|
HWND hDlg
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Get the list of tickets to display
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
KERB_QUERY_TKT_CACHE_REQUEST CacheRequest;
|
|
PKERB_RETRIEVE_TKT_RESPONSE TicketEntry = NULL;
|
|
PKERB_EXTERNAL_TICKET Ticket;
|
|
NTSTATUS Status, SubStatus;
|
|
ULONG ResponseSize;
|
|
DWORD i;
|
|
DLGTABHDR *pHdr;
|
|
TCITEM tie;
|
|
DWORD dwDlgBase = GetDialogBaseUnits();
|
|
int cxMargin = LOWORD(dwDlgBase) / 4;
|
|
int cyMargin = HIWORD(dwDlgBase) / 8;
|
|
RECT rcTab;
|
|
static TCHAR princ[LONGSTRING];
|
|
|
|
pHdr = (DLGTABHDR *) LocalAlloc(LPTR|LMEM_ZEROINIT, sizeof(DLGTABHDR));
|
|
if (!pHdr)
|
|
ErrorExit(TEXT("Unable to allocate memory"));
|
|
|
|
//
|
|
// Save a pointer to the DLGHDR structure.
|
|
//
|
|
SetWindowLongPtr(hDlg, GWLP_USERDATA, (LONG_PTR)pHdr);
|
|
|
|
pHdr->hwndTab = GetDlgItem(hDlg, IDC_TAB_ATTRIBUTES);
|
|
|
|
hWndUsers = GetDlgItem(hDlg, IDC_TICKETS);
|
|
|
|
//
|
|
// Associate the image list with the tree view control.
|
|
//
|
|
//TreeView_SetImageList(hWndUsers, himl, TVSIL_NORMAL);
|
|
|
|
//
|
|
// Add a tab for each of the three child dialog boxes.
|
|
//
|
|
tie.mask = TCIF_TEXT | TCIF_IMAGE;
|
|
tie.iImage = -1;
|
|
tie.pszText = GetStringRes(IDS_LNAMES);
|
|
TabCtrl_InsertItem(pHdr->hwndTab, PPAGE_NAMES, &tie);
|
|
tie.pszText = GetStringRes(IDS_LTIMES);
|
|
TabCtrl_InsertItem(pHdr->hwndTab, PPAGE_TIMES, &tie);
|
|
tie.pszText = GetStringRes(IDS_LFLAGS);
|
|
TabCtrl_InsertItem(pHdr->hwndTab, PPAGE_FLAGS, &tie);
|
|
tie.pszText = GetStringRes(IDS_LENCTYPE);
|
|
TabCtrl_InsertItem(pHdr->hwndTab, PPAGE_ETYPES, &tie);
|
|
|
|
//
|
|
// Lock the resources for the three child dialog boxes.
|
|
//
|
|
pHdr->apRes[PPAGE_NAMES] = DoLockDlgRes(MAKEINTRESOURCE(IDD_PROP_NAMES));
|
|
pHdr->apRes[PPAGE_TIMES] = DoLockDlgRes(MAKEINTRESOURCE(IDD_PROP_TIMES));
|
|
pHdr->apRes[PPAGE_FLAGS] = DoLockDlgRes(MAKEINTRESOURCE(IDD_PROP_TKT_FLAGS));
|
|
pHdr->apRes[PPAGE_ETYPES] = DoLockDlgRes(MAKEINTRESOURCE(IDD_PROP_ENCTYPES));
|
|
|
|
//
|
|
// Determine the bounding rectangle for all child dialog boxes.
|
|
//
|
|
SetRectEmpty(&rcTab);
|
|
for (i = 0; i < C_PAGES; i++) {
|
|
if (pHdr->apRes[i]->cx > rcTab.right)
|
|
rcTab.right = pHdr->apRes[i]->cx;
|
|
if (pHdr->apRes[i]->cy > rcTab.bottom)
|
|
rcTab.bottom = pHdr->apRes[i]->cy;
|
|
}
|
|
rcTab.right = rcTab.right * LOWORD(dwDlgBase) / 4;
|
|
rcTab.bottom = rcTab.bottom * HIWORD(dwDlgBase) / 8;
|
|
|
|
//
|
|
// Calculate how large to make the tab control, so
|
|
// the display area can accommodate all the child dialog boxes.
|
|
//
|
|
TabCtrl_AdjustRect(pHdr->hwndTab, TRUE, &rcTab);
|
|
OffsetRect(&rcTab, cxMargin - rcTab.left,
|
|
cyMargin - rcTab.top);
|
|
|
|
//
|
|
// Calculate the display rectangle.
|
|
//
|
|
CopyRect(&pHdr->rcDisplay, &rcTab);
|
|
TabCtrl_AdjustRect(pHdr->hwndTab, FALSE, &pHdr->rcDisplay);
|
|
|
|
//
|
|
// Get the User's TGT for the client name
|
|
//
|
|
CacheRequest.MessageType = KerbRetrieveTicketMessage;
|
|
CacheRequest.LogonId.LowPart = 0;
|
|
CacheRequest.LogonId.HighPart = 0;
|
|
|
|
Status = LsaCallAuthenticationPackage(LogonHandle,
|
|
PackageId,
|
|
&CacheRequest,
|
|
sizeof(CacheRequest),
|
|
(PVOID *) &TicketEntry,
|
|
&ResponseSize,
|
|
&SubStatus);
|
|
|
|
if (SEC_SUCCESS(Status) && SEC_SUCCESS(SubStatus)) {
|
|
|
|
//
|
|
// Got the cname/crealm format it and display
|
|
//
|
|
Ticket = &(TicketEntry->Ticket);
|
|
memset(princ, 0, sizeof(princ));
|
|
swprintf(princ, TEXT("%wZ@%wZ"),
|
|
&Ticket->ClientName->Names[0],
|
|
&Ticket->DomainName);
|
|
SetDlgItemText(hDlg, IDC_PRINC_LABEL, princ);
|
|
}
|
|
else {
|
|
|
|
//
|
|
// No TGT, clear out the client name
|
|
//
|
|
SetDlgItemText(hDlg, IDC_PRINC_LABEL,
|
|
GetStringRes(IDS_NO_NET_CREDS));
|
|
SetDlgItemText(hDlg, IDC_PRINC_START,
|
|
TEXT(""));
|
|
|
|
if (TicketEntry)
|
|
LsaFreeReturnBuffer(TicketEntry);
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Done with the TGT
|
|
//
|
|
if (TicketEntry) {
|
|
LsaFreeReturnBuffer(TicketEntry);
|
|
TicketEntry = NULL;
|
|
}
|
|
|
|
//
|
|
// Get the list of cached tickets
|
|
//
|
|
CacheRequest.MessageType = KerbQueryTicketCacheMessage;
|
|
CacheRequest.LogonId.LowPart = 0;
|
|
CacheRequest.LogonId.HighPart = 0;
|
|
|
|
Status = LsaCallAuthenticationPackage(LogonHandle,
|
|
PackageId,
|
|
&CacheRequest,
|
|
sizeof(CacheRequest),
|
|
(PVOID *) &pHdr->Tickets,
|
|
&ResponseSize,
|
|
&SubStatus);
|
|
|
|
if (SEC_SUCCESS(Status) && SEC_SUCCESS(SubStatus)) {
|
|
|
|
for (i = 0; i < pHdr->Tickets->CountOfTickets; i++) {
|
|
|
|
ShowTicket(hDlg, &pHdr->Tickets->Tickets[i], i, FALSE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Position the selection on the initial TGT
|
|
//
|
|
if (tgt)
|
|
TreeView_SelectItem(hWndUsers, tgt);
|
|
|
|
PropsheetDisplay(hDlg);
|
|
SelectTicket(hDlg);
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
PropSheetProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DLGTABHDR *pHdr;
|
|
HWND hwndParent = GetParent(hDlg);
|
|
|
|
hwndParent = GetParent(hwndParent);
|
|
pHdr = (DLGTABHDR *) GetWindowLongPtr(hwndParent, GWLP_USERDATA);
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
SetWindowPos(hDlg, HWND_TOP,
|
|
pHdr->rcDisplay.left, pHdr->rcDisplay.top,
|
|
0, 0, SWP_NOSIZE);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
PropsheetDisplay(HWND hDlg)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DLGTABHDR *pHdr = (DLGTABHDR *) GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);
|
|
|
|
//
|
|
// Destroy the current child dialog box, if any.
|
|
//
|
|
if (pHdr->hwndDisplay != NULL)
|
|
DestroyWindow(pHdr->hwndDisplay);
|
|
|
|
//
|
|
// Create the new child dialog box.
|
|
//
|
|
pHdr->hwndDisplay = CreateDialogIndirect(hInstance, pHdr->apRes[iSel],
|
|
pHdr->hwndTab, PropSheetProc);
|
|
|
|
}
|
|
|
|
INT
|
|
UnparseExternalName(
|
|
PKERB_EXTERNAL_NAME iName,
|
|
PUNICODE_STRING *np
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Format the name list into a "/" seperated name for display.
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
int len, cnt;
|
|
PUNICODE_STRING name;
|
|
|
|
for (len = 0, cnt = 0; cnt < iName->NameCount; cnt++) {
|
|
len += iName->Names[cnt].Length;
|
|
if ((cnt + 1) < iName->NameCount)
|
|
len += 2;
|
|
}
|
|
|
|
name = malloc(sizeof(UNICODE_STRING));
|
|
if (!name)
|
|
return -1;
|
|
|
|
name->Buffer = malloc(len + 2);
|
|
if (!name->Buffer) {
|
|
free(name);
|
|
return -1;
|
|
}
|
|
name->Length = 0;
|
|
name->MaximumLength = len+2;
|
|
memset(name->Buffer, 0, len + 2);
|
|
|
|
for (cnt = 0; cnt < iName->NameCount; cnt++) {
|
|
wcsncat(name->Buffer, iName->Names[cnt].Buffer, iName->Names[cnt].Length/2);
|
|
name->Length += iName->Names[cnt].Length;
|
|
if ((cnt + 1) < iName->NameCount) {
|
|
wcsncat(name->Buffer, L"/", 1);
|
|
name->Length += 2;
|
|
}
|
|
}
|
|
*np = name;
|
|
|
|
return 0;
|
|
}
|
|
|
|
VOID
|
|
FreeUnicodeString(
|
|
PUNICODE_STRING ustr
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
if (ustr) {
|
|
free(ustr->Buffer);
|
|
free(ustr);
|
|
}
|
|
}
|
|
|
|
void
|
|
SelectTicket(HWND hDlg)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Respond to the user clicking on a ticket in the tree
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
DLGTABHDR *pHdr = (DLGTABHDR *) GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);
|
|
HTREEITEM hItem = TreeView_GetSelection(hWndUsers);
|
|
TVITEM item;
|
|
TCHAR sname[LONGSTRING];
|
|
PKERB_TICKET_CACHE_INFO tix;
|
|
FILETIME CurrentFileTime;
|
|
LARGE_INTEGER Quad;
|
|
long dt = 0L;
|
|
|
|
//
|
|
// No selection
|
|
//
|
|
if (!hItem)
|
|
return;
|
|
|
|
item.hItem = hItem;
|
|
item.mask = TVIF_PARAM;
|
|
item.lParam = 0;
|
|
|
|
TreeView_GetItem(hWndUsers, &item);
|
|
|
|
//
|
|
// No info on the leaf
|
|
//
|
|
if (!item.lParam) {
|
|
SetDlgItemText(hDlg, IDC_SERVICE_PRINC_LABEL,
|
|
GetStringRes(IDS_DOMAIN));
|
|
SetDlgItemText(hDlg, IDC_SERVICE_PRINC, TEXT(""));
|
|
FillinTicket(hDlg);
|
|
return;
|
|
}
|
|
|
|
SetDlgItemText(hDlg, IDC_SERVICE_PRINC_LABEL,
|
|
GetStringRes(IDS_SERVICE_PRINCIPAL));
|
|
|
|
tix = (PKERB_TICKET_CACHE_INFO)item.lParam;
|
|
|
|
|
|
//
|
|
// Calculate lifetime
|
|
//
|
|
GetSystemTimeAsFileTime(&CurrentFileTime);
|
|
|
|
Quad.LowPart = CurrentFileTime.dwLowDateTime;
|
|
Quad.HighPart = CurrentFileTime.dwHighDateTime;
|
|
|
|
dt = (long)((tix->EndTime.QuadPart - Quad.QuadPart) / TPS);
|
|
if (dt > 0) {
|
|
|
|
swprintf(sname, TEXT("%wZ@%wZ"),
|
|
&tix->ServerName,
|
|
&tix->RealmName);
|
|
|
|
SetDlgItemText(hDlg, IDC_SERVICE_PRINC, sname);
|
|
}
|
|
else {
|
|
SetDlgItemText(hDlg, IDC_SERVICE_PRINC_LABEL,
|
|
GetStringRes(IDS_EXPIRED));
|
|
SetDlgItemText(hDlg, IDC_SERVICE_PRINC,
|
|
TEXT(""));
|
|
}
|
|
|
|
FillinTicket(hDlg);
|
|
}
|
|
|
|
|
|
void
|
|
FillinTicket(HWND hDlg)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
PKERB_TICKET_CACHE_INFO tix;
|
|
DLGTABHDR *pHdr = (DLGTABHDR *) GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
int iSel = TabCtrl_GetCurSel(pHdr->hwndTab);
|
|
HTREEITEM hItem = TreeView_GetSelection(hWndUsers);
|
|
TVITEM item;
|
|
PKERB_RETRIEVE_TKT_REQUEST TicketRequest;
|
|
ULONG ResponseSize;
|
|
NTSTATUS Status, SubStatus;
|
|
PKERB_EXTERNAL_TICKET ticket;
|
|
int sz;
|
|
TCHAR sname[LONGSTRING];
|
|
PUNICODE_STRING svc;
|
|
|
|
if (!hItem)
|
|
return;
|
|
|
|
item.hItem = hItem;
|
|
item.mask = TVIF_PARAM;
|
|
item.lParam = 0;
|
|
|
|
TreeView_GetItem(hWndUsers, &item);
|
|
|
|
switch(iSel) {
|
|
case PPAGE_NAMES:
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_SERVICENAME,
|
|
TEXT(""));
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_TARGETNAME,
|
|
TEXT(""));
|
|
#if 0
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_CLIENTNAME,
|
|
TEXT(""));
|
|
#endif
|
|
break;
|
|
|
|
case PPAGE_TIMES:
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_STARTTIME,
|
|
TEXT(""));
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_ENDTIME,
|
|
TEXT(""));
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_RENEW_UNTIL,
|
|
TEXT(""));
|
|
break;
|
|
|
|
case PPAGE_ETYPES:
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_TKT_ENCTYPE,
|
|
TEXT(""));
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_KEY_ENCTYPE,
|
|
TEXT(""));
|
|
break;
|
|
|
|
case PPAGE_FLAGS:
|
|
ShowFlags(pHdr->hwndDisplay, 0);
|
|
break;
|
|
}
|
|
|
|
if (!item.lParam) {
|
|
return;
|
|
}
|
|
|
|
|
|
//
|
|
// Retrieve full ticket for properties
|
|
//
|
|
tix = (PKERB_TICKET_CACHE_INFO)item.lParam;
|
|
|
|
swprintf(sname, TEXT("%wZ@%wZ"),
|
|
&tix->ServerName,
|
|
&tix->RealmName);
|
|
|
|
sz = sizeof(WCHAR)*(wcslen(sname) + 1);
|
|
|
|
TicketRequest = LocalAlloc(LMEM_ZEROINIT,
|
|
sizeof(KERB_RETRIEVE_TKT_REQUEST) + sz);
|
|
|
|
if (!TicketRequest)
|
|
ErrorExit(TEXT("Unable to allocate memory"));
|
|
|
|
TicketRequest->MessageType = KerbRetrieveEncodedTicketMessage;
|
|
TicketRequest->LogonId.LowPart = 0;
|
|
TicketRequest->LogonId.HighPart = 0;
|
|
TicketRequest->TargetName.Length = wcslen(sname) * sizeof(WCHAR);
|
|
TicketRequest->TargetName.MaximumLength =
|
|
TicketRequest->TargetName.Length + sizeof(WCHAR);
|
|
TicketRequest->TargetName.Buffer = (LPWSTR) (TicketRequest + 1);
|
|
wcsncpy(TicketRequest->TargetName.Buffer, sname, wcslen(sname));
|
|
TicketRequest->CacheOptions = KERB_RETRIEVE_TICKET_USE_CACHE_ONLY;
|
|
TicketRequest->EncryptionType = 0L;
|
|
TicketRequest->TicketFlags = 0L;
|
|
|
|
Status = LsaCallAuthenticationPackage(LogonHandle,
|
|
PackageId,
|
|
TicketRequest,
|
|
(sizeof(KERB_RETRIEVE_TKT_REQUEST) + sz),
|
|
(PVOID *)&ticket,
|
|
&ResponseSize,
|
|
&SubStatus);
|
|
|
|
//
|
|
// Don't need the request buffer anymore
|
|
//
|
|
LocalFree(TicketRequest);
|
|
|
|
if (SEC_SUCCESS(Status) && SEC_SUCCESS(SubStatus)) {
|
|
|
|
switch(iSel) {
|
|
case PPAGE_NAMES:
|
|
|
|
//
|
|
// Get the service name for the ticket
|
|
//
|
|
if (ticket->ServiceName && ticket->DomainName.Length &&
|
|
!UnparseExternalName(ticket->ServiceName, &svc)) {
|
|
|
|
swprintf(sname, TEXT("%wZ@%wZ"),
|
|
svc,
|
|
&ticket->DomainName);
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_SERVICENAME,
|
|
sname);
|
|
FreeUnicodeString(svc);
|
|
}
|
|
|
|
#if 0
|
|
//
|
|
// Get the client name from the buffer
|
|
//
|
|
// Bug - client name is wrong from the kerberos ssp. Use
|
|
// the TGT client name.
|
|
//
|
|
if (ticket->ClientName && ticket->DomainName.Length &&
|
|
!UnparseExternalName(ticket->ClientName, &svc)) {
|
|
|
|
swprintf(sname, TEXT("%wZ@%wZ"),
|
|
svc,
|
|
&ticket->DomainName);
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_CLIENTNAME,
|
|
sname);
|
|
FreeUnicodeString(svc);
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Get the requested target name for the ticket
|
|
//
|
|
if (ticket->TargetName && ticket->TargetDomainName.Length &&
|
|
!UnparseExternalName(ticket->TargetName, &svc)) {
|
|
swprintf(sname, TEXT("%wZ@%wZ"),
|
|
svc,
|
|
&ticket->TargetDomainName);
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_TARGETNAME,
|
|
sname);
|
|
FreeUnicodeString(svc);
|
|
}
|
|
break;
|
|
|
|
case PPAGE_TIMES:
|
|
//
|
|
// Display the ticket times
|
|
//
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_STARTTIME,
|
|
TimeString(tix->StartTime));
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_ENDTIME,
|
|
TimeString(tix->EndTime));
|
|
|
|
if (tix->TicketFlags & KERB_TICKET_FLAGS_renewable) {
|
|
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_RENEW_UNTIL,
|
|
TimeString(tix->RenewTime));
|
|
ShowWindow(GetDlgItem(pHdr->hwndDisplay, IDC_RENEW_UNTIL),
|
|
SW_SHOW);
|
|
}
|
|
else {
|
|
|
|
ShowWindow(GetDlgItem(pHdr->hwndDisplay, IDC_RENEW_UNTIL),
|
|
SW_HIDE);
|
|
}
|
|
break;
|
|
|
|
case PPAGE_ETYPES:
|
|
//
|
|
// Display ticket and session key enctype
|
|
//
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_TKT_ENCTYPE,
|
|
ETypeString(tix->EncryptionType));
|
|
SetDlgItemText(pHdr->hwndDisplay, IDC_KEY_ENCTYPE,
|
|
ETypeString(ticket->SessionKey.KeyType));
|
|
break;
|
|
|
|
case PPAGE_FLAGS:
|
|
//
|
|
// Display the ticket flags
|
|
//
|
|
ShowFlags(pHdr->hwndDisplay, tix->TicketFlags);
|
|
break;
|
|
}
|
|
|
|
LsaFreeReturnBuffer(ticket);
|
|
}
|
|
}
|
|
|
|
LRESULT CALLBACK
|
|
TicketsProc(
|
|
HWND hDlg,
|
|
UINT message,
|
|
WPARAM wParam,
|
|
LPARAM lParam
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
LPNMHDR nm;
|
|
DLGTABHDR *pHdr;
|
|
|
|
switch (message) {
|
|
case WM_INITDIALOG:
|
|
DisplayCreds(hDlg);
|
|
ShowWindow(hDlg, SW_SHOW);
|
|
return TRUE;
|
|
|
|
case WM_NOTIFY: {
|
|
nm = (LPNMHDR)lParam;
|
|
|
|
switch (nm->code) {
|
|
|
|
case TCN_SELCHANGING:
|
|
return FALSE;
|
|
|
|
case TCN_SELCHANGE:
|
|
PropsheetDisplay(hDlg);
|
|
FillinTicket(hDlg);
|
|
return TRUE;
|
|
|
|
case TVN_SELCHANGED:
|
|
SelectTicket(hDlg);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case WM_SYSCOMMAND:
|
|
switch (wParam) {
|
|
case SC_CLOSE:
|
|
goto close_tix;
|
|
}
|
|
break;
|
|
|
|
case WM_COMMAND:
|
|
switch (LOWORD(wParam)) {
|
|
case IDC_CLOSE:
|
|
close_tix:
|
|
pHdr = (DLGTABHDR *) GetWindowLongPtr(hDlg, GWLP_USERDATA);
|
|
if (pHdr->hwndDisplay != NULL)
|
|
DestroyWindow(pHdr->hwndDisplay);
|
|
|
|
DestroyWindow(hDlgTickets);
|
|
LsaFreeReturnBuffer(pHdr->Tickets);
|
|
LocalFree(pHdr);
|
|
hDlgTickets = NULL;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void
|
|
Tickets(void)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Arguments:
|
|
|
|
Return Value:
|
|
|
|
--*/
|
|
{
|
|
if (!hDlgTickets)
|
|
hDlgTickets = CreateDialog(hInstance,
|
|
MAKEINTRESOURCE(IDD_TICKETS),
|
|
hWnd,
|
|
TicketsProc);
|
|
else {
|
|
ShowWindow(hDlgTickets, SW_SHOW);
|
|
SetForegroundWindow(hDlgTickets);
|
|
}
|
|
}
|