1 //************************************************************************** 2 // File: Leash.cpp 3 // By: Arthur David Leather 4 // Created: 12/02/98 5 // Copyright: 1998 Massachusetts Institute of Technology - All rights 6 // reserved. 7 // 8 // Description: CPP file for Leash.h. Contains variables and functions 9 // for Leash 10 // 11 // History: 12 // 13 // MM/DD/YY Inits Description of Change 14 // 12/02/98 ADL Original 15 //************************************************************************** 16 17 #include "stdafx.h" 18 #include "Leash.h" 19 20 #include "MainFrm.h" 21 #include "LeashDoc.h" 22 #include "LeashView.h" 23 #include "LeashAboutBox.h" 24 25 #include "reminder.h" 26 #include <leasherr.h> 27 #include "lglobals.h" 28 #include <krb5.h> 29 #include <com_err.h> 30 31 #include <errno.h> 32 33 #include <afxwin.h> 34 35 #ifdef _DEBUG 36 #define new DEBUG_NEW 37 #undef THIS_FILE 38 static char THIS_FILE[] = __FILE__; 39 #endif 40 41 TicketInfoWrapper ticketinfo; 42 43 HWND CLeashApp::m_hProgram = 0; 44 HINSTANCE CLeashApp::m_hLeashDLL = 0; 45 HINSTANCE CLeashApp::m_hComErr = 0; 46 HINSTANCE CLeashApp::m_hKrb5DLL = 0; 47 HINSTANCE CLeashApp::m_hKrb5ProfileDLL= 0; 48 HINSTANCE CLeashApp::m_hPsapi = 0; 49 HINSTANCE CLeashApp::m_hToolHelp32 = 0; 50 krb5_context CLeashApp::m_krbv5_context = 0; 51 profile_t CLeashApp::m_krbv5_profile = 0; 52 HINSTANCE CLeashApp::m_hKrbLSA = 0; 53 int CLeashApp::m_useRibbon = TRUE; 54 BOOL CLeashApp::m_bUpdateDisplay = FALSE; 55 56 ///////////////////////////////////////////////////////////////////////////// 57 // CLeashApp 58 59 60 BEGIN_MESSAGE_MAP(CLeashApp, CWinApp) 61 //{{AFX_MSG_MAP(CLeashApp) 62 //}}AFX_MSG_MAP 63 // Standard file based document commands 64 ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew) 65 ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen) 66 END_MESSAGE_MAP() 67 68 ///////////////////////////////////////////////////////////////////////////// 69 // CLeashApp construction 70 CLeashApp::CLeashApp() 71 { 72 m_krbv5_context = NULL; 73 m_krbv5_profile = NULL; 74 // TODO: add construction code here, 75 // Place all significant initialization in InitInstance 76 77 // Memory may not be initialized to zeros (in debug) 78 memset(&ticketinfo, 0, sizeof(ticketinfo)); 79 80 ticketinfo.lockObj = CreateMutex(NULL, FALSE, NULL); 81 82 #ifdef USE_HTMLHELP 83 #if _MSC_VER >= 1300 84 EnableHtmlHelp(); 85 #endif 86 #endif 87 } 88 89 CLeashApp::~CLeashApp() 90 { 91 if ( m_krbv5_context ) { 92 pkrb5_free_context(m_krbv5_context); 93 m_krbv5_context = NULL; 94 } 95 96 if ( m_krbv5_profile ) { 97 pprofile_release(m_krbv5_profile); 98 m_krbv5_profile = NULL; 99 } 100 101 #ifdef COMMENT 102 /* Do not free the locking objects. Doing so causes an invalid handle access */ 103 CloseHandle(ticketinfo.lockObj); 104 #endif 105 AfxFreeLibrary(m_hLeashDLL); 106 AfxFreeLibrary(m_hKrb5DLL); 107 AfxFreeLibrary(m_hKrb5ProfileDLL); 108 AfxFreeLibrary(m_hPsapi); 109 AfxFreeLibrary(m_hToolHelp32); 110 AfxFreeLibrary(m_hKrbLSA); 111 #ifdef DEBUG 112 _CrtDumpMemoryLeaks(); 113 #endif 114 } 115 116 ///////////////////////////////////////////////////////////////////////////// 117 // The one and only CLeashApp object 118 119 CLeashApp theApp; 120 121 ///////////////////////////////////////////////////////////////////////////// 122 // CLeashApp initialization 123 124 void CLeashApp::ParseParam (LPCTSTR lpszParam,BOOL bFlag,BOOL bLast) 125 { 126 //CCommandLineInfo::ParseParam(lpszParam, bFlag, bLast) ; 127 } 128 129 extern "C" { 130 LRESULT WINAPI LeashWindowProc( HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) 131 { 132 switch ( Msg ) { 133 case WM_SYSCOMMAND: 134 if (SC_CLOSE == (wParam & 0xfff0)) { 135 wParam = (wParam & ~0xfff0) | SC_MINIMIZE; 136 } 137 break; 138 } 139 return ::DefWindowProc(hWnd, Msg, wParam, lParam); 140 } 141 } 142 143 BOOL CLeashApp::InitInstance() 144 { 145 #ifdef DEBUG 146 _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE ); 147 _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT ); 148 _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE ); 149 _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT ); 150 151 int tmp = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG); 152 _CrtSetDbgFlag( tmp | _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 153 #endif 154 AfxOleInit(); 155 // NOTE: Not used at this time 156 /// Set LEASH_DLL to the path where the Leash.exe is 157 char modulePath[MAX_PATH]; 158 krb5_error_code code; 159 DWORD result = GetModuleFileName(AfxGetInstanceHandle(), modulePath, MAX_PATH); 160 ASSERT(result); 161 162 char* pPath = modulePath + strlen(modulePath) - 1; 163 while (*pPath != '\\') 164 { 165 *pPath = 0; 166 pPath--; 167 } 168 strcat(modulePath, LEASH_HELP_FILE); 169 m_helpFile = modulePath; 170 171 ///strcat(dllFile, LEASH_DLL); 172 ///m_leashDLL = dllFile; 173 174 BOOL autoInit = FALSE; 175 HWND hMsg = GetForegroundWindow(); 176 if (!InitDLLs()) 177 return FALSE; //exit program, can't load LEASHDLL 178 code = pkrb5_init_context(&m_krbv5_context); 179 if (code) { 180 // @TODO: report error 181 return FALSE; 182 } 183 184 // Check for args (switches) 185 LPCTSTR exeFile = __targv[0]; 186 for (int argi = 1; argi < __argc; argi++) { 187 LPCTSTR optionParam = __targv[argi]; 188 189 if (!optionParam) 190 continue; 191 192 if (*optionParam == '-' || *optionParam == '/') 193 { 194 if (0 == stricmp(optionParam+1, "kinit") || 195 0 == stricmp(optionParam+1, "i")) 196 { 197 LSH_DLGINFO_EX ldi; 198 char username[64]=""; 199 char realm[192]=""; 200 int i=0, j=0; 201 if (WaitForSingleObject( ticketinfo.lockObj, INFINITE ) != WAIT_OBJECT_0) 202 throw("Unable to lock ticketinfo"); 203 204 LeashKRB5ListDefaultTickets(&ticketinfo.Krb5); 205 206 if ( ticketinfo.Krb5.btickets && ticketinfo.Krb5.principal ) { 207 for (; ticketinfo.Krb5.principal[i] && ticketinfo.Krb5.principal[i] != '@'; i++) 208 { 209 username[i] = ticketinfo.Krb5.principal[i]; 210 } 211 username[i] = '\0'; 212 if (ticketinfo.Krb5.principal[i]) { 213 for (i++ ; ticketinfo.Krb5.principal[i] ; i++, j++) 214 { 215 realm[j] = ticketinfo.Krb5.principal[i]; 216 } 217 } 218 realm[j] = '\0'; 219 } 220 221 LeashKRB5FreeTicketInfo(&ticketinfo.Krb5); 222 223 ReleaseMutex(ticketinfo.lockObj); 224 225 ldi.size = LSH_DLGINFO_EX_V1_SZ; 226 ldi.dlgtype = DLGTYPE_PASSWD; 227 ldi.title = "MIT Kerberos: Get Ticket"; 228 ldi.username = username; 229 ldi.realm = realm; 230 ldi.dlgtype = DLGTYPE_PASSWD; 231 ldi.use_defaults = 1; 232 233 if (!pLeash_kinit_dlg_ex(hMsg, &ldi)) 234 { 235 MessageBox(hMsg, "There was an error getting tickets!", 236 "Error", MB_OK); 237 return FALSE; 238 } 239 return TRUE; 240 } 241 else if (0 == stricmp(optionParam+1, "destroy") || 242 0 == stricmp(optionParam+1, "d")) 243 { 244 if (pLeash_kdestroy()) 245 { 246 MessageBox(hMsg, 247 "There was an error destroying tickets!", 248 "Error", MB_OK); 249 return FALSE; 250 } 251 return TRUE; 252 } 253 else if (0 == stricmp(optionParam+1, "renew") || 254 0 == stricmp(optionParam+1, "r")) 255 { 256 if (!pLeash_renew()) 257 { 258 MessageBox(hMsg, 259 "There was an error renewing tickets!", 260 "Error", MB_OK); 261 return FALSE; 262 } 263 return TRUE; 264 } 265 else if (0 == stricmp(optionParam+1, "autoinit") || 266 0 == stricmp(optionParam+1, "a")) 267 { 268 autoInit = TRUE; 269 } 270 else if (0 == stricmp(optionParam+1, "console") || 271 0 == stricmp(optionParam+1, "c")) 272 { 273 FILE *dummy; 274 AllocConsole(); 275 freopen_s(&dummy, "CONOUT$", "w", stderr); 276 freopen_s(&dummy, "CONOUT$", "w", stdout); 277 } 278 else if (0 == stricmp(optionParam+1, "noribbon")) 279 { 280 m_useRibbon = FALSE; 281 } 282 else 283 { 284 MessageBox(hMsg, 285 "'-kinit' or '-i' to perform ticket initialization (and exit)\n" 286 "'-renew' or '-r' to perform ticket renewal (and exit)\n" 287 "'-destroy' or '-d' to perform ticket destruction (and exit)\n" 288 "'-autoinit' or '-a' to perform automatic ticket initialization\n" 289 "'-console' or '-c' to attach a console for debugging\n", 290 "MIT Kerberos Error", MB_OK); 291 return FALSE; 292 } 293 } 294 else 295 { 296 MessageBox(hMsg, 297 "'-kinit' or '-i' to perform ticket initialization (and exit)\n" 298 "'-renew' or '-r' to perform ticket renewal (and exit)\n" 299 "'-destroy' or '-d' to perform ticket destruction (and exit)\n" 300 "'-autoinit' or '-a' to perform automatic ticket initialization\n", 301 "MIT Kerberos Error", MB_OK); 302 return FALSE; 303 } 304 } 305 306 // Insure only one instance of Leash 307 if (!FirstInstance()) 308 return FALSE; 309 310 if (!CWinAppEx::InitInstance()) 311 return FALSE; 312 313 //register our unique wnd class name to find it later 314 WNDCLASS wndcls; 315 memset(&wndcls, 0, sizeof(WNDCLASS)); 316 wndcls.style = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; 317 wndcls.lpfnWndProc = ::LeashWindowProc; 318 wndcls.hInstance = AfxGetInstanceHandle(); 319 wndcls.hIcon = LoadIcon(IDR_MAINFRAME); 320 wndcls.hCursor = LoadCursor(IDC_ARROW); 321 wndcls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); 322 wndcls.lpszMenuName = NULL; 323 //now the wnd class name to find it 324 wndcls.lpszClassName = _T("LEASH.0WNDCLASS"); 325 326 //register the new class 327 if(!AfxRegisterClass(&wndcls)) 328 { 329 TRACE("Class registration failed\n"); 330 return FALSE; 331 } 332 333 AfxEnableControlContainer(); 334 335 // Standard initialization 336 // If you are not using these features and wish to reduce the size 337 // of your final executable, you should remove from the following 338 // the specific initialization routines you do not need. 339 340 #if _MSC_VER < 1300 341 #ifdef _AFXDLL 342 Enable3dControls(); // Call this when using MFC in a shared DLL 343 #else 344 Enable3dControlsStatic(); // Call this when linking to MFC statically 345 #endif 346 #endif 347 348 // Registry key under which our settings are stored. 349 if (m_pszAppName) 350 free((void*)m_pszAppName); 351 m_pszAppName = _tcsdup("MIT Kerberos"); 352 SetRegistryKey(_T("MIT")); 353 354 LoadStdProfileSettings(); // Load standard INI file options (including MRU) 355 356 // Register the application's document templates. Document templates 357 // serve as the connection between documents, frame windows and views. 358 359 CSingleDocTemplate* pDocTemplate; 360 pDocTemplate = new CSingleDocTemplate( 361 IDR_MAINFRAME, 362 RUNTIME_CLASS(LeashDoc), 363 RUNTIME_CLASS(CMainFrame), // main SDI frame window 364 RUNTIME_CLASS(CLeashView)); 365 AddDocTemplate(pDocTemplate); 366 367 // Parse command line for standard shell commands, DDE, file open 368 CCommandLineInfo cmdInfo; 369 ParseCommandLine(cmdInfo); 370 371 // Dispatch commands specified on the command line 372 if (!ProcessShellCommand(cmdInfo)) 373 return FALSE; 374 375 // Check to see if there are any tickets in the cache. If not and 376 // autoinitialization is enabled, display the initial tickets dialog. 377 { 378 if (WaitForSingleObject( ticketinfo.lockObj, INFINITE ) != WAIT_OBJECT_0) 379 throw("Unable to lock ticketinfo"); 380 LeashKRB5ListDefaultTickets(&ticketinfo.Krb5); 381 BOOL b_autoinit = !ticketinfo.Krb5.btickets; 382 LeashKRB5FreeTicketInfo(&ticketinfo.Krb5); 383 ReleaseMutex(ticketinfo.lockObj); 384 385 if (autoInit) { 386 if ( b_autoinit ) 387 AfxBeginThread(InitWorker, m_pMainWnd->m_hWnd); 388 389 IpAddrChangeMonitorInit(m_pMainWnd->m_hWnd); 390 } 391 } 392 393 // The one and only window has been initialized, so show and update it. 394 m_pMainWnd->SetWindowText("MIT Kerberos"); 395 m_pMainWnd->UpdateWindow(); 396 m_pMainWnd->ShowWindow(SW_SHOW); 397 m_pMainWnd->SetForegroundWindow(); 398 399 ValidateConfigFiles(); 400 401 return TRUE; 402 } 403 404 405 ///////////////////////////////////////////////////////////////////////////// 406 // CLeashApp commands 407 408 // leash functions 409 DECL_FUNC_PTR(Leash_kdestroy); 410 DECL_FUNC_PTR(Leash_changepwd_dlg); 411 DECL_FUNC_PTR(Leash_changepwd_dlg_ex); 412 DECL_FUNC_PTR(Leash_kinit_dlg); 413 DECL_FUNC_PTR(Leash_kinit_dlg_ex); 414 DECL_FUNC_PTR(Leash_timesync); 415 DECL_FUNC_PTR(Leash_get_default_uppercaserealm); 416 DECL_FUNC_PTR(Leash_set_default_uppercaserealm); 417 DECL_FUNC_PTR(Leash_renew); 418 419 FUNC_INFO leash_fi[] = { 420 MAKE_FUNC_INFO(Leash_kdestroy), 421 MAKE_FUNC_INFO(Leash_changepwd_dlg), 422 MAKE_FUNC_INFO(Leash_changepwd_dlg_ex), 423 MAKE_FUNC_INFO(Leash_kinit_dlg), 424 MAKE_FUNC_INFO(Leash_kinit_dlg_ex), 425 MAKE_FUNC_INFO(Leash_timesync), 426 MAKE_FUNC_INFO(Leash_get_default_uppercaserealm), 427 MAKE_FUNC_INFO(Leash_set_default_uppercaserealm), 428 MAKE_FUNC_INFO(Leash_renew), 429 END_FUNC_INFO 430 }; 431 432 // com_err functions 433 DECL_FUNC_PTR(error_message); 434 FUNC_INFO ce_fi[] = { 435 MAKE_FUNC_INFO(error_message), 436 END_FUNC_INFO 437 }; 438 439 // psapi functions 440 DECL_FUNC_PTR(GetModuleFileNameExA); 441 DECL_FUNC_PTR(EnumProcessModules); 442 443 FUNC_INFO psapi_fi[] = { 444 MAKE_FUNC_INFO(GetModuleFileNameExA), 445 MAKE_FUNC_INFO(EnumProcessModules), 446 END_FUNC_INFO 447 }; 448 449 // toolhelp functions 450 DECL_FUNC_PTR(CreateToolhelp32Snapshot); 451 DECL_FUNC_PTR(Module32First); 452 DECL_FUNC_PTR(Module32Next); 453 454 FUNC_INFO toolhelp_fi[] = { 455 MAKE_FUNC_INFO(CreateToolhelp32Snapshot), 456 MAKE_FUNC_INFO(Module32First), 457 MAKE_FUNC_INFO(Module32Next), 458 END_FUNC_INFO 459 }; 460 461 // krb5 functions 462 DECL_FUNC_PTR(krb5_cc_default_name); 463 DECL_FUNC_PTR(krb5_cc_set_default_name); 464 DECL_FUNC_PTR(krb5_get_default_config_files); 465 DECL_FUNC_PTR(krb5_free_config_files); 466 DECL_FUNC_PTR(krb5_free_context); 467 DECL_FUNC_PTR(krb5_get_default_realm); 468 DECL_FUNC_PTR(krb5_free_default_realm); 469 DECL_FUNC_PTR(krb5_init_context); 470 DECL_FUNC_PTR(krb5_cc_default); 471 DECL_FUNC_PTR(krb5_parse_name); 472 DECL_FUNC_PTR(krb5_free_principal); 473 DECL_FUNC_PTR(krb5_cc_close); 474 DECL_FUNC_PTR(krb5_cc_get_principal); 475 DECL_FUNC_PTR(krb5_build_principal); 476 DECL_FUNC_PTR(krb5_c_random_make_octets); 477 DECL_FUNC_PTR(krb5_get_init_creds_password); 478 DECL_FUNC_PTR(krb5_free_cred_contents); 479 DECL_FUNC_PTR(krb5_cc_resolve); 480 DECL_FUNC_PTR(krb5_unparse_name); 481 DECL_FUNC_PTR(krb5_free_unparsed_name); 482 DECL_FUNC_PTR(krb5_cc_destroy); 483 DECL_FUNC_PTR(krb5_cccol_cursor_new); 484 DECL_FUNC_PTR(krb5_cccol_cursor_free); 485 DECL_FUNC_PTR(krb5_cccol_cursor_next); 486 DECL_FUNC_PTR(krb5_cc_start_seq_get); 487 DECL_FUNC_PTR(krb5_cc_next_cred); 488 DECL_FUNC_PTR(krb5_cc_end_seq_get); 489 DECL_FUNC_PTR(krb5_cc_get_name); 490 DECL_FUNC_PTR(krb5_cc_set_flags); 491 DECL_FUNC_PTR(krb5_is_config_principal); 492 DECL_FUNC_PTR(krb5_free_ticket); 493 DECL_FUNC_PTR(krb5_decode_ticket); 494 DECL_FUNC_PTR(krb5_cc_switch); 495 DECL_FUNC_PTR(krb5_build_principal_ext); 496 DECL_FUNC_PTR(krb5_get_renewed_creds); 497 DECL_FUNC_PTR(krb5_cc_initialize); 498 DECL_FUNC_PTR(krb5_cc_store_cred); 499 DECL_FUNC_PTR(krb5_cc_get_full_name); 500 DECL_FUNC_PTR(krb5_free_string); 501 DECL_FUNC_PTR(krb5_enctype_to_name); 502 DECL_FUNC_PTR(krb5_cc_get_type); 503 DECL_FUNC_PTR(krb5int_cc_user_set_default_name); 504 505 FUNC_INFO krb5_fi[] = { 506 MAKE_FUNC_INFO(krb5_cc_default_name), 507 MAKE_FUNC_INFO(krb5_cc_set_default_name), 508 MAKE_FUNC_INFO(krb5_get_default_config_files), 509 MAKE_FUNC_INFO(krb5_free_config_files), 510 MAKE_FUNC_INFO(krb5_free_context), 511 MAKE_FUNC_INFO(krb5_get_default_realm), 512 MAKE_FUNC_INFO(krb5_free_default_realm), 513 MAKE_FUNC_INFO(krb5_init_context), 514 MAKE_FUNC_INFO(krb5_cc_default), 515 MAKE_FUNC_INFO(krb5_parse_name), 516 MAKE_FUNC_INFO(krb5_free_principal), 517 MAKE_FUNC_INFO(krb5_cc_close), 518 MAKE_FUNC_INFO(krb5_cc_get_principal), 519 MAKE_FUNC_INFO(krb5_build_principal), 520 MAKE_FUNC_INFO(krb5_c_random_make_octets), 521 MAKE_FUNC_INFO(krb5_get_init_creds_password), 522 MAKE_FUNC_INFO(krb5_free_cred_contents), 523 MAKE_FUNC_INFO(krb5_cc_resolve), 524 MAKE_FUNC_INFO(krb5_unparse_name), 525 MAKE_FUNC_INFO(krb5_free_unparsed_name), 526 MAKE_FUNC_INFO(krb5_cc_destroy), 527 MAKE_FUNC_INFO(krb5_cccol_cursor_new), 528 MAKE_FUNC_INFO(krb5_cccol_cursor_next), 529 MAKE_FUNC_INFO(krb5_cccol_cursor_free), 530 MAKE_FUNC_INFO(krb5_cc_start_seq_get), 531 MAKE_FUNC_INFO(krb5_cc_next_cred), 532 MAKE_FUNC_INFO(krb5_cc_end_seq_get), 533 MAKE_FUNC_INFO(krb5_cc_get_name), 534 MAKE_FUNC_INFO(krb5_cc_set_flags), 535 MAKE_FUNC_INFO(krb5_is_config_principal), 536 MAKE_FUNC_INFO(krb5_free_ticket), 537 MAKE_FUNC_INFO(krb5_decode_ticket), 538 MAKE_FUNC_INFO(krb5_cc_switch), 539 MAKE_FUNC_INFO(krb5_build_principal_ext), 540 MAKE_FUNC_INFO(krb5_get_renewed_creds), 541 MAKE_FUNC_INFO(krb5_cc_initialize), 542 MAKE_FUNC_INFO(krb5_cc_store_cred), 543 MAKE_FUNC_INFO(krb5_cc_get_full_name), 544 MAKE_FUNC_INFO(krb5_free_string), 545 MAKE_FUNC_INFO(krb5_enctype_to_name), 546 MAKE_FUNC_INFO(krb5_cc_get_type), 547 MAKE_FUNC_INFO(krb5int_cc_user_set_default_name), 548 END_FUNC_INFO 549 }; 550 551 // profile functions 552 DECL_FUNC_PTR(profile_release); 553 DECL_FUNC_PTR(profile_init); 554 DECL_FUNC_PTR(profile_flush); 555 DECL_FUNC_PTR(profile_rename_section); 556 DECL_FUNC_PTR(profile_update_relation); 557 DECL_FUNC_PTR(profile_clear_relation); 558 DECL_FUNC_PTR(profile_add_relation); 559 DECL_FUNC_PTR(profile_get_relation_names); 560 DECL_FUNC_PTR(profile_get_subsection_names); 561 DECL_FUNC_PTR(profile_get_values); 562 DECL_FUNC_PTR(profile_free_list); 563 DECL_FUNC_PTR(profile_abandon); 564 DECL_FUNC_PTR(profile_get_string); 565 DECL_FUNC_PTR(profile_release_string); 566 567 FUNC_INFO profile_fi[] = { 568 MAKE_FUNC_INFO(profile_release), 569 MAKE_FUNC_INFO(profile_init), 570 MAKE_FUNC_INFO(profile_flush), 571 MAKE_FUNC_INFO(profile_rename_section), 572 MAKE_FUNC_INFO(profile_update_relation), 573 MAKE_FUNC_INFO(profile_clear_relation), 574 MAKE_FUNC_INFO(profile_add_relation), 575 MAKE_FUNC_INFO(profile_get_relation_names), 576 MAKE_FUNC_INFO(profile_get_subsection_names), 577 MAKE_FUNC_INFO(profile_get_values), 578 MAKE_FUNC_INFO(profile_free_list), 579 MAKE_FUNC_INFO(profile_abandon), 580 MAKE_FUNC_INFO(profile_get_string), 581 MAKE_FUNC_INFO(profile_release_string), 582 END_FUNC_INFO 583 }; 584 585 // Tries to load the .DLL files. If it works, we get some functions from them 586 // and return a TRUE. If it doesn't work, we return a FALSE. 587 BOOL CLeashApp::InitDLLs() 588 { 589 m_hLeashDLL = AfxLoadLibrary(LEASHDLL); 590 m_hKrb5DLL = AfxLoadLibrary(KERB5DLL); 591 m_hKrb5ProfileDLL = AfxLoadLibrary(KERB5_PPROFILE_DLL); 592 m_hComErr = AfxLoadLibrary(COMERR_DLL); 593 594 #define PSAPIDLL "psapi.dll" 595 #define TOOLHELPDLL "kernel32.dll" 596 597 m_hPsapi = AfxLoadLibrary(PSAPIDLL); 598 m_hToolHelp32 = AfxLoadLibrary(TOOLHELPDLL); 599 600 HWND hwnd = GetForegroundWindow(); 601 if (!m_hLeashDLL) 602 { 603 // We couldn't load the m_hLeashDLL. 604 m_msgError = "Couldn't load the Leash DLL or one of its dependents."; 605 MessageBox(hwnd, m_msgError, "Error", MB_OK); 606 return FALSE; 607 } 608 609 if (!LoadFuncs(LEASHDLL, leash_fi, 0, 0, 1, 0, 0)) 610 { 611 MessageBox(hwnd, 612 "Functions within the Leash DLL didn't load properly!", 613 "Error", MB_OK); 614 return FALSE; 615 } 616 617 if (!LoadFuncs(COMERR_DLL, ce_fi, &m_hComErr, 0, 0, 1, 0)) { 618 MessageBox(hwnd, 619 "Functions within " COMERR_DLL "didn't load properly!", 620 "Error", MB_OK); 621 return FALSE; 622 } 623 624 if (m_hKrb5DLL) 625 { 626 if (!LoadFuncs(KERB5DLL, krb5_fi, 0, 0, 1, 0, 0)) 627 { 628 MessageBox(hwnd, 629 "Unexpected error while loading " KERB5DLL ".\n" 630 "Kerberos 5 functionality will be disabled.\n", 631 "Error", MB_OK); 632 AfxFreeLibrary(m_hKrb5DLL); 633 m_hKrb5DLL = 0; 634 } 635 else if (!m_hKrb5ProfileDLL || 636 !LoadFuncs(KERB5_PPROFILE_DLL, profile_fi, 0, 0, 1, 0, 0)) 637 { 638 MessageBox(hwnd, 639 "Unexpected error while loading " KERB5_PPROFILE_DLL "." 640 "\nKerberos 5 functionality will be disabled.\n", 641 "Error", MB_OK); 642 AfxFreeLibrary(m_hKrb5ProfileDLL); 643 m_hKrb5ProfileDLL = 0; 644 // Use m_hKrb5DLL to undo LoadLibrary in loadfuncs... 645 UnloadFuncs(krb5_fi, m_hKrb5DLL); 646 AfxFreeLibrary(m_hKrb5DLL); 647 m_hKrb5DLL = 0; 648 } 649 650 } 651 652 OSVERSIONINFO osvi; 653 memset(&osvi, 0, sizeof(OSVERSIONINFO)); 654 osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); 655 GetVersionEx(&osvi); 656 657 // XXX: We should really use feature testing, first 658 // checking for CreateToolhelp32Snapshot. If that's 659 // not around, we try the psapi stuff. 660 // 661 // Only load LSA functions if on NT/2000/XP 662 if(osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) 663 { 664 // Windows 9x 665 AfxFreeLibrary(m_hPsapi); 666 m_hPsapi = NULL; 667 if (!m_hToolHelp32 || 668 !LoadFuncs(TOOLHELPDLL, toolhelp_fi, 0, 0, 1, 0, 0)) 669 { 670 MessageBox(hwnd, "Could not load " TOOLHELPDLL "!", "Error", 671 MB_OK); 672 return FALSE; 673 } 674 } 675 else if(osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) 676 { 677 // Windows NT 678 AfxFreeLibrary(m_hToolHelp32); 679 m_hToolHelp32 = NULL; 680 if (!m_hPsapi || 681 !LoadFuncs(PSAPIDLL, psapi_fi, 0, 0, 1, 0, 0)) 682 { 683 MessageBox(hwnd, "Could not load " PSAPIDLL "!", "Error", MB_OK); 684 return FALSE; 685 } 686 687 m_hKrbLSA = AfxLoadLibrary(SECUR32DLL); 688 } 689 else 690 { 691 MessageBox(hwnd, 692 "Unrecognized Operating System!", 693 "Error", MB_OK); 694 return FALSE; 695 } 696 697 return TRUE; 698 } 699 700 701 BOOL CLeashApp::FirstInstance() 702 { 703 CWnd* pWndprev; 704 CWnd* pWndchild; 705 706 //find if it exists 707 pWndprev = CWnd::FindWindow(_T("LEASH.0WNDCLASS"), NULL); 708 if (pWndprev) 709 { 710 //if it has popups 711 pWndchild = pWndprev->GetLastActivePopup(); 712 //if iconic restore 713 if (pWndprev->IsIconic()) 714 pWndprev->ShowWindow(SW_RESTORE); 715 716 //bring the wnd to foreground 717 pWndchild->SetForegroundWindow(); 718 719 return FALSE; 720 } 721 //we could not find prev instance 722 else 723 return TRUE; 724 } 725 726 void 727 CLeashApp::ValidateConfigFiles() 728 { 729 char confname[257]; 730 char realm[256]=""; 731 732 CWinApp * pApp = AfxGetApp(); 733 if (pApp) 734 if (!pApp->GetProfileInt("Settings", "CreateMissingConfig", FALSE_FLAG)) 735 return; 736 737 if ( m_hKrb5DLL ) { 738 // Create the empty KRB5.INI file 739 if (!GetProfileFile(confname,sizeof(confname))) { 740 const char *filenames[2]; 741 filenames[0] = confname; 742 filenames[1] = NULL; 743 long retval = pprofile_init(filenames, &m_krbv5_profile); 744 if (!retval) 745 return; 746 else if (retval == ENOENT) { 747 FILE * f = fopen(confname,"w"); 748 if (f != NULL) { 749 fclose(f); 750 retval = pprofile_init(filenames, &m_krbv5_profile); 751 } 752 } 753 754 755 const char* lookupKdc[] = {"libdefaults", "dns_lookup_kdc", NULL}; 756 const char* lookupRealm[] = {"libdefaults", "dns_lookup_realm", NULL}; 757 const char* defRealm[] = {"libdefaults", "default_realm", NULL}; 758 const char* noAddresses[] = {"libdefaults", "noaddresses", NULL}; 759 760 // activate DNS KDC Lookups 761 const char** names = lookupKdc; 762 retval = pprofile_add_relation(m_krbv5_profile, 763 names, 764 "true"); 765 766 // activate No Addresses 767 names = noAddresses; 768 retval = pprofile_add_relation(m_krbv5_profile, 769 names, 770 "true"); 771 772 // Get Windows 2000/XP/2003 Kerberos config 773 if ( m_hKrbLSA && m_hKrb5DLL ) 774 { 775 char domain[256]=""; 776 HKEY hk=0; 777 DWORD dwType, dwSize, dwIndex; 778 779 if ( !RegOpenKeyEx(HKEY_CURRENT_USER, 780 "Volatile Environment", 0, 781 KEY_READ, &hk) ) 782 { 783 dwSize = sizeof(domain); 784 RegQueryValueEx(hk, "USERDNSDOMAIN", 0, 0, (LPBYTE)domain, &dwSize); 785 RegCloseKey(hk); 786 } 787 else if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, 788 "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 789 0, KEY_READ, &hk)) 790 { 791 792 dwSize = sizeof(domain); 793 RegQueryValueEx( hk, "DefaultDomainName", 794 NULL, &dwType, (unsigned char *)&domain, &dwSize); 795 RegCloseKey(hk); 796 } 797 798 char realmkey[256]="SYSTEM\\CurrentControlSet\\Control\\Lsa\\Kerberos\\Domains\\"; 799 size_t keylen = strlen(realmkey)-1; 800 801 if ( domain[0] ) { 802 strncpy(realm,domain,256); 803 realm[255] = '\0'; 804 strncat(realmkey,domain,256-strlen(realmkey)); 805 realmkey[255] = '\0'; 806 } 807 808 if ( domain[0] && 809 !RegOpenKeyEx(HKEY_LOCAL_MACHINE, 810 realmkey, 811 0, 812 KEY_READ, 813 &hk) 814 ) 815 { 816 RegCloseKey(hk); 817 818 realmkey[keylen] = '\0'; 819 RegOpenKeyEx(HKEY_LOCAL_MACHINE, 820 realmkey, 821 0, 822 KEY_READ|KEY_ENUMERATE_SUB_KEYS, 823 &hk); 824 825 dwIndex = 0; 826 unsigned char subkey[256]; 827 FILETIME ft; 828 dwSize = 256; 829 while ( ERROR_SUCCESS == RegEnumKeyEx(hk,dwIndex++, 830 (char *)subkey, 831 &dwSize, 832 0, 833 0, 834 0, 835 &ft) ) 836 { 837 HKEY hksub; 838 839 if ( !RegOpenKeyEx(hk, 840 (char *)subkey, 841 0, 842 KEY_READ, 843 &hksub) ) 844 { 845 unsigned char * lpszValue = NULL, *p; 846 dwSize = 0; 847 dwType = 0; 848 RegQueryValueEx( hksub, "KdcNames", 849 NULL, &dwType, lpszValue, &dwSize); 850 if ( dwSize > 0 ) { 851 lpszValue = (unsigned char *)malloc(dwSize+1); 852 dwSize += 1; 853 RegQueryValueEx( hksub, "KdcNames", 854 NULL, &dwType, lpszValue, &dwSize); 855 856 p = lpszValue; 857 while ( *p ) { 858 const char* realmKdc[] = {"realms", (const char *)subkey, "kdc", NULL}; 859 names = realmKdc; 860 retval = pprofile_add_relation(m_krbv5_profile, 861 names, 862 (const char *)p); 863 864 p += strlen((char*)p) + 1; 865 } 866 free(lpszValue); 867 } 868 RegCloseKey(hksub); 869 } 870 } 871 RegCloseKey(hk); 872 } 873 } else { 874 // activate DNS Realm Lookups (temporarily) 875 names = lookupRealm; 876 retval = pprofile_add_relation(m_krbv5_profile, 877 names, 878 "true"); 879 } 880 881 // Save to Kerberos Five config. file "Krb5.ini" 882 retval = pprofile_flush(m_krbv5_profile); 883 884 885 // Use DNS to retrieve the realm (if possible) 886 if (!realm[0]) { 887 krb5_context ctx = 0; 888 krb5_principal me = 0; 889 krb5_error_code code = 0; 890 891 code = pkrb5_init_context(&ctx); 892 if (code) goto no_k5_realm; 893 894 code = pkrb5_parse_name(ctx, "foo", &me); 895 if (code) goto no_k5_realm; 896 897 if ( krb5_princ_realm(ctx,me)->length < sizeof(realm) - 1) { 898 memcpy(realm, krb5_princ_realm(ctx,me)->data, 899 krb5_princ_realm(ctx,me)->length); 900 realm[krb5_princ_realm(ctx,me)->length] = '\0'; 901 } 902 903 no_k5_realm: 904 if ( me ) 905 pkrb5_free_principal(ctx,me); 906 if ( ctx ) 907 pkrb5_free_context(ctx); 908 } 909 910 // disable DNS Realm Lookups 911 retval = pprofile_update_relation(m_krbv5_profile, 912 names, 913 "true", "false"); 914 915 // save the default realm if it was discovered 916 if ( realm[0] ) { 917 names = defRealm; 918 retval = pprofile_add_relation(m_krbv5_profile, 919 names, 920 realm); 921 922 // It would be nice to be able to generate a list of KDCs 923 // but to do so based upon the contents of DNS would be 924 // wrong for several reasons: 925 // . it would make static the values inserted into DNS SRV 926 // records 927 // . DNS cannot necessarily be trusted 928 } 929 930 // Save to Kerberos Five config. file "Krb5.ini" 931 retval = pprofile_flush(m_krbv5_profile); 932 933 pprofile_release(m_krbv5_profile); 934 m_krbv5_profile = NULL; 935 936 } 937 } 938 } 939 940 BOOL 941 CLeashApp::GetProfileFile( 942 LPSTR confname, 943 UINT szConfname 944 ) 945 { 946 char **configFile = NULL; 947 if (!m_hKrb5DLL) 948 return NULL; 949 950 if (pkrb5_get_default_config_files(&configFile)) 951 { 952 GetWindowsDirectory(confname,szConfname); 953 confname[szConfname-1] = '\0'; 954 strncat(confname,"\\KRB5.INI",szConfname-strlen(confname)); 955 confname[szConfname-1] = '\0'; 956 return FALSE; 957 } 958 959 *confname = 0; 960 961 if (configFile) 962 { 963 strncpy(confname, *configFile, szConfname); 964 confname[szConfname-1] = '\0'; 965 pkrb5_free_config_files(configFile); 966 } 967 968 if (!*confname) 969 { 970 GetWindowsDirectory(confname,szConfname); 971 confname[szConfname-1] = '\0'; 972 strncat(confname,"\\KRB5.INI",szConfname-strlen(confname)); 973 confname[szConfname-1] = '\0'; 974 } 975 976 return FALSE; 977 } 978 979 #define PROBE_USERNAME "KERBEROS-KDC-PROBE" 980 #define PROBE_PASSWORD_LEN 16 981 982 BOOL 983 CLeashApp::ProbeKDC(void) 984 { 985 krb5_context ctx=0; 986 krb5_ccache cc=0; 987 krb5_principal principal = 0; 988 krb5_principal probeprinc = 0; 989 krb5_creds creds; 990 krb5_error_code code; 991 krb5_data pwdata; 992 char password[PROBE_PASSWORD_LEN+1]; 993 long success = FALSE; 994 995 if (!pkrb5_init_context) 996 return success; 997 998 memset(&creds, 0, sizeof(creds)); 999 1000 code = pkrb5_init_context(&ctx); 1001 if (code) 1002 goto cleanup; 1003 1004 code = pkrb5_cc_default(ctx, &cc); 1005 if (code) 1006 goto cleanup; 1007 1008 code = pkrb5_cc_get_principal(ctx, cc, &principal); 1009 if ( code ) 1010 code = pkrb5_parse_name(ctx, "foo", &principal); 1011 if ( code ) 1012 goto cleanup; 1013 1014 code = pkrb5_build_principal( ctx, &probeprinc, 1015 krb5_princ_realm(ctx,principal)->length, 1016 krb5_princ_realm(ctx,principal)->data, 1017 PROBE_USERNAME, NULL, NULL); 1018 if ( code ) 1019 goto cleanup; 1020 1021 pwdata.data = password; 1022 pwdata.length = PROBE_PASSWORD_LEN; 1023 code = pkrb5_c_random_make_octets(ctx, &pwdata); 1024 if (code) { 1025 int i; 1026 for ( i=0 ; i<PROBE_PASSWORD_LEN ; i ) 1027 password[i] = 'x'; 1028 } 1029 password[PROBE_PASSWORD_LEN] = '\0'; 1030 1031 code = pkrb5_get_init_creds_password(ctx, 1032 &creds, 1033 probeprinc, 1034 password, // password 1035 NULL, // prompter 1036 0, // prompter data 1037 0, // start time 1038 0, // service name 1039 0 // no options 1040 ); 1041 1042 switch ( code ) { 1043 case KRB5KDC_ERR_C_PRINCIPAL_UNKNOWN: 1044 case KRB5KDC_ERR_CLIENT_REVOKED: 1045 case KRB5KDC_ERR_CLIENT_NOTYET: 1046 case KRB5KDC_ERR_PREAUTH_FAILED: 1047 case KRB5KDC_ERR_PREAUTH_REQUIRED: 1048 case KRB5KDC_ERR_PADATA_TYPE_NOSUPP: 1049 success = TRUE; 1050 break; 1051 } 1052 cleanup: 1053 if (creds.client == probeprinc) 1054 creds.client = 0; 1055 pkrb5_free_cred_contents(ctx, &creds); 1056 if (principal) 1057 pkrb5_free_principal(ctx,principal); 1058 if (probeprinc) 1059 pkrb5_free_principal(ctx,probeprinc); 1060 if (cc) 1061 pkrb5_cc_close(ctx,cc); 1062 if (ctx) 1063 pkrb5_free_context(ctx); 1064 return success; 1065 } 1066 1067 VOID 1068 CLeashApp::ObtainTicketsViaUserIfNeeded(HWND hWnd) 1069 { 1070 if (WaitForSingleObject( ticketinfo.lockObj, INFINITE ) != WAIT_OBJECT_0) 1071 throw("Unable to lock ticketinfo"); 1072 LeashKRB5ListDefaultTickets(&ticketinfo.Krb5); 1073 int btickets = ticketinfo.Krb5.btickets; 1074 LeashKRB5FreeTicketInfo(&ticketinfo.Krb5); 1075 ReleaseMutex(ticketinfo.lockObj); 1076 1077 if (ProbeKDC() && (!btickets || !pLeash_renew())) { 1078 LSH_DLGINFO_EX ldi; 1079 ldi.size = LSH_DLGINFO_EX_V1_SZ; 1080 ldi.dlgtype = DLGTYPE_PASSWD; 1081 ldi.title = "MIT Kerberos: Get Ticket"; 1082 ldi.username = NULL; 1083 ldi.realm = NULL; 1084 ldi.dlgtype = DLGTYPE_PASSWD; 1085 ldi.use_defaults = 1; 1086 1087 pLeash_kinit_dlg_ex(hWnd, &ldi); 1088 } 1089 return; 1090 } 1091 1092 // IP Change Monitoring Functions 1093 #include <Iphlpapi.h> 1094 1095 1096 DWORD 1097 CLeashApp::GetNumOfIpAddrs(void) 1098 { 1099 PMIB_IPADDRTABLE pIpAddrTable = 0; 1100 ULONG dwSize; 1101 DWORD code; 1102 DWORD index; 1103 DWORD validAddrs = 0; 1104 1105 dwSize = 0; 1106 code = GetIpAddrTable(NULL, &dwSize, 0); 1107 if (code == ERROR_INSUFFICIENT_BUFFER) { 1108 pIpAddrTable = (PMIB_IPADDRTABLE) malloc(dwSize); 1109 code = GetIpAddrTable(pIpAddrTable, &dwSize, 0); 1110 if ( code == NO_ERROR ) { 1111 for ( index=0; index < pIpAddrTable->dwNumEntries; index++ ) { 1112 if (pIpAddrTable->table[index].dwAddr != 0) 1113 validAddrs++; 1114 } 1115 } 1116 free(pIpAddrTable); 1117 } 1118 return validAddrs; 1119 } 1120 1121 UINT 1122 CLeashApp::IpAddrChangeMonitor(void * hWnd) 1123 { 1124 DWORD Result; 1125 DWORD prevNumOfAddrs = GetNumOfIpAddrs(); 1126 DWORD NumOfAddrs; 1127 1128 if ( !hWnd ) 1129 return 0; 1130 1131 while ( TRUE ) { 1132 Result = NotifyAddrChange(NULL,NULL); 1133 if ( Result != NO_ERROR ) { 1134 // We do not have permission to open the device 1135 return 0; 1136 } 1137 1138 NumOfAddrs = GetNumOfIpAddrs(); 1139 if ( NumOfAddrs != prevNumOfAddrs ) { 1140 // wait for the network state to stabilize 1141 Sleep(2000); 1142 // this call should probably be mutex protected 1143 ObtainTicketsViaUserIfNeeded((HWND)hWnd); 1144 } 1145 prevNumOfAddrs = NumOfAddrs; 1146 } 1147 1148 return 0; 1149 } 1150 1151 1152 DWORD 1153 CLeashApp::IpAddrChangeMonitorInit(HWND hWnd) 1154 { 1155 AfxBeginThread(IpAddrChangeMonitor, hWnd); 1156 return 0; 1157 } 1158 1159 UINT 1160 CLeashApp::InitWorker(void * hWnd) 1161 { 1162 if ( ProbeKDC() ) { 1163 LSH_DLGINFO_EX ldi; 1164 ldi.size = LSH_DLGINFO_EX_V1_SZ; 1165 ldi.dlgtype = DLGTYPE_PASSWD; 1166 ldi.title = "Initialize Ticket"; 1167 ldi.username = NULL; 1168 ldi.realm = NULL; 1169 ldi.use_defaults = 1; 1170 1171 pLeash_kinit_dlg_ex((HWND)hWnd, &ldi); 1172 ::SendMessage((HWND)hWnd, WM_COMMAND, ID_UPDATE_DISPLAY, 0); 1173 } 1174 return 0; 1175 } 1176 1177 #ifdef USE_HTMLHELP 1178 #if _MSC_VER < 1300 1179 void 1180 CLeashApp::WinHelp(DWORD dwData, UINT nCmd) 1181 { 1182 switch (nCmd) 1183 { 1184 case HELP_CONTEXT: 1185 ::HtmlHelp(GetDesktopWindow(), m_helpFile, HH_HELP_CONTEXT, dwData ); 1186 break; 1187 case HELP_FINDER: 1188 ::HtmlHelp(GetDesktopWindow(), m_helpFile, HH_DISPLAY_TOPIC, 0); 1189 break; 1190 } 1191 } 1192 #endif 1193 #endif 1194 1195 1196 BOOL CLeashApp::OnIdle(LONG lCount) 1197 { 1198 // TODO: Add your specialized code here and/or call the base class 1199 BOOL retval = CWinAppEx::OnIdle(lCount); 1200 if ((lCount == 0) && m_bUpdateDisplay) { 1201 m_bUpdateDisplay = FALSE; 1202 m_pMainWnd->SendMessage(WM_COMMAND, ID_UPDATE_DISPLAY, 0); 1203 } 1204 return retval; 1205 } 1206