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