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