/*-- 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: --*/ #define UNICODE #define _UNICODE #define STRICT #include #include #include #include #include #include #include #include #include #include #include #include #define SECURITY_WIN32 #include #include #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); wvsprintf(szTemp, fmt, ap); 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, sizeof(szTemp), fmt, ap); #else _vsnprintf(szTemp, sizeof(szTemp), fmt, ap); #endif 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: 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: 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); } int UpdateTray(HWND hwnd) /*++ Routine Description: Arguments: Return Value: --*/ { HICON hicon; TCHAR buf[SHORTSTRING]; int expired = FALSE; long dt = 0L; 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; CacheRequest.MessageType = KerbRetrieveTicketMessage; CacheRequest.LogonId.LowPart = 0; CacheRequest.LogonId.HighPart = 0; StrNCpy(buf, progname, TSIZE(buf)); Status = LsaCallAuthenticationPackage(LogonHandle, PackageId, &CacheRequest, sizeof(CacheRequest), (PVOID *) &TicketEntry, &ResponseSize, &SubStatus); if (!SEC_SUCCESS(Status) || !SEC_SUCCESS(SubStatus)) { hicon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_KDC)); StrCatBuff(buf, GetStringRes(IDS_NO_CREDS), TSIZE(buf)); } else { 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 { int days, hours, minutes, seconds; DWORD tt; TCHAR buf2[SHORTSTRING]; 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)); 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++) { #if 1 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]); } #if 1 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) { 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; 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: 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, }; 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)); /* Now lets dive in and pull out the version information: */ dwVerInfoSize = GetFileVersionInfoSize(szFullPath, &dwVerHnd); if (dwVerInfoSize) { LPSTR lpstrVffInfo; HANDLE hMem; 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); 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 etype_string( int enctype ) /*++ Routine Description: Arguments: Return Value: --*/ { #ifndef NO_CRYPTDLL static PCRYPTO_SYSTEM pcsSystem; static TCHAR buf[12]; if (pCDLocateCSystem(enctype, &pcsSystem) == S_OK) return pcsSystem->Name; else { _snwprintf(buf, TSIZE(buf), TEXT("etype %d"), enctype); 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); return buf; break; } #endif } LPTSTR timestring(TimeStamp ConvertTime) /*++ Routine Description: 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); } else return(GetStringRes(IDS_INVALID)); return(buf); } // DoLockDlgRes - loads and locks a dialog template resource. // Returns the address of the locked resource. // lpszResName - name of the resource DLGTEMPLATE * WINAPI DoLockDlgRes(LPCTSTR lpszResName) /*++ Routine Description: Arguments: Return Value: --*/ { 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)); 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 ) { 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) { 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 ) { 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) { 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 ) { 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 ) /*++ Routine Description: Arguments: Return Value: --*/ { TCHAR sname[LONGSTRING]; HTREEITEM dom, tick; FILETIME CurrentFileTime; LARGE_INTEGER Quad; long dt = 0L; memset(sname, 0, sizeof(sname)); swprintf(sname, TEXT("%wZ"), &tix->RealmName); dom = AddDomain(sname); swprintf(sname, TEXT("%wZ"), &tix->ServerName); GetSystemTimeAsFileTime(&CurrentFileTime); Quad.LowPart = CurrentFileTime.dwLowDateTime; Quad.HighPart = CurrentFileTime.dwHighDateTime; dt = (long)((tix->EndTime.QuadPart - Quad.QuadPart) / TPS); // 14 tick = AddTicket(dom, sname, GetIconIndex(dt), (LPARAM)tix); if (tix->TicketFlags & KERB_TICKET_FLAGS_initial) tgt = tick; } void DisplayCreds( HWND hDlg ) /*++ Routine Description: 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; 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); 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)) { static TCHAR princ[LONGSTRING]; 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 { SetDlgItemText(hDlg, IDC_PRINC_LABEL, GetStringRes(IDS_NO_NET_CREDS)); SetDlgItemText(hDlg, IDC_PRINC_START, TEXT("")); if (TicketEntry) LsaFreeReturnBuffer(TicketEntry); return; } // 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); 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); } LsaFreeReturnBuffer(TicketEntry); } 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 ) { 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 ) { if (ustr) { free(ustr->Buffer); free(ustr); } } void SelectTicket(HWND hDlg) /*++ Routine Description: 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; if (!hItem) return; item.hItem = hItem; item.mask = TVIF_PARAM; item.lParam = 0; TreeView_GetItem(hWndUsers, &item); 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; 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("")); SetDlgItemText(pHdr->hwndDisplay, IDC_CLIENTNAME, TEXT("")); 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; } 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); LocalFree(TicketRequest); if (SEC_SUCCESS(Status) && SEC_SUCCESS(SubStatus)) { #if 0 if (ticket->TargetName && ticket->TargetDomainName.Length && !UnparseExternalName(ticket->TargetName, &svc)) { swprintf(sname, TEXT("%wZ@%wZ"), svc, &ticket->TargetDomainName); SetDlgItemText(hDlg, IDC_SERVICE_PRINC, sname); SetDlgItemText(hDlg, IDC_SERVICE_PRINC_LABEL, GetStringRes(IDS_TARGET_NAME)); FreeUnicodeString(svc); } #endif switch(iSel) { case PPAGE_NAMES: 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 (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); } 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: 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: SetDlgItemText(pHdr->hwndDisplay, IDC_TKT_ENCTYPE, etype_string(tix->EncryptionType)); SetDlgItemText(pHdr->hwndDisplay, IDC_KEY_ENCTYPE, etype_string(ticket->SessionKey.KeyType)); break; case PPAGE_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); } }