xref: /freebsd/crypto/krb5/src/windows/leash/Leash.cpp (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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