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
BEGIN_MESSAGE_MAP(CLeashApp,CWinApp)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
~CLeashApp()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
ParseParam(LPCTSTR lpszParam,BOOL bFlag,BOOL bLast)124 void CLeashApp::ParseParam (LPCTSTR lpszParam,BOOL bFlag,BOOL bLast)
125 {
126 //CCommandLineInfo::ParseParam(lpszParam, bFlag, bLast) ;
127 }
128
129 extern "C" {
LeashWindowProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)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
InitInstance()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.
InitDLLs()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
FirstInstance()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
ValidateConfigFiles()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
GetProfileFile(LPSTR confname,UINT szConfname)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
ProbeKDC(void)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
ObtainTicketsViaUserIfNeeded(HWND hWnd)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
GetNumOfIpAddrs(void)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
IpAddrChangeMonitor(void * hWnd)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
IpAddrChangeMonitorInit(HWND hWnd)1153 CLeashApp::IpAddrChangeMonitorInit(HWND hWnd)
1154 {
1155 AfxBeginThread(IpAddrChangeMonitor, hWnd);
1156 return 0;
1157 }
1158
1159 UINT
InitWorker(void * hWnd)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
WinHelp(DWORD dwData,UINT nCmd)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
OnIdle(LONG lCount)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