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