1 /*
2  * Portions Copyright (C) 2004-2010, 2013, 2014  Internet Systems Consortium, Inc. ("ISC")
3  * Portions Copyright (C) 2001, 2003  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 /* Id: BINDInstallDlg.cpp,v 1.48 2010/01/07 23:48:54 tbox Exp  */
19 
20 /*
21  * Copyright (c) 1999-2000 by Nortel Networks Corporation
22  *
23  * Permission to use, copy, modify, and distribute this software for any
24  * purpose with or without fee is hereby granted, provided that the above
25  * copyright notice and this permission notice appear in all copies.
26  *
27  * THE SOFTWARE IS PROVIDED "AS IS" AND NORTEL NETWORKS DISCLAIMS
28  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
29  * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NORTEL NETWORKS
30  * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
31  * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
32  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
33  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
34  * SOFTWARE.
35  */
36 
37 /*
38  * Define this to make a standalone installer that will copy msvcrt.dll
39  * and/or msvcrtd.dll during the install
40  */
41 // #define BINARIES_INSTALL
42 
43 /*
44  * msvcrt.dll is the release c-runtime library for MSVC.  msvcrtd.dll
45  * is the debug c-runtime library for MSVC.  If you have debug
46  * binaries you want to have DEBUG_BINARIES defined.  If you have
47  * release binaries you want to have RELEASE_BINARIES defined.
48  * If you have both, then define them both.
49  * Of course, you need msvcrt[d].dll present to install it!
50  */
51 #ifdef BINARIES_INSTALL
52 // #  define DEBUG_BINARIES
53 // #  define RELEASE_BINARIES
54 #endif
55 
56 #include "stdafx.h"
57 #include "BINDInstall.h"
58 #include "BINDInstallDlg.h"
59 #include "DirBrowse.h"
60 #include <winsvc.h>
61 #include <shlobj.h>
62 #include <named/ntservice.h>
63 #include <isc/bind_registry.h>
64 #include <isc/ntgroups.h>
65 #include <direct.h>
66 #include "AccountInfo.h"
67 #include "versioninfo.h"
68 
69 #include <config.h>
70 
71 #define MAX_GROUPS	100
72 #define MAX_PRIVS	 50
73 
74 #define LOCAL_SERVICE "NT AUTHORITY\\LocalService"
75 
76 #ifdef _DEBUG
77 #define new DEBUG_NEW
78 #undef THIS_FILE
79 static char THIS_FILE[] = __FILE__;
80 #endif
81 
82 typedef struct _xexception
83 {
84 	_xexception(UINT string, ...);
85 
86 	CString resString;
87 } Exception;
88 
_xexception(UINT string,...)89 _xexception::_xexception(UINT string, ...)
90 {
91 	CString format;
92 	va_list va;
93 
94 	format.LoadString(string);
95 
96 	va_start(va, string);
97 	resString.FormatV(format, va);
98 	va_end(va);
99 }
100 
101 typedef struct _filedata {
102 	enum FileDestinations {TargetDir, BinDir, EtcDir, WinSystem};
103 	enum FileImportance {Trivial, Normal, Critical};
104 
105 	char *filename;
106 	int destination;
107 	int importance;
108 	BOOL checkVer;
109 	BOOL withTools;
110 } FileData;
111 
112 const FileData installFiles[] =
113 {
114 #ifdef BINARIES_INSTALL
115 #  ifdef DEBUG_BINARIES
116 	{"msvcrtd.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
117 #  endif
118 #  ifdef RELEASE_BINARIES
119 	{"msvcrt.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
120 #  endif
121 #endif
122 #if _MSC_VER < 1400
123 #if _MSC_VER >= 1310
124 	{"mfc71.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
125 	{"msvcr71.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
126 #elif _MSC_VER > 1200 && _MSC_VER < 1310
127 	{"mfc70.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
128 	{"msvcr70.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
129 #endif
130 #endif
131 	{"bindevt.dll", FileData::BinDir, FileData::Normal, FALSE, TRUE},
132 	{"libbind9.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
133 	{"libisc.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
134 	{"libisccfg.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
135 	{"libisccc.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
136 	{"libdns.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
137 	{"liblwres.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
138 	{"libirs.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
139 #ifdef OPENSSL
140 	{"libeay32.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
141 #endif
142 #ifdef HAVE_LIBXML2
143 	{"libxml2.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
144 #endif
145 #ifdef USE_GSSAPI
146 #ifndef _WIN64
147 	{"gssapi32.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
148 	{"krb5_32.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
149 #else
150 	{"gssapi64.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
151 	{"krb5_64.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
152 #endif
153 #endif
154 #ifdef HAVE_GEOIP
155 	{"libgeoip.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
156 #endif
157 #ifdef WITH_IDN
158 	{"idnkit.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
159 	{"iconv.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
160 #endif
161 	{"named.exe", FileData::BinDir, FileData::Critical, FALSE, FALSE},
162 	{"nsupdate.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
163 	{"BINDInstall.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
164 	{"rndc.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
165 	{"dig.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
166 	{"host.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
167 	{"nslookup.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
168 	{"delv.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
169 	{"arpaname.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
170 	{"nsec3hash.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
171 	{"genrandom.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
172 	{"rndc-confgen.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
173 	{"ddns-confgen.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
174 	{"tsig-keygen.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
175 	{"dnssec-keygen.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
176 	{"dnssec-signzone.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
177 	{"dnssec-dsfromkey.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
178 	{"dnssec-importkey.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
179 	{"dnssec-keyfromlabel.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
180 	{"dnssec-revoke.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
181 	{"dnssec-settime.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
182 	{"dnssec-verify.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
183 	{"named-checkconf.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
184 	{"named-checkzone.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
185 	{"named-compilezone.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
186 	{"named-journalprint.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
187 	{"named-rrchecker.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
188 	{"isc-hmax-fixup.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
189 #ifdef USE_PKCS11
190 	{"pkcs11-destroy.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
191 	{"pkcs11-keygen.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
192 	{"pkcs11-list.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
193 	{"pkcs11-tokens.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
194 #endif
195 #ifdef USE_PYTHON
196 	{"dnssec-checkds.py", FileData::BinDir, FileData::Normal, FALSE, FALSE},
197 	{"dnssec-coverage.py", FileData::BinDir, FileData::Normal, FALSE, FALSE},
198 #endif
199 	{"readme1st.txt", FileData::BinDir, FileData::Trivial, FALSE, TRUE},
200 	{NULL, -1, -1}
201 };
202 
203 /////////////////////////////////////////////////////////////////////////////
204 // CBINDInstallDlg dialog
205 
CBINDInstallDlg(CWnd * pParent)206 CBINDInstallDlg::CBINDInstallDlg(CWnd* pParent /*=NULL*/)
207 	: CDialog(CBINDInstallDlg::IDD, pParent) {
208 	char winsys[MAX_PATH];
209 	char progfiles[MAX_PATH];
210 
211 	//{{AFX_DATA_INIT(CBINDInstallDlg)
212 	m_targetDir = _T("");
213 	m_version = _T("");
214 	m_toolsOnly = FALSE;
215 	m_autoStart = FALSE;
216 	m_keepFiles = FALSE;
217 	m_current = _T("");
218 	m_startOnInstall = FALSE;
219 	m_accountName = _T("");
220 	m_accountPassword = _T("");
221 	m_accountName = _T("");
222 	//}}AFX_DATA_INIT
223 	// Note that LoadIcon does not require a subsequent
224 	// DestroyIcon in Win32
225 	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
226 
227 	GetSystemDirectory(winsys, MAX_PATH);
228 	m_winSysDir = winsys;
229 
230 #ifndef _WIN64
231 	SHGetFolderPath(NULL, CSIDL_FLAG_CREATE|CSIDL_PROGRAM_FILESX86,
232 			NULL, SHGFP_TYPE_CURRENT, progfiles);
233 #else
234 	SHGetFolderPath(NULL, CSIDL_FLAG_CREATE|CSIDL_PROGRAM_FILES,
235 			NULL, SHGFP_TYPE_CURRENT, progfiles);
236 #endif
237 
238 	m_defaultDir = progfiles;
239 	m_defaultDir += "\\ISC BIND 9";
240 	m_installed = FALSE;
241 	m_accountExists = FALSE;
242 	m_accountUsed = FALSE;
243 	m_serviceExists = TRUE;
244 	GetCurrentServiceAccountName();
245 	m_currentAccount = m_accountName;
246 	if (m_accountName == "") {
247 		m_accountName = "named";
248 	}
249 }
250 
DoDataExchange(CDataExchange * pDX)251 void CBINDInstallDlg::DoDataExchange(CDataExchange* pDX) {
252 	CDialog::DoDataExchange(pDX);
253 	//{{AFX_DATA_MAP(CBINDInstallDlg)
254 	DDX_Text(pDX, IDC_TARGETDIR, m_targetDir);
255 	DDX_Text(pDX, IDC_VERSION, m_version);
256 	DDX_Text(pDX, IDC_ACCOUNT_NAME, m_accountName);
257 	DDX_Text(pDX, IDC_ACCOUNT_PASSWORD, m_accountPassword);
258 	DDX_Text(pDX, IDC_ACCOUNT_PASSWORD_CONFIRM, m_accountPasswordConfirm);
259 	DDX_Check(pDX, IDC_TOOLS_ONLY, m_toolsOnly);
260 	DDX_Check(pDX, IDC_AUTO_START, m_autoStart);
261 	DDX_Check(pDX, IDC_KEEP_FILES, m_keepFiles);
262 	DDX_Text(pDX, IDC_CURRENT, m_current);
263 	DDX_Check(pDX, IDC_START, m_startOnInstall);
264 	//}}AFX_DATA_MAP
265 }
266 
BEGIN_MESSAGE_MAP(CBINDInstallDlg,CDialog)267 BEGIN_MESSAGE_MAP(CBINDInstallDlg, CDialog)
268 	//{{AFX_MSG_MAP(CBINDInstallDlg)
269 	ON_WM_PAINT()
270 	ON_WM_QUERYDRAGICON()
271 	ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
272 	ON_BN_CLICKED(IDC_INSTALL, OnInstall)
273 	ON_BN_CLICKED(IDC_EXIT, OnExit)
274 	ON_BN_CLICKED(IDC_UNINSTALL, OnUninstall)
275 	//}}AFX_MSG_MAP
276 END_MESSAGE_MAP()
277 
278 /////////////////////////////////////////////////////////////////////////////
279 // CBINDInstallDlg message handlers
280 
281 BOOL CBINDInstallDlg::OnInitDialog() {
282 	CDialog::OnInitDialog();
283 
284 	// Set the icon for this dialog.  The framework does this automatically
285 	//  when the application's main window is not a dialog
286 	SetIcon(m_hIcon, TRUE);			// Set big icon
287 	SetIcon(m_hIcon, FALSE);		// Set small icon
288 
289 	char filename[MAX_PATH];
290 	char dirname[MAX_PATH];
291 	char *fptr = &filename[0];
292 	GetModuleFileName(NULL, filename, MAX_PATH);
293 	char *dptr = strrchr(filename,'\\');
294 	size_t index = dptr - fptr;
295 	strncpy(dirname, filename, index);
296 	dirname[index] = '\0';
297 	CString Dirname(dirname);
298 	m_currentDir = Dirname;
299 
300 	CVersionInfo bindInst(filename);
301 	if(bindInst.IsValid())
302 		m_version.Format(IDS_VERSION, bindInst.GetFileVersionString());
303 	else
304 		m_version.LoadString(IDS_NO_VERSION);
305 
306 	DWORD dwBufLen = MAX_PATH;
307 	char buf[MAX_PATH];
308 	HKEY hKey;
309 
310 	m_startOnInstall = CheckBINDService();
311 
312 	/* See if we are installed already */
313 	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SUBKEY, 0, KEY_READ, &hKey)
314 			== ERROR_SUCCESS) {
315 		m_installed = TRUE;
316 		memset(buf, 0, MAX_PATH);
317 		// Get the install directory
318 		if (RegQueryValueEx(hKey, "InstallDir", NULL, NULL, (LPBYTE)buf,
319 			&dwBufLen) == ERROR_SUCCESS)
320 			if (strcmp(buf, ""))
321 				m_defaultDir = buf;
322 
323 		RegCloseKey(hKey);
324 	}
325 	m_targetDir = m_defaultDir;
326 
327 	// Set checkbox defaults
328 	m_autoStart = TRUE;
329 	m_keepFiles = TRUE;
330 
331 	UpdateData(FALSE);
332 
333 	return (TRUE); /* return(TRUE) unless you set the focus to a control */
334 }
335 
336 /*
337  *  If you add a minimize button to your dialog, you will need the code below
338  *  to draw the icon.  For MFC applications using the document/view model,
339  *  this is automatically done for you by the framework.
340  */
341 
OnPaint()342 void CBINDInstallDlg::OnPaint() {
343 	if (IsIconic())	{
344 		CPaintDC dc(this); // device context for painting
345 
346 		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
347 
348 		// Center icon in client rectangle
349 		int cxIcon = GetSystemMetrics(SM_CXICON);
350 		int cyIcon = GetSystemMetrics(SM_CYICON);
351 		CRect rect;
352 		GetClientRect(&rect);
353 		int x = (rect.Width() - cxIcon + 1) / 2;
354 		int y = (rect.Height() - cyIcon + 1) / 2;
355 
356 		// Draw the icon
357 		dc.DrawIcon(x, y, m_hIcon);
358 	}
359 	else {
360 		CDialog::OnPaint();
361 	}
362 }
363 
364 // The system calls this to obtain the cursor to display while the user drags
365 //  the minimized window.
OnQueryDragIcon()366 HCURSOR CBINDInstallDlg::OnQueryDragIcon() {
367 	return((HCURSOR)m_hIcon);
368 }
369 
OnBrowse()370 void CBINDInstallDlg::OnBrowse() {
371 
372 	CDirBrowse browse;
373 
374 	if (browse.DoModal() == IDOK) 	{
375 		//m_targetDir = browse.m_selectedDir;
376 		UpdateData(FALSE);
377 	}
378 }
379 
380 /*
381  * User pressed the exit button
382  */
OnExit()383 void CBINDInstallDlg::OnExit() {
384 	EndDialog(0);
385 }
386 
387 /*
388  * User pressed the uninstall button.  Make it go.
389  */
OnUninstall()390 void CBINDInstallDlg::OnUninstall() {
391 	UpdateData();
392 
393 	if (MsgBox(IDS_UNINSTALL, MB_YESNO) == IDYES) {
394 		if (CheckBINDService())
395 			StopBINDService();
396 
397 		SC_HANDLE hSCManager = OpenSCManager(NULL, NULL,
398 					SC_MANAGER_ALL_ACCESS);
399 		if (!hSCManager) {
400 			MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
401 			return;
402 		}
403 
404 		SC_HANDLE hService = OpenService(hSCManager, BIND_SERVICE_NAME,
405 					      SERVICE_ALL_ACCESS);
406 		if (!hService && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST){
407 			MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
408 			return;
409 		}
410 
411 		SERVICE_STATUS ss;
412 		QueryServiceStatus(hService, &ss);
413 		if (ss.dwCurrentState == SERVICE_RUNNING) {
414 			BOOL rc = ControlService(hService,
415 						 SERVICE_CONTROL_STOP, &ss);
416 			if (rc == FALSE || ss.dwCurrentState != SERVICE_STOPPED) {
417 				MsgBox(IDS_ERR_STOP_SERVICE, GetErrMessage());
418 				return;
419 			}
420 
421 		}
422 		CloseServiceHandle(hService);
423 		CloseServiceHandle(hSCManager);
424 
425 		// Directories
426 		m_etcDir = m_targetDir + "\\etc";
427 		m_binDir = m_targetDir + "\\bin";
428 
429 		UninstallTags();
430 		UnregisterMessages(TRUE);
431 		UnregisterService(TRUE);
432 		DeleteFiles(TRUE);
433 		if (m_keepFiles == FALSE)
434 			RemoveDirs(TRUE);
435 		else
436 			GetDlgItem(IDC_CREATE_DIR)->SetWindowText("Not Removed");
437 
438 
439 		// Delete registry keys for named
440 		RegDeleteKey(HKEY_LOCAL_MACHINE, BIND_SESSION_SUBKEY);
441 		RegDeleteKey(HKEY_LOCAL_MACHINE, BIND_SUBKEY);
442 		RegDeleteKey(HKEY_LOCAL_MACHINE, BIND_UNINSTALL_SUBKEY);
443 
444 		ProgramGroup(FALSE);
445 
446 		SetCurrent(IDS_UNINSTALL_DONE);
447 		MsgBox(IDS_UNINSTALL_DONE);
448 	}
449 }
450 
451 /*
452  * User pressed the install button.  Make it go.
453  */
OnInstall()454 void CBINDInstallDlg::OnInstall() {
455 #if _MSC_VER >= 1400
456 	char Vcredist_x86[MAX_PATH];
457 #endif
458 	BOOL success = FALSE;
459 	int oldlen;
460 
461 	if (CheckBINDService())
462 		StopBINDService();
463 
464 	InstallTags();
465 
466 	UpdateData();
467 
468 	if (!m_toolsOnly && m_accountName != LOCAL_SERVICE) {
469 		/*
470 		 * Check that the Passwords entered match.
471 		 */
472 		if (m_accountPassword != m_accountPasswordConfirm) {
473 			MsgBox(IDS_ERR_PASSWORD);
474 			return;
475 		}
476 
477 		/*
478 		 * Check that there is not leading / trailing whitespace.
479 		 * This is for compatibility with the standard password dialog.
480 		 * Passwords really should be treated as opaque blobs.
481 		 */
482 		oldlen = m_accountPassword.GetLength();
483 		m_accountPassword.TrimLeft();
484 		m_accountPassword.TrimRight();
485 		if (m_accountPassword.GetLength() != oldlen) {
486 			MsgBox(IDS_ERR_WHITESPACE);
487 			return;
488 		}
489 
490 		/*
491 		 * Check the entered account name.
492 		 */
493 		if (ValidateServiceAccount() == FALSE)
494 			return;
495 
496 		/*
497 		 * For Registration we need to know if account was changed.
498 		 */
499 		if (m_accountName != m_currentAccount)
500 			m_accountUsed = FALSE;
501 
502 		if (m_accountUsed == FALSE && m_serviceExists == FALSE)
503 		{
504 		/*
505 		 * Check that the Password is not null.
506 		 */
507 			if (m_accountPassword.GetLength() == 0) {
508 				MsgBox(IDS_ERR_NULLPASSWORD);
509 				return;
510 			}
511 		}
512 	} else if (m_accountName == LOCAL_SERVICE) {
513 		/* The LocalService always exists. */
514 		m_accountExists = TRUE;
515 		if (m_accountName != m_currentAccount)
516 			m_accountUsed = FALSE;
517 	}
518 
519 	/* Directories */
520 	m_etcDir = m_targetDir + "\\etc";
521 	m_binDir = m_targetDir + "\\bin";
522 
523 	if (m_defaultDir != m_targetDir) {
524 		if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF)
525 		{
526 			int install = MsgBox(IDS_DIREXIST,
527 					MB_YESNO | MB_ICONQUESTION, m_targetDir);
528 			if (install == IDNO)
529 				return;
530 		}
531 		else {
532 			int createDir = MsgBox(IDS_CREATEDIR,
533 					MB_YESNO | MB_ICONQUESTION, m_targetDir);
534 			if (createDir == IDNO)
535 				return;
536 		}
537 	}
538 
539 	if (!m_toolsOnly) {
540 		if (m_accountExists == FALSE) {
541 			success = CreateServiceAccount(m_accountName.GetBuffer(30),
542 						       m_accountPassword.GetBuffer(30));
543 			if (success == FALSE) {
544 				MsgBox(IDS_CREATEACCOUNT_FAILED);
545 				return;
546 			}
547 			m_accountExists = TRUE;
548 		}
549 	}
550 
551 	ProgramGroup(FALSE);
552 
553 #if _MSC_VER >= 1400
554 	/*
555 	 * Install Visual Studio libraries.  As per:
556 	 * http://blogs.msdn.com/astebner/archive/2006/08/23/715755.aspx
557 	 *
558 	 * Vcredist_x86.exe /q:a /c:"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log"
559 	 */
560 	/*system(".\\Vcredist_x86.exe /q:a /c:\"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log\"");*/
561 
562 	/*
563 	 * Enclose full path to Vcredist_x86.exe in quotes as
564 	 * m_currentDir may contain spaces.
565 	 */
566 #ifndef _WIN64
567 	sprintf(Vcredist_x86, "\"%s\\Vcredist_x86.exe\"",
568 		(LPCTSTR) m_currentDir);
569 #else
570 	sprintf(Vcredist_x86, "\"%s\\Vcredist_x64.exe\"",
571 		(LPCTSTR) m_currentDir);
572 #endif
573 	system(Vcredist_x86);
574 #endif
575 	try {
576 		CreateDirs();
577 		CopyFiles();
578 		if (!m_toolsOnly)
579 			RegisterService();
580 		RegisterMessages();
581 
582 		HKEY hKey;
583 
584 		/* Create a new key for named */
585 		SetCurrent(IDS_CREATE_KEY);
586 		if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_SUBKEY,
587 			&hKey) == ERROR_SUCCESS) {
588 			// Get the install directory
589 			RegSetValueEx(hKey, "InstallDir", 0, REG_SZ,
590 					(LPBYTE)(LPCTSTR)m_targetDir,
591 					m_targetDir.GetLength());
592 			RegCloseKey(hKey);
593 		}
594 
595 
596 		SetCurrent(IDS_ADD_REMOVE);
597 		if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_UNINSTALL_SUBKEY,
598 				 &hKey) == ERROR_SUCCESS) {
599 			CString buf(BIND_DISPLAY_NAME);
600 
601 			RegSetValueEx(hKey, "DisplayName", 0, REG_SZ,
602 					(LPBYTE)(LPCTSTR)buf, buf.GetLength());
603 
604 			buf.Format("%s\\BINDInstall.exe", m_binDir);
605 			RegSetValueEx(hKey, "UninstallString", 0, REG_SZ,
606 					(LPBYTE)(LPCTSTR)buf, buf.GetLength());
607 			RegCloseKey(hKey);
608 		}
609 
610 		ProgramGroup(FALSE);
611 
612 		if (m_startOnInstall)
613 			StartBINDService();
614 	}
615 	catch(Exception e) {
616 		MessageBox(e.resString);
617 		SetCurrent(IDS_CLEANUP);
618 		FailedInstall();
619 		MsgBox(IDS_FAIL);
620 		return;
621 	}
622 	catch(DWORD dw)	{
623 		CString msg;
624 		msg.Format("A fatal error occured\n(%s)", GetErrMessage(dw));
625 		MessageBox(msg);
626 		SetCurrent(IDS_CLEANUP);
627 		FailedInstall();
628 		MsgBox(IDS_FAIL);
629 		return;
630 	}
631 
632 	SetCurrent(IDS_INSTALL_DONE);
633 	MsgBox(IDS_SUCCESS);
634 }
635 
636 /*
637  * Methods to do the work
638  */
CreateDirs()639 void CBINDInstallDlg::CreateDirs() {
640 	/* s'OK if the directories already exist */
641 	SetCurrent(IDS_CREATE_DIR, m_targetDir);
642 	if (!CreateDirectory(m_targetDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
643 		throw(Exception(IDS_ERR_CREATE_DIR, m_targetDir, GetErrMessage()));
644 
645 	SetCurrent(IDS_CREATE_DIR, m_etcDir);
646 	if (!CreateDirectory(m_etcDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
647 		throw(Exception(IDS_ERR_CREATE_DIR, m_etcDir, GetErrMessage()));
648 
649 	SetCurrent(IDS_CREATE_DIR, m_binDir);
650 	if (!CreateDirectory(m_binDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
651 		throw(Exception(IDS_ERR_CREATE_DIR, m_binDir, GetErrMessage()));
652 
653 	SetItemStatus(IDC_CREATE_DIR);
654 }
655 
RemoveDirs(BOOL uninstall)656 void CBINDInstallDlg::RemoveDirs(BOOL uninstall) {
657 	if (!m_keepFiles) {
658 		SetCurrent(IDS_REMOVE_DIR, m_binDir);
659 		// Check for existence then remove if present
660 		if (GetFileAttributes(m_binDir) != 0xFFFFFFFF)
661 			RemoveDirectory(m_binDir);
662 
663 		SetCurrent(IDS_REMOVE_DIR, m_etcDir);
664 		if (GetFileAttributes(m_etcDir) != 0xFFFFFFFF)
665 			RemoveDirectory(m_etcDir);
666 
667 		SetCurrent(IDS_REMOVE_DIR, m_targetDir);
668 		if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF)
669 			RemoveDirectory(m_targetDir);
670 	}
671 
672 	if (uninstall)
673 		SetItemStatus(IDC_CREATE_DIR, TRUE);
674 }
675 
CopyFiles()676 void CBINDInstallDlg::CopyFiles() {
677 	CString destFile;
678 
679 	for (int i = 0; installFiles[i].filename; i++) {
680 		if (m_toolsOnly && !installFiles[i].withTools)
681 			continue;
682 		SetCurrent(IDS_COPY_FILE, installFiles[i].filename);
683 
684 		destFile = DestDir(installFiles[i].destination) + "\\" +
685 				   installFiles[i].filename;
686 		CString filespec = m_currentDir + "\\" + installFiles[i].filename;
687 		CVersionInfo bindFile(destFile);
688 
689 		CVersionInfo origFile(filespec);
690 		if (!origFile.IsValid() && installFiles[i].checkVer) {
691 			if (MsgBox(IDS_FILE_BAD, MB_YESNO,
692 				  installFiles[i].filename) == IDNO)
693 				throw(Exception(IDS_ERR_COPY_FILE,
694 					installFiles[i].filename,
695 					GetErrMessage()));
696 		}
697 
698 		try {
699 /*
700  * Ignore Version checking.  We need to make sure that all files get
701  * copied regardless of whether or not they are earlier or later
702  * versions since we cannot guarantee that we have either backward or
703  * forward compatibility between versions.
704  */
705 			bindFile.CopyFileNoVersion(origFile);
706 		}
707 		catch(...) {
708 			if (installFiles[i].importance != FileData::Trivial) {
709 				if (installFiles[i].importance ==
710 					FileData::Critical ||
711 					MsgBox(IDS_ERR_NONCRIT_FILE, MB_YESNO,
712 					installFiles[i].filename,
713 					GetErrMessage()) == IDNO)
714 				{
715 					SetItemStatus(IDC_COPY_FILE, FALSE);
716 					throw(Exception(IDS_ERR_COPY_FILE,
717 						installFiles[i].filename,
718 						GetErrMessage()));
719 				}
720 			}
721 		}
722 	}
723 
724 	SetItemStatus(IDC_COPY_FILE);
725 }
726 
DeleteFiles(BOOL uninstall)727 void CBINDInstallDlg::DeleteFiles(BOOL uninstall) {
728 	CString destFile;
729 
730 	for (int i = 0; installFiles[i].filename; i++) {
731 		if (installFiles[i].checkVer)
732 			continue;
733 
734 		destFile = DestDir(installFiles[i].destination) + "\\" +
735 				   installFiles[i].filename;
736 
737 		if (uninstall)
738 			SetCurrent(IDS_DELETE_FILE, installFiles[i].filename);
739 
740 		DeleteFile(destFile);
741 	}
742 
743 	if (!m_keepFiles) {
744 		WIN32_FIND_DATA findData;
745 		CString file = m_etcDir + "\\*.*";
746 		BOOL rc;
747 		HANDLE hFile;
748 
749 		hFile = FindFirstFile(file, &findData);
750 		rc = hFile != INVALID_HANDLE_VALUE;
751 
752 		while (rc == TRUE) {
753 			if (strcmp(findData.cFileName, ".") &&
754 			    strcmp(findData.cFileName, "..")) {
755 				file = m_etcDir + "\\" + findData.cFileName;
756 				SetCurrent(IDS_DELETE_FILE, file);
757 				DeleteFile(file);
758 			}
759 			rc = FindNextFile(hFile, &findData);
760 		}
761 		FindClose(hFile);
762 	}
763 
764 	if (uninstall)
765 		SetItemStatus(IDC_COPY_FILE, TRUE);
766 }
767 
768 /*
769  * Get the service account name out of the registry, if any
770  */
771 void
GetCurrentServiceAccountName()772 CBINDInstallDlg::GetCurrentServiceAccountName() {
773 	HKEY hKey;
774 	BOOL keyFound = FALSE;
775 	char accountName[MAX_PATH];
776 	DWORD nameLen = MAX_PATH;
777 	CString Tmp;
778 	m_accountUsed = FALSE;
779 
780 	memset(accountName, 0, nameLen);
781 	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SERVICE_SUBKEY, 0, KEY_READ,
782 		&hKey) == ERROR_SUCCESS) {
783 		keyFound = TRUE;
784 	}
785 	else {
786 		m_serviceExists = FALSE;
787 	}
788 
789 	if (keyFound == TRUE) {
790 		/* Get the named service account, if one was specified */
791 		if (RegQueryValueEx(hKey, "ObjectName", NULL, NULL,
792 			(LPBYTE)accountName, &nameLen) != ERROR_SUCCESS)
793 			keyFound = FALSE;
794 	}
795 
796 	RegCloseKey(hKey);
797 	if (keyFound == FALSE)
798 		m_accountName = "";
799 	else if (!strcmp(accountName, LOCAL_SERVICE)) {
800 		m_accountName = LOCAL_SERVICE;
801 		m_accountUsed = TRUE;
802 	} else {
803 		/*
804 		 * LocalSystem is not a regular account and is equivalent
805 		 * to no account but with lots of privileges
806 		 */
807 		Tmp = accountName;
808 		if (Tmp == ".\\LocalSystem")
809 			m_accountName = "";
810 		/* Found account strip any ".\" from it */
811 		if (Tmp.Left(2) == ".\\") {
812 			m_accountName = Tmp.Mid(2);
813 			m_accountUsed = TRUE;
814 		}
815 	}
816 }
817 
818 BOOL
ValidateServiceAccount()819 CBINDInstallDlg::ValidateServiceAccount() {
820 	wchar_t *PrivList[MAX_PRIVS];
821 	unsigned int PrivCount = 0;
822 	char *Groups[MAX_GROUPS];
823 	unsigned int totalGroups = 0;
824 	int status;
825 	char *name;
826 
827 	name = m_accountName.GetBuffer(30);
828 
829 	status = GetAccountPrivileges(name, PrivList, &PrivCount,
830 		 Groups, &totalGroups, MAX_GROUPS);
831 	if (status == RTN_NOACCOUNT) {
832 		m_accountExists = FALSE;
833 		/* We need to do this in case an account was previously used */
834 		m_accountUsed = FALSE;
835 		return (TRUE);
836 	}
837 	if (status != RTN_OK) {
838 		MsgBox(IDS_ERR_BADACCOUNT);
839 		return (FALSE);
840 	}
841 
842 	m_accountExists = TRUE;
843 	if (PrivCount > 1) {
844 		if (MsgBox(IDS_ERR_TOOPRIVED, MB_YESNO) == IDYES)
845 			return (FALSE);
846 		else
847 			return (TRUE);
848 	}
849 
850 	/* See if we have the correct privilege */
851 	if (wcscmp(PrivList[0], SE_SERVICE_LOGON_PRIV) != 0) {
852 		MsgBox(IDS_ERR_WRONGPRIV, PrivList[0]);
853 		return (FALSE);
854 	}
855 	return (TRUE);
856 }
857 
858 void
RegisterService()859 CBINDInstallDlg::RegisterService() {
860 	SC_HANDLE hSCManager;
861 	SC_HANDLE hService;
862 	CString StartName;
863 
864 	if (m_accountName == LOCAL_SERVICE)
865 		StartName = LOCAL_SERVICE;
866 	else
867 		StartName = ".\\" + m_accountName;
868 	/*
869 	 * We need to change the service rather than create it
870 	 * if the service already exists. Do nothing if we are already
871 	 * using that account
872 	 */
873 	if (m_serviceExists == TRUE) {
874 		if (m_accountUsed == FALSE) {
875 			UpdateService(StartName);
876 			SetItemStatus(IDC_REG_SERVICE);
877 			return;
878 		} else {
879 			SetItemStatus(IDC_REG_SERVICE);
880 			return;
881 		}
882 	}
883 
884 	SetCurrent(IDS_OPEN_SCM);
885 	hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
886 	if (!hSCManager)
887 		throw(Exception(IDS_ERR_OPEN_SCM, GetErrMessage()));
888 
889 	DWORD dwStart = SERVICE_DEMAND_START;
890 	if (m_autoStart)
891 		dwStart = SERVICE_AUTO_START;
892 
893 	DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;
894 
895 	CString namedLoc;
896 	namedLoc.Format("%s\\bin\\named.exe", m_targetDir);
897 
898 	SetCurrent(IDS_CREATE_SERVICE);
899 	hService = CreateService(hSCManager, BIND_SERVICE_NAME,
900 		BIND_DISPLAY_NAME, SERVICE_ALL_ACCESS, dwServiceType, dwStart,
901 		SERVICE_ERROR_NORMAL, namedLoc, NULL, NULL, NULL, StartName,
902 		m_accountPassword);
903 
904 	if (!hService && GetLastError() != ERROR_SERVICE_EXISTS)
905 		throw(Exception(IDS_ERR_CREATE_SERVICE, GetErrMessage()));
906 
907 	if (hService)
908 		CloseServiceHandle(hService);
909 
910 	if (hSCManager)
911 		CloseServiceHandle(hSCManager);
912 
913 	SetItemStatus(IDC_REG_SERVICE);
914 }
915 
916 void
UpdateService(CString StartName)917 CBINDInstallDlg::UpdateService(CString StartName) {
918 	SC_HANDLE hSCManager;
919 	SC_HANDLE hService;
920 
921 	if(m_toolsOnly)
922 		return;
923 
924 	SetCurrent(IDS_OPEN_SCM);
925 	hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
926 	if (!hSCManager) {
927 		MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
928 		return;
929 	}
930 
931 	DWORD dwStart = SERVICE_DEMAND_START;
932 	if (m_autoStart)
933 		dwStart = SERVICE_AUTO_START;
934 
935 	DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;
936 
937 	CString namedLoc;
938 	namedLoc.Format("%s\\bin\\named.exe", m_targetDir);
939 
940 	SetCurrent(IDS_OPEN_SERVICE);
941 	hService = OpenService(hSCManager, BIND_SERVICE_NAME,
942 			       SERVICE_CHANGE_CONFIG);
943 	if (!hService)
944 	{
945 		MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
946 		if (hSCManager)
947 			CloseServiceHandle(hSCManager);
948 		return;
949 	} else {
950 		if (ChangeServiceConfig(hService, dwServiceType, dwStart,
951 			SERVICE_ERROR_NORMAL, namedLoc, NULL, NULL, NULL,
952 			StartName, m_accountPassword, BIND_DISPLAY_NAME)
953 			!= TRUE) {
954 			DWORD err = GetLastError();
955 			MsgBox(IDS_ERR_UPDATE_SERVICE, GetErrMessage());
956 		}
957 	}
958 
959 	if (hService)
960 		CloseServiceHandle(hService);
961 
962 	if (hSCManager)
963 		CloseServiceHandle(hSCManager);
964 
965 	SetItemStatus(IDC_REG_SERVICE);
966 }
967 
UnregisterService(BOOL uninstall)968 void CBINDInstallDlg::UnregisterService(BOOL uninstall) {
969 	BOOL rc = FALSE;
970 	SC_HANDLE hSCManager;
971 	SC_HANDLE hService;
972 
973 	while(1) {
974 		SetCurrent(IDS_OPEN_SCM);
975 		hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
976 		if (!hSCManager && uninstall == TRUE) {
977 			MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
978 			break;
979 		}
980 
981 		SetCurrent(IDS_OPEN_SERVICE);
982 		hService = OpenService(hSCManager, BIND_SERVICE_NAME,
983 				       STANDARD_RIGHTS_REQUIRED);
984 		if (!hService && uninstall == TRUE)
985 		{
986 			if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) {
987 				MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
988 				break;
989 			}
990 		}
991 		else {
992 			SetCurrent(IDS_REMOVE_SERVICE);
993 			if (!DeleteService(hService) && uninstall == TRUE) {
994 				DWORD err = GetLastError();
995 				if (err != ERROR_SERVICE_MARKED_FOR_DELETE &&
996 				   err != ERROR_SERVICE_DOES_NOT_EXIST) {
997 					MsgBox(IDS_ERR_REMOVE_SERVICE,
998 					       GetErrMessage());
999 					break;
1000 				}
1001 			}
1002 		}
1003 
1004 		rc = TRUE;
1005 		break;
1006 	}
1007 
1008 	if (hService)
1009 		CloseServiceHandle(hService);
1010 
1011 	if (hSCManager)
1012 		CloseServiceHandle(hSCManager);
1013 
1014 	if (uninstall)
1015 		SetItemStatus(IDC_REG_SERVICE, rc);
1016 }
1017 
RegisterMessages()1018 void CBINDInstallDlg::RegisterMessages() {
1019 	HKEY hKey;
1020 	DWORD dwData;
1021 	char pszMsgDLL[MAX_PATH];
1022 
1023 	sprintf(pszMsgDLL, "%s\\%s", (LPCTSTR)m_binDir, "bindevt.dll");
1024 
1025 	SetCurrent(IDS_REGISTER_MESSAGES);
1026 	/* Create a new key for named */
1027 	if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_MESSAGE_SUBKEY, &hKey)
1028 		!= ERROR_SUCCESS)
1029 		throw(Exception(IDS_ERR_CREATE_KEY, GetErrMessage()));
1030 
1031 	/* Add the Event-ID message-file name to the subkey. */
1032 	if (RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ,
1033 		(LPBYTE)pszMsgDLL, (DWORD)(strlen(pszMsgDLL) + 1)) != ERROR_SUCCESS)
1034 		throw(Exception(IDS_ERR_SET_VALUE, GetErrMessage()));
1035 
1036 	/* Set the supported types flags and addit to the subkey. */
1037 	dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
1038 	if (RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD,
1039 		(LPBYTE)&dwData, sizeof(DWORD)) != ERROR_SUCCESS)
1040 		throw(Exception(IDS_ERR_SET_VALUE, GetErrMessage()));
1041 
1042 	RegCloseKey(hKey);
1043 
1044 	SetItemStatus(IDC_REG_MESSAGE);
1045 }
1046 
UnregisterMessages(BOOL uninstall)1047 void CBINDInstallDlg::UnregisterMessages(BOOL uninstall) {
1048 	BOOL rc = FALSE;
1049 	HKEY hKey = NULL;
1050 
1051 	while(1) {
1052 		SetCurrent(IDS_UNREGISTER_MESSAGES);
1053 		/* Open key for Application Event Log */
1054 		if (RegOpenKey(HKEY_LOCAL_MACHINE, EVENTLOG_APP_SUBKEY, &hKey)
1055 			!= ERROR_SUCCESS)
1056 			break;
1057 
1058 		/* Remove named from the list of messages sources */
1059 		if (RegDeleteKey(hKey, BIND_MESSAGE_NAME) != ERROR_SUCCESS)
1060 			break;
1061 
1062 		rc = TRUE;
1063 		break;
1064 	}
1065 
1066 	if (hKey)
1067 		RegCloseKey(hKey);
1068 
1069 	if (uninstall)
1070 		SetItemStatus(IDC_REG_MESSAGE, rc);
1071 }
1072 
1073 /*
1074  * Install failed - clean up quietly
1075  */
FailedInstall()1076 void CBINDInstallDlg::FailedInstall() {
1077 	UnregisterMessages(FALSE);
1078 	UnregisterService(FALSE);
1079 	DeleteFiles(FALSE);
1080 	RemoveDirs(FALSE);
1081 }
1082 
1083 /*
1084  * Set the checklist tags for install
1085  */
InstallTags()1086 void CBINDInstallDlg::InstallTags() {
1087 	CString tag;
1088 
1089 	tag.LoadString(IDS_INSTALL_FILE);
1090 	GetDlgItem(IDC_COPY_TAG)->SetWindowText(tag);
1091 	GetDlgItem(IDC_COPY_FILE)->SetWindowText("");
1092 
1093 	tag.LoadString(IDS_INSTALL_DIR);
1094 	GetDlgItem(IDC_DIR_TAG)->SetWindowText(tag);
1095 	GetDlgItem(IDC_CREATE_DIR)->SetWindowText("");
1096 	GetDlgItem(IDC_REG_SERVICE)->SetWindowText("");
1097 
1098 	tag.LoadString(IDS_INSTALL_SERVICE);
1099 	GetDlgItem(IDC_SERVICE_TAG)->SetWindowText(tag);
1100 
1101 	tag.LoadString(IDS_INSTALL_MESSAGE);
1102 	GetDlgItem(IDC_MESSAGE_TAG)->SetWindowText(tag);
1103 	GetDlgItem(IDC_REG_MESSAGE)->SetWindowText("");
1104 }
1105 
1106 /*
1107  * Set the checklist tags for uninstall
1108  */
UninstallTags()1109 void CBINDInstallDlg::UninstallTags() {
1110 	CString tag;
1111 
1112 	tag.LoadString(IDS_UNINSTALL_FILES);
1113 	GetDlgItem(IDC_COPY_TAG)->SetWindowText(tag);
1114 	GetDlgItem(IDC_COPY_FILE)->SetWindowText("");
1115 
1116 	tag.LoadString(IDS_UNINSTALL_DIR);
1117 	GetDlgItem(IDC_DIR_TAG)->SetWindowText(tag);
1118 	GetDlgItem(IDC_CREATE_DIR)->SetWindowText("");
1119 
1120 	tag.LoadString(IDS_UNINSTALL_SERVICE);
1121 	GetDlgItem(IDC_SERVICE_TAG)->SetWindowText(tag);
1122 	GetDlgItem(IDC_REG_SERVICE)->SetWindowText("");
1123 
1124 	tag.LoadString(IDS_UNINSTALL_MESSAGE);
1125 	GetDlgItem(IDC_MESSAGE_TAG)->SetWindowText(tag);
1126 	GetDlgItem(IDC_REG_MESSAGE)->SetWindowText("");
1127 }
1128 
SetItemStatus(UINT nID,BOOL bSuccess)1129 void CBINDInstallDlg::SetItemStatus(UINT nID, BOOL bSuccess) {
1130 	GetDlgItem(nID)->SetWindowText(bSuccess == TRUE ? "Done" : "Failed");
1131 }
1132 
1133 
1134 /*
1135  * Set the text in the current operation field - use a string table string
1136  */
SetCurrent(int id,...)1137 void CBINDInstallDlg::SetCurrent(int id, ...) {
1138 	CString format;
1139 	va_list va;
1140 	char buf[128];
1141 
1142 	format.LoadString(id);
1143 	memset(buf, 0, 128);
1144 
1145 	va_start(va, id);
1146 	vsprintf(buf, format, va);
1147 	va_end(va);
1148 
1149 	m_current.Format("%s", buf);
1150 	UpdateData(FALSE);
1151 }
1152 
1153 /*
1154  * Stop the BIND service
1155  */
StopBINDService()1156 void CBINDInstallDlg::StopBINDService() {
1157 	SERVICE_STATUS svcStatus;
1158 
1159 	SetCurrent(IDS_STOP_SERVICE);
1160 
1161 	SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1162 	if (!hSCManager) {
1163 		MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
1164 	}
1165 
1166 	SC_HANDLE hBINDSvc = OpenService(hSCManager, BIND_SERVICE_NAME,
1167 				      SERVICE_ALL_ACCESS);
1168 	if (!hBINDSvc) {
1169 		MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
1170 	}
1171 
1172 	BOOL rc = ControlService(hBINDSvc, SERVICE_CONTROL_STOP, &svcStatus);
1173 }
1174 
1175 /*
1176  * Start the BIND service
1177  */
StartBINDService()1178 void CBINDInstallDlg::StartBINDService() {
1179 	SetCurrent(IDS_START_SERVICE);
1180 
1181 	SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1182 	if (!hSCManager) {
1183 		MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
1184 	}
1185 
1186 	SC_HANDLE hBINDSvc = OpenService(hSCManager, BIND_SERVICE_NAME,
1187 				      SERVICE_ALL_ACCESS);
1188 	if (!hBINDSvc) {
1189 		MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
1190 	}
1191 	BOOL rc = StartService(hBINDSvc, 0, NULL);
1192 }
1193 
1194 /*
1195  * Check to see if the BIND service is running or not
1196  */
CheckBINDService()1197 BOOL CBINDInstallDlg::CheckBINDService() {
1198 	SERVICE_STATUS svcStatus;
1199 
1200 	SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1201 	if (hSCManager) {
1202 		SC_HANDLE hBINDSvc = OpenService(hSCManager, BIND_SERVICE_NAME,
1203 					      SERVICE_ALL_ACCESS);
1204 		if (hBINDSvc) {
1205 			BOOL rc = ControlService(hBINDSvc,
1206 				  SERVICE_CONTROL_INTERROGATE, &svcStatus);
1207 			if (!rc)
1208 				DWORD err = GetLastError();
1209 
1210 			return (svcStatus.dwCurrentState == SERVICE_RUNNING);
1211 		}
1212 	}
1213 	return (FALSE);
1214 }
1215 
1216 /*
1217  * Display message boxes with variable args, using string table strings
1218  * for the format specifiers
1219  */
MsgBox(int id,...)1220 int CBINDInstallDlg::MsgBox(int id, ...) {
1221 	CString format;
1222 	va_list va;
1223 	char buf[BUFSIZ];
1224 
1225 	format.LoadString(id);
1226 	memset(buf, 0, BUFSIZ);
1227 
1228 	va_start(va, id);
1229 	vsprintf(buf, format, va);
1230 	va_end(va);
1231 
1232 	return (MessageBox(buf));
1233 }
1234 
MsgBox(int id,UINT type,...)1235 int CBINDInstallDlg::MsgBox(int id, UINT type, ...) {
1236 	CString format;
1237 	va_list va;
1238 	char buf[BUFSIZ];
1239 
1240 	format.LoadString(id);
1241 	memset(buf, 0, BUFSIZ);
1242 
1243 	va_start(va, type);
1244 	vsprintf(buf, format, va);
1245 	va_end(va);
1246 
1247 	return(MessageBox(buf, NULL, type));
1248 }
1249 
1250 /*
1251  * Call GetLastError(), retrieve the message associated with the error
1252  */
GetErrMessage(DWORD err)1253 CString CBINDInstallDlg::GetErrMessage(DWORD err) {
1254 	LPVOID msgBuf;
1255 	static char buf[BUFSIZ];
1256 
1257 	DWORD len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
1258 		NULL, err == -1 ? GetLastError() : err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msgBuf, 0, NULL );
1259 
1260 
1261 	strcpy(buf, (LPTSTR)msgBuf);
1262 	LocalFree(msgBuf);
1263 	/* Strip off the period and the \n */
1264 	buf[len - 3] = 0;
1265 	return(buf);
1266 }
1267 
ProgramGroup(BOOL create)1268 void CBINDInstallDlg::ProgramGroup(BOOL create) {
1269 	TCHAR path[MAX_PATH], commonPath[MAX_PATH], fileloc[MAX_PATH], linkpath[MAX_PATH];
1270 	HRESULT hres;
1271 	IShellLink *psl = NULL;
1272 	LPMALLOC pMalloc = NULL;
1273 	ITEMIDLIST *itemList = NULL;
1274 
1275 	HRESULT hr = SHGetMalloc(&pMalloc);
1276 	if (hr != NOERROR) {
1277 		MessageBox("Could not get a handle to Shell memory object");
1278 		return;
1279 	}
1280 
1281 	hr = SHGetSpecialFolderLocation(m_hWnd, CSIDL_COMMON_PROGRAMS, &itemList);
1282 	if (hr != NOERROR) {
1283 		MessageBox("Could not get a handle to the Common Programs folder");
1284 		if (itemList) {
1285 			pMalloc->Free(itemList);
1286 		}
1287 		return;
1288 	}
1289 
1290 	hr = SHGetPathFromIDList(itemList, commonPath);
1291 	pMalloc->Free(itemList);
1292 
1293 	if (create) {
1294 		sprintf(path, "%s\\ISC", commonPath);
1295 		CreateDirectory(path, NULL);
1296 
1297 		sprintf(path, "%s\\ISC\\BIND", commonPath);
1298 		CreateDirectory(path, NULL);
1299 
1300 		hres = CoInitialize(NULL);
1301 
1302 		if (SUCCEEDED(hres)) {
1303 			// Get a pointer to the IShellLink interface.
1304 			hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl);
1305 			if (SUCCEEDED(hres))
1306 			{
1307 				IPersistFile* ppf;
1308 				sprintf(linkpath, "%s\\BINDCtrl.lnk", path);
1309 				sprintf(fileloc, "%s\\BINDCtrl.exe", m_binDir);
1310 
1311 				psl->SetPath(fileloc);
1312 				psl->SetDescription("BIND Control Panel");
1313 
1314 				hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
1315 				if (SUCCEEDED(hres)) {
1316 					WCHAR wsz[MAX_PATH];
1317 
1318 					MultiByteToWideChar(CP_ACP, 0, linkpath, -1, wsz, MAX_PATH);
1319 					hres = ppf->Save(wsz, TRUE);
1320 					ppf->Release();
1321 				}
1322 
1323 				if (GetFileAttributes("readme.txt") != -1) {
1324 					sprintf(fileloc, "%s\\Readme.txt", m_targetDir);
1325 					sprintf(linkpath, "%s\\Readme.lnk", path);
1326 
1327 					psl->SetPath(fileloc);
1328 					psl->SetDescription("BIND Readme");
1329 
1330 					hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
1331 					if (SUCCEEDED(hres)) {
1332 						WCHAR wsz[MAX_PATH];
1333 
1334 						MultiByteToWideChar(CP_ACP, 0, linkpath, -1, wsz, MAX_PATH);
1335 						hres = ppf->Save(wsz, TRUE);
1336 						ppf->Release();
1337 					}
1338 					psl->Release();
1339 				}
1340 			}
1341 			CoUninitialize();
1342 		}
1343 	}
1344 	else {
1345 		TCHAR filename[MAX_PATH];
1346 		WIN32_FIND_DATA fd;
1347 
1348 		sprintf(path, "%s\\ISC\\BIND", commonPath);
1349 
1350 		sprintf(filename, "%s\\*.*", path);
1351 		HANDLE hFind = FindFirstFile(filename, &fd);
1352 		if (hFind != INVALID_HANDLE_VALUE) {
1353 			do {
1354 				if (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..")) {
1355 					sprintf(filename, "%s\\%s", path, fd.cFileName);
1356 					DeleteFile(filename);
1357 				}
1358 			} while (FindNextFile(hFind, &fd));
1359 			FindClose(hFind);
1360 		}
1361 		RemoveDirectory(path);
1362 		sprintf(path, "%s\\ISC", commonPath);
1363 		RemoveDirectory(path);
1364 	}
1365 }
1366 
DestDir(int destination)1367 CString CBINDInstallDlg::DestDir(int destination) {
1368 	switch(destination) {
1369 		case FileData::TargetDir:
1370 			return m_targetDir;
1371 		case FileData::BinDir:
1372 			return m_binDir;
1373 		case FileData::EtcDir:
1374 			return m_etcDir;
1375 		case FileData::WinSystem:
1376 			return m_winSysDir;
1377 	}
1378 	return("");
1379 }
1380