BINDInstallDlg.cpp 34 KB
Newer Older
1
/*
Automatic Updater's avatar
Automatic Updater committed
2
 * Portions Copyright (C) 2004-2009  Internet Systems Consortium, Inc. ("ISC")
Mark Andrews's avatar
Mark Andrews committed
3
 * Portions Copyright (C) 2001, 2003  Internet Software Consortium.
4
 *
Automatic Updater's avatar
Automatic Updater committed
5
 * Permission to use, copy, modify, and/or distribute this software for any
6 7 8
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
Mark Andrews's avatar
Mark Andrews committed
9 10 11 12 13 14 15
 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 * PERFORMANCE OF THIS SOFTWARE.
16 17
 */

18
/* $Id: BINDInstallDlg.cpp,v 1.44 2009/09/01 06:51:47 marka Exp $ */
Andreas Gustafsson's avatar
Andreas Gustafsson committed
19

20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
/*
 * Copyright (c) 1999-2000 by Nortel Networks Corporation
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND NORTEL NETWORKS DISCLAIMS
 * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NORTEL NETWORKS
 * BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES
 * OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 * SOFTWARE.
 */

/*
 * Define this to make a standalone installer that will copy msvcrt.dll
 * and/or msvcrtd.dll during the install
 */
// #define BINARIES_INSTALL

/*
 * msvcrt.dll is the release c-runtime library for MSVC.  msvcrtd.dll is the debug
 * c-runtime library for MSVC.  If you have debug binaries you want to have DEBUG_BINARIES
 * defined.  If you have release binaries you want to have RELEASE_BINARIES defined.
 * If you have both, then define them both.
 * Of course, you need msvcrt[d].dll present to install it!
 */
#ifdef BINARIES_INSTALL
// #  define DEBUG_BINARIES
// #  define RELEASE_BINARIES
#endif

#include "stdafx.h"
#include "BINDInstall.h"
#include "BINDInstallDlg.h"
#include "DirBrowse.h"
#include <winsvc.h>
#include <named/ntservice.h>
#include <isc/bind_registry.h>
62
#include <isc/ntgroups.h>
63
#include <direct.h>
64
#include "AccountInfo.h"
65 66
#include "versioninfo.h"

67 68
#include <config.h>

69 70 71
#define MAX_GROUPS	100
#define MAX_PRIVS	 50

72 73
#define LOCAL_SERVICE "NT AUTHORITY\\LocalService"

74 75 76 77 78 79
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

Mark Andrews's avatar
Mark Andrews committed
80
typedef struct _xexception
81
{
Mark Andrews's avatar
Mark Andrews committed
82
	_xexception(UINT string, ...);
Automatic Updater's avatar
Automatic Updater committed
83

84 85 86
	CString resString;
} Exception;

Mark Andrews's avatar
Mark Andrews committed
87
_xexception::_xexception(UINT string, ...)
88 89 90 91 92 93 94 95 96 97 98
{
	CString format;
	va_list va;

	format.LoadString(string);

	va_start(va, string);
	resString.FormatV(format, va);
	va_end(va);
}

99
typedef struct _filedata {
100 101 102 103 104 105 106
	enum FileDestinations {TargetDir, BinDir, EtcDir, WinSystem};
	enum FileImportance {Trivial, Normal, Critical};

	char *filename;
	int destination;
	int importance;
	BOOL checkVer;
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
107
	BOOL withTools;
108 109 110 111 112 113
} FileData;

const FileData installFiles[] =
{
#ifdef BINARIES_INSTALL
#  ifdef DEBUG_BINARIES
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
114
	{"msvcrtd.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
115 116
#  endif
#  ifdef RELEASE_BINARIES
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
117
	{"msvcrt.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
118 119
#  endif
#endif
Mark Andrews's avatar
win32  
Mark Andrews committed
120 121
#if _MSC_VER < 1400
#if _MSC_VER >= 1310
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
122 123
	{"mfc71.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
	{"msvcr71.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
124
#elif _MSC_VER > 1200 && _MSC_VER < 1310
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
125 126
	{"mfc70.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
	{"msvcr70.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
Mark Andrews's avatar
win32  
Mark Andrews committed
127
#endif
128
#endif
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
129 130 131 132 133 134 135 136
	{"bindevt.dll", FileData::BinDir, FileData::Normal, FALSE, TRUE},
	{"libbind9.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
	{"libisc.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
	{"libisccfg.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
	{"libisccc.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
	{"libdns.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
	{"liblwres.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
	{"libeay32.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
137
#ifdef HAVE_LIBXML2
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
138
	{"libxml2.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
139
#endif
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157
	{"named.exe", FileData::BinDir, FileData::Critical, FALSE, FALSE},
	{"nsupdate.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
	{"BINDInstall.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
	{"rndc.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"dig.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
	{"host.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
	{"nslookup.exe", FileData::BinDir, FileData::Normal, FALSE, TRUE},
	{"rndc-confgen.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"ddns-confgen.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"dnssec-keygen.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"dnssec-signzone.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"dnssec-dsfromkey.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"dnssec-keyfromlabel.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"dnssec-revoke.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"named-checkconf.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"named-checkzone.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"named-compilezone.exe", FileData::BinDir, FileData::Normal, FALSE, FALSE},
	{"readme1st.txt", FileData::BinDir, FileData::Trivial, FALSE, TRUE},
158 159 160 161 162 163 164
	{NULL, -1, -1}
};

/////////////////////////////////////////////////////////////////////////////
// CBINDInstallDlg dialog

CBINDInstallDlg::CBINDInstallDlg(CWnd* pParent /*=NULL*/)
165
	: CDialog(CBINDInstallDlg::IDD, pParent) {
166 167 168 169 170
	char buf[MAX_PATH];

	//{{AFX_DATA_INIT(CBINDInstallDlg)
	m_targetDir = _T("");
	m_version = _T("");
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
171
	m_toolsOnly = FALSE;
172 173 174 175
	m_autoStart = FALSE;
	m_keepFiles = FALSE;
	m_current = _T("");
	m_startOnInstall = FALSE;
176 177 178
	m_accountName = _T("");
	m_accountPassword = _T("");
	m_accountName = _T("");
179 180 181 182 183 184 185 186
	//}}AFX_DATA_INIT
	// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);

	GetSystemDirectory(buf, MAX_PATH);
	m_winSysDir = buf;
	m_defaultDir = buf;
	m_defaultDir += "\\dns";
187 188 189
	m_installed = FALSE;
	m_accountExists = FALSE;
	m_accountUsed = FALSE;
190
	m_serviceExists = TRUE;
191
	GetCurrentServiceAccountName();
192
	m_currentAccount = m_accountName;
193 194 195
	if (m_accountName == "") {
		m_accountName = "named";
	}
196 197
}

198
void CBINDInstallDlg::DoDataExchange(CDataExchange* pDX) {
199 200 201 202
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CBINDInstallDlg)
	DDX_Text(pDX, IDC_TARGETDIR, m_targetDir);
	DDX_Text(pDX, IDC_VERSION, m_version);
203 204 205
	DDX_Text(pDX, IDC_ACCOUNT_NAME, m_accountName);
	DDX_Text(pDX, IDC_ACCOUNT_PASSWORD, m_accountPassword);
	DDX_Text(pDX, IDC_ACCOUNT_PASSWORD_CONFIRM, m_accountPasswordConfirm);
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
206
	DDX_Check(pDX, IDC_TOOLS_ONLY, m_toolsOnly);
207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227
	DDX_Check(pDX, IDC_AUTO_START, m_autoStart);
	DDX_Check(pDX, IDC_KEEP_FILES, m_keepFiles);
	DDX_Text(pDX, IDC_CURRENT, m_current);
	DDX_Check(pDX, IDC_START, m_startOnInstall);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CBINDInstallDlg, CDialog)
	//{{AFX_MSG_MAP(CBINDInstallDlg)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BROWSE, OnBrowse)
	ON_BN_CLICKED(IDC_INSTALL, OnInstall)
	ON_BN_CLICKED(IDC_EXIT, OnExit)
	ON_BN_CLICKED(IDC_UNINSTALL, OnUninstall)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CBINDInstallDlg message handlers

228
BOOL CBINDInstallDlg::OnInitDialog() {
229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	char filename[MAX_PATH];
	char dirname[MAX_PATH];
	char *fptr = &filename[0];
	GetModuleFileName(NULL, filename, MAX_PATH);
	char *dptr = strrchr(filename,'\\');
	int index = dptr - fptr;
	strncpy(dirname, filename, index);
	dirname[index] = '\0';
	CString Dirname(dirname);
	m_currentDir = Dirname;
Automatic Updater's avatar
Automatic Updater committed
246

247 248 249 250 251 252 253 254 255 256 257 258 259
	CVersionInfo bindInst(filename);
	if(bindInst.IsValid())
		m_version.Format(IDS_VERSION, bindInst.GetFileVersionString());
	else
		m_version.LoadString(IDS_NO_VERSION);

	DWORD dwBufLen = MAX_PATH;
	char buf[MAX_PATH];
	HKEY hKey;

	m_startOnInstall = CheckBINDService();

	/* See if we are installed already */
260 261 262
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SUBKEY, 0, KEY_READ, &hKey)
			== ERROR_SUCCESS) {
		m_installed = TRUE;
263 264
		memset(buf, 0, MAX_PATH);
		// Get the install directory
265 266 267
		if (RegQueryValueEx(hKey, "InstallDir", NULL, NULL, (LPBYTE)buf,
			&dwBufLen) == ERROR_SUCCESS)
			if (strcmp(buf, ""))
268
				m_defaultDir = buf;
Automatic Updater's avatar
Automatic Updater committed
269

270 271 272 273 274 275 276 277 278 279
		RegCloseKey(hKey);
	}
	m_targetDir = m_defaultDir;

	// Set checkbox defaults
	m_autoStart = TRUE;
	m_keepFiles = TRUE;

	UpdateData(FALSE);

280
	return (TRUE); /* return(TRUE) unless you set the focus to a control */
281 282
}

283 284 285 286 287
/*
 *  If you add a minimize button to your dialog, you will need the code below
 *  to draw the icon.  For MFC applications using the document/view model,
 *  this is automatically done for you by the framework.
 */
288

289 290
void CBINDInstallDlg::OnPaint() {
	if (IsIconic())	{
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
306
	else {
307 308 309 310 311 312
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
313
HCURSOR CBINDInstallDlg::OnQueryDragIcon() {
314 315 316
	return((HCURSOR)m_hIcon);
}

317
void CBINDInstallDlg::OnBrowse() {
318 319 320

	CDirBrowse browse;

321
	if (browse.DoModal() == IDOK) 	{
322 323 324 325 326 327 328 329
		//m_targetDir = browse.m_selectedDir;
		UpdateData(FALSE);
	}
}

/*
 * User pressed the exit button
 */
330
void CBINDInstallDlg::OnExit() {
Automatic Updater's avatar
Automatic Updater committed
331
	EndDialog(0);
332 333 334 335 336
}

/*
 * User pressed the uninstall button.  Make it go.
 */
337
void CBINDInstallDlg::OnUninstall() {
Automatic Updater's avatar
Automatic Updater committed
338
	UpdateData();
339

340 341
	if (MsgBox(IDS_UNINSTALL, MB_YESNO) == IDYES) {
		if (CheckBINDService())
342 343
			StopBINDService();

Mark Andrews's avatar
Mark Andrews committed
344
		SC_HANDLE hSCManager = OpenSCManager(NULL, NULL,
345
					SC_MANAGER_ALL_ACCESS);
346
		if (!hSCManager) {
347 348 349
			MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
			return;
		}
Automatic Updater's avatar
Automatic Updater committed
350

Mark Andrews's avatar
Mark Andrews committed
351
		SC_HANDLE hService = OpenService(hSCManager, BIND_SERVICE_NAME,
352
					      SERVICE_ALL_ACCESS);
353
		if (!hService && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST){
354 355 356 357 358 359
			MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
			return;
		}

		SERVICE_STATUS ss;
		QueryServiceStatus(hService, &ss);
360 361
		if (ss.dwCurrentState == SERVICE_RUNNING) {
			BOOL rc = ControlService(hService,
Automatic Updater's avatar
Automatic Updater committed
362
						 SERVICE_CONTROL_STOP, &ss);
363
			if (rc == FALSE || ss.dwCurrentState != SERVICE_STOPPED) {
364 365 366 367 368 369 370
				MsgBox(IDS_ERR_STOP_SERVICE, GetErrMessage());
				return;
			}

		}
		CloseServiceHandle(hService);
		CloseServiceHandle(hSCManager);
Automatic Updater's avatar
Automatic Updater committed
371

372 373 374 375 376 377 378 379
		// Directories
		m_etcDir = m_targetDir + "\\etc";
		m_binDir = m_targetDir + "\\bin";

		UninstallTags();
		UnregisterMessages(TRUE);
		UnregisterService(TRUE);
		DeleteFiles(TRUE);
380
		if (m_keepFiles == FALSE)
381 382 383 384
			RemoveDirs(TRUE);
		else
			GetDlgItem(IDC_CREATE_DIR)->SetWindowText("Not Removed");

Automatic Updater's avatar
Automatic Updater committed
385

386 387 388 389
		// Delete registry keys for named
		RegDeleteKey(HKEY_LOCAL_MACHINE, BIND_SESSION_SUBKEY);
		RegDeleteKey(HKEY_LOCAL_MACHINE, BIND_SUBKEY);
		RegDeleteKey(HKEY_LOCAL_MACHINE, BIND_UNINSTALL_SUBKEY);
Automatic Updater's avatar
Automatic Updater committed
390

391 392 393 394 395 396 397 398 399 400
		ProgramGroup(FALSE);

		SetCurrent(IDS_UNINSTALL_DONE);
		MsgBox(IDS_UNINSTALL_DONE);
	}
}

/*
 * User pressed the install button.  Make it go.
 */
401
void CBINDInstallDlg::OnInstall() {
402 403 404
#if _MSC_VER >= 1400
	char Vcredist_x86[MAX_PATH];
#endif
405
	BOOL success = FALSE;
406
	int oldlen;
407

408
	if (CheckBINDService())
409 410 411 412 413 414
		StopBINDService();

	InstallTags();

	UpdateData();

415
	if (!m_toolsOnly && m_accountName != LOCAL_SERVICE) {
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
416 417 418 419 420 421 422
		/*
		 * Check that the Passwords entered match.
		 */
		if (m_accountPassword != m_accountPasswordConfirm) {
			MsgBox(IDS_ERR_PASSWORD);
			return;
		}
423

Mark Andrews's avatar
CHANGES  
Mark Andrews committed
424 425 426 427 428 429 430 431 432 433 434 435
		/*
		 * Check that there is not leading / trailing whitespace.
		 * This is for compatibility with the standard password dialog.
		 * Passwords really should be treated as opaque blobs.
		 */
		oldlen = m_accountPassword.GetLength();
		m_accountPassword.TrimLeft();
		m_accountPassword.TrimRight();
		if (m_accountPassword.GetLength() != oldlen) {
			MsgBox(IDS_ERR_WHITESPACE);
			return;
		}
Automatic Updater's avatar
Automatic Updater committed
436

Mark Andrews's avatar
CHANGES  
Mark Andrews committed
437 438 439 440 441
		/*
		 * Check the entered account name.
		 */
		if (ValidateServiceAccount() == FALSE)
			return;
442

Mark Andrews's avatar
CHANGES  
Mark Andrews committed
443 444 445 446 447
		/*
		 * For Registration we need to know if account was changed.
		 */
		if (m_accountName != m_currentAccount)
			m_accountUsed = FALSE;
448

Mark Andrews's avatar
CHANGES  
Mark Andrews committed
449 450 451 452 453 454 455 456 457
		if (m_accountUsed == FALSE && m_serviceExists == FALSE)
		{
		/*
		 * Check that the Password is not null.
		 */
			if (m_accountPassword.GetLength() == 0) {
				MsgBox(IDS_ERR_NULLPASSWORD);
				return;
			}
458
		}
459 460 461 462 463
	} else if (m_accountName == LOCAL_SERVICE) {
		/* The LocalService always exists. */
		m_accountExists = TRUE;
		if (m_accountName != m_currentAccount)
			m_accountUsed = FALSE;
464 465
	}

466
	/* Directories */
467 468 469
	m_etcDir = m_targetDir + "\\etc";
	m_binDir = m_targetDir + "\\bin";

470 471
	if (m_defaultDir != m_targetDir) {
		if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF)
472
		{
473 474
			int install = MsgBox(IDS_DIREXIST,
					MB_YESNO | MB_ICONQUESTION, m_targetDir);
475
			if (install == IDNO)
476 477
				return;
		}
478
		else {
479 480
			int createDir = MsgBox(IDS_CREATEDIR,
					MB_YESNO | MB_ICONQUESTION, m_targetDir);
481
			if (createDir == IDNO)
482 483 484 485
				return;
		}
	}

Mark Andrews's avatar
CHANGES  
Mark Andrews committed
486 487 488 489 490 491 492 493 494
	if (!m_toolsOnly) {
		if (m_accountExists == FALSE) {
			success = CreateServiceAccount(m_accountName.GetBuffer(30),
							m_accountPassword.GetBuffer(30));
			if (success == FALSE) {
				MsgBox(IDS_CREATEACCOUNT_FAILED);
				return;
			}
			m_accountExists = TRUE;
495 496 497
		}
	}

498
	ProgramGroup(FALSE);
499

500 501
#if _MSC_VER >= 1400
	/*
Mark Andrews's avatar
win32  
Mark Andrews committed
502 503 504 505
	 * Install Visual Studio libraries.  As per:
	 * http://blogs.msdn.com/astebner/archive/2006/08/23/715755.aspx
	 *
	 * Vcredist_x86.exe /q:a /c:"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log"
506
	 */
Mark Andrews's avatar
win32  
Mark Andrews committed
507
	/*system(".\\Vcredist_x86.exe /q:a /c:\"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log\"");*/
508 509 510 511 512 513 514 515

	/*
	 * Enclose full path to Vcredist_x86.exe in quotes as
	 * m_currentDir may contain spaces.
	 */
	sprintf(Vcredist_x86, "\"%s\\Vcredist_x86.exe\"",
		(LPCTSTR) m_currentDir);
	system(Vcredist_x86);
516
#endif
517
	try {
518
		CreateDirs();
Automatic Updater's avatar
Automatic Updater committed
519
		CopyFiles();
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
520 521
		if (!m_toolsOnly)
			RegisterService();
522 523 524 525 526 527
		RegisterMessages();

		HKEY hKey;

		/* Create a new key for named */
		SetCurrent(IDS_CREATE_KEY);
528 529
		if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_SUBKEY,
			&hKey) == ERROR_SUCCESS) {
530
			// Get the install directory
531 532 533
			RegSetValueEx(hKey, "InstallDir", 0, REG_SZ,
					(LPBYTE)(LPCTSTR)m_targetDir,
					m_targetDir.GetLength());
534 535 536
			RegCloseKey(hKey);
		}

Automatic Updater's avatar
Automatic Updater committed
537

538
		SetCurrent(IDS_ADD_REMOVE);
539
		if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_UNINSTALL_SUBKEY,
540
				 &hKey) == ERROR_SUCCESS) {
541 542
			CString buf(BIND_DISPLAY_NAME);

543 544
			RegSetValueEx(hKey, "DisplayName", 0, REG_SZ,
					(LPBYTE)(LPCTSTR)buf, buf.GetLength());
545

546
			buf.Format("%s\\BINDInstall.exe", m_binDir);
547 548
			RegSetValueEx(hKey, "UninstallString", 0, REG_SZ,
					(LPBYTE)(LPCTSTR)buf, buf.GetLength());
549 550
			RegCloseKey(hKey);
		}
Automatic Updater's avatar
Automatic Updater committed
551

552
		ProgramGroup(FALSE);
Automatic Updater's avatar
Automatic Updater committed
553

554
		if (m_startOnInstall)
555 556
			StartBINDService();
	}
557
	catch(Exception e) {
558 559 560 561 562 563
		MessageBox(e.resString);
		SetCurrent(IDS_CLEANUP);
		FailedInstall();
		MsgBox(IDS_FAIL);
		return;
	}
564
	catch(DWORD dw)	{
565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
		CString msg;
		msg.Format("A fatal error occured\n(%s)", GetErrMessage(dw));
		MessageBox(msg);
		SetCurrent(IDS_CLEANUP);
		FailedInstall();
		MsgBox(IDS_FAIL);
		return;
	}

	SetCurrent(IDS_INSTALL_DONE);
	MsgBox(IDS_SUCCESS);
}

/*
 * Methods to do the work
 */
581
void CBINDInstallDlg::CreateDirs() {
582 583
	/* s'OK if the directories already exist */
	SetCurrent(IDS_CREATE_DIR, m_targetDir);
584
	if (!CreateDirectory(m_targetDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
585 586 587
		throw(Exception(IDS_ERR_CREATE_DIR, m_targetDir, GetErrMessage()));

	SetCurrent(IDS_CREATE_DIR, m_etcDir);
588
	if (!CreateDirectory(m_etcDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
589 590 591
		throw(Exception(IDS_ERR_CREATE_DIR, m_etcDir, GetErrMessage()));

	SetCurrent(IDS_CREATE_DIR, m_binDir);
592
	if (!CreateDirectory(m_binDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
593
		throw(Exception(IDS_ERR_CREATE_DIR, m_binDir, GetErrMessage()));
Automatic Updater's avatar
Automatic Updater committed
594

595 596 597
	SetItemStatus(IDC_CREATE_DIR);
}

598 599
void CBINDInstallDlg::RemoveDirs(BOOL uninstall) {
	if (!m_keepFiles) {
600 601
		SetCurrent(IDS_REMOVE_DIR, m_binDir);
		// Check for existence then remove if present
602
		if (GetFileAttributes(m_binDir) != 0xFFFFFFFF)
603 604 605
			RemoveDirectory(m_binDir);

		SetCurrent(IDS_REMOVE_DIR, m_etcDir);
606
		if (GetFileAttributes(m_etcDir) != 0xFFFFFFFF)
607 608 609
			RemoveDirectory(m_etcDir);

		SetCurrent(IDS_REMOVE_DIR, m_targetDir);
610
		if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF)
611 612 613
			RemoveDirectory(m_targetDir);
	}

614
	if (uninstall)
615 616 617
		SetItemStatus(IDC_CREATE_DIR, TRUE);
}

618
void CBINDInstallDlg::CopyFiles() {
619 620
	CString destFile;

621
	for (int i = 0; installFiles[i].filename; i++) {
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
622 623
		if (m_toolsOnly && !installFiles[i].withTools)
			continue;
624 625
		SetCurrent(IDS_COPY_FILE, installFiles[i].filename);

626 627
		destFile = DestDir(installFiles[i].destination) + "\\" +
				   installFiles[i].filename;
628
		CString filespec = m_currentDir + "\\" + installFiles[i].filename;
629
		CVersionInfo bindFile(destFile);
Automatic Updater's avatar
Automatic Updater committed
630

631
		CVersionInfo origFile(filespec);
632 633 634 635 636 637
		if (!origFile.IsValid() && installFiles[i].checkVer) {
			if (MsgBox(IDS_FILE_BAD, MB_YESNO,
				  installFiles[i].filename) == IDNO)
				throw(Exception(IDS_ERR_COPY_FILE,
					installFiles[i].filename,
					GetErrMessage()));
638
		}
Automatic Updater's avatar
Automatic Updater committed
639

640
		try {
Automatic Updater's avatar
Automatic Updater committed
641
/*
642 643 644 645
 * Ignore Version checking.  We need to make sure that all files get copied regardless
 * of whether or not they are earlier or later versions since we cannot guarantee
 * that we have either backward or forward compatibility between versions.
 */
646 647
			bindFile.CopyFileNoVersion(origFile);
		}
648 649
		catch(...) {
			if (installFiles[i].importance != FileData::Trivial) {
Automatic Updater's avatar
Automatic Updater committed
650
				if (installFiles[i].importance ==
651 652 653 654
					FileData::Critical ||
					MsgBox(IDS_ERR_NONCRIT_FILE, MB_YESNO,
					installFiles[i].filename,
					GetErrMessage()) == IDNO)
655 656
				{
					SetItemStatus(IDC_COPY_FILE, FALSE);
657 658 659
					throw(Exception(IDS_ERR_COPY_FILE,
						installFiles[i].filename,
						GetErrMessage()));
660 661 662 663 664 665 666 667
				}
			}
		}
	}

	SetItemStatus(IDC_COPY_FILE);
}

668
void CBINDInstallDlg::DeleteFiles(BOOL uninstall) {
669 670
	CString destFile;

671 672
	for (int i = 0; installFiles[i].filename; i++) {
		if (installFiles[i].checkVer)
673 674
			continue;

675 676
		destFile = DestDir(installFiles[i].destination) + "\\" +
				   installFiles[i].filename;
Automatic Updater's avatar
Automatic Updater committed
677

678
		if (uninstall)
679
			SetCurrent(IDS_DELETE_FILE, installFiles[i].filename);
Automatic Updater's avatar
Automatic Updater committed
680

681 682 683
		DeleteFile(destFile);
	}

684
	if (!m_keepFiles) {
685 686 687 688
		WIN32_FIND_DATA findData;
		CString file = m_etcDir + "\\*.*";
		BOOL rc;
		HANDLE hFile;
Automatic Updater's avatar
Automatic Updater committed
689

690 691
		hFile = FindFirstFile(file, &findData);
		rc = hFile != INVALID_HANDLE_VALUE;
Automatic Updater's avatar
Automatic Updater committed
692

693 694 695
		while (rc == TRUE) {
			if (strcmp(findData.cFileName, ".") &&
			    strcmp(findData.cFileName, "..")) {
696 697 698 699 700 701 702 703 704
				file = m_etcDir + "\\" + findData.cFileName;
				SetCurrent(IDS_DELETE_FILE, file);
				DeleteFile(file);
			}
			rc = FindNextFile(hFile, &findData);
		}
		FindClose(hFile);
	}

705
	if (uninstall)
706
		SetItemStatus(IDC_COPY_FILE, TRUE);
Automatic Updater's avatar
Automatic Updater committed
707
}
708

709 710 711 712 713 714 715
/*
 * Get the service account name out of the registry, if any
 */
void
CBINDInstallDlg::GetCurrentServiceAccountName() {
	HKEY hKey;
	BOOL keyFound = FALSE;
716 717
	char accountName[MAX_PATH];
	DWORD nameLen = MAX_PATH;
718 719 720 721 722
	CString Tmp;
	m_accountUsed = FALSE;

	memset(accountName, 0, nameLen);
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SERVICE_SUBKEY, 0, KEY_READ,
723
		&hKey) == ERROR_SUCCESS) {
724
		keyFound = TRUE;
725 726 727 728
	}
	else {
		m_serviceExists = FALSE;
	}
Automatic Updater's avatar
Automatic Updater committed
729

730 731 732 733 734 735
	if (keyFound == TRUE) {
		/* Get the named service account, if one was specified */
		if (RegQueryValueEx(hKey, "ObjectName", NULL, NULL,
			(LPBYTE)accountName, &nameLen) != ERROR_SUCCESS)
			keyFound = FALSE;
	}
736

737
	RegCloseKey(hKey);
738
	if (keyFound == FALSE)
739
		m_accountName = "";
740 741 742 743 744 745 746 747
	else if (!strcmp(accountName, LOCAL_SERVICE)) {
		m_accountName = LOCAL_SERVICE;
		m_accountUsed = TRUE;
	} else {
		/*
		 * LocalSystem is not a regular account and is equivalent
		 * to no account but with lots of privileges
		 */
748 749 750 751 752 753 754 755 756 757
		Tmp = accountName;
		if (Tmp == ".\\LocalSystem")
			m_accountName = "";
		/* Found account strip any ".\" from it */
		if (Tmp.Left(2) == ".\\") {
			m_accountName = Tmp.Mid(2);
			m_accountUsed = TRUE;
		}
	}
}
758

759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
BOOL
CBINDInstallDlg::ValidateServiceAccount() {
	wchar_t *PrivList[MAX_PRIVS];
	unsigned int PrivCount = 0;
	char *Groups[MAX_GROUPS];
	unsigned int totalGroups = 0;
	int status;
	char *name;

	name = m_accountName.GetBuffer(30);

	status = GetAccountPrivileges(name, PrivList, &PrivCount,
		 Groups, &totalGroups, MAX_GROUPS);
	if (status == RTN_NOACCOUNT) {
		m_accountExists = FALSE;
		/* We need to do this in case an account was previously used */
		m_accountUsed = FALSE;
		return (TRUE);
	}
	if (status != RTN_OK) {
		MsgBox(IDS_ERR_BADACCOUNT);
		return (FALSE);
	}

	m_accountExists = TRUE;
	if (PrivCount > 1) {
		if (MsgBox(IDS_ERR_TOOPRIVED, MB_YESNO) == IDYES)
			return (FALSE);
		else
			return (TRUE);
	}

791 792 793 794 795 796
	/* See if we have the correct privilege */
	if (wcscmp(PrivList[0], SE_SERVICE_LOGON_PRIV) != 0) {
		MsgBox(IDS_ERR_WRONGPRIV, PrivList[0]);
		return (FALSE);
	}
	return (TRUE);
797 798 799 800
}

void
CBINDInstallDlg::RegisterService() {
Mark Andrews's avatar
Mark Andrews committed
801 802
	SC_HANDLE hSCManager;
	SC_HANDLE hService;
803
	CString StartName;
Mark Andrews's avatar
CHANGES  
Mark Andrews committed
804

805 806 807 808
	if (m_accountName == LOCAL_SERVICE)
		StartName = LOCAL_SERVICE;
	else
		StartName = ".\\" + m_accountName;
809 810 811 812 813
	/*
	 * We need to change the service rather than create it
	 * if the service already exists. Do nothing if we are already
	 * using that account
	 */
814 815 816
	if (m_serviceExists == TRUE) {
		if (m_accountUsed == FALSE) {
			UpdateService(StartName);
817
			SetItemStatus(IDC_REG_SERVICE);
818
			return;
819
		} else {
820
			SetItemStatus(IDC_REG_SERVICE);
821 822 823
			return;
		}
	}
824 825 826

	SetCurrent(IDS_OPEN_SCM);
	hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
827
	if (!hSCManager)
828 829 830
		throw(Exception(IDS_ERR_OPEN_SCM, GetErrMessage()));

	DWORD dwStart = SERVICE_DEMAND_START;
831
	if (m_autoStart)
832 833 834 835 836 837 838 839
		dwStart = SERVICE_AUTO_START;

	DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;

	CString namedLoc;
	namedLoc.Format("%s\\bin\\named.exe", m_targetDir);

	SetCurrent(IDS_CREATE_SERVICE);
840 841
	hService = CreateService(hSCManager, BIND_SERVICE_NAME,
		BIND_DISPLAY_NAME, SERVICE_ALL_ACCESS, dwServiceType, dwStart,
842
		SERVICE_ERROR_NORMAL, namedLoc, NULL, NULL, NULL, StartName,
Automatic Updater's avatar
Automatic Updater committed
843 844
		m_accountPassword);

845
	if (!hService && GetLastError() != ERROR_SERVICE_EXISTS)
846 847
		throw(Exception(IDS_ERR_CREATE_SERVICE, GetErrMessage()));

848 849 850
	if (hService)
		CloseServiceHandle(hService);

851
	if (hSCManager)
852 853
		CloseServiceHandle(hSCManager);

854 855 856 857
	SetItemStatus(IDC_REG_SERVICE);
}

void
858
CBINDInstallDlg::UpdateService(CString StartName) {
Mark Andrews's avatar
Mark Andrews committed
859 860
	SC_HANDLE hSCManager;
	SC_HANDLE hService;
861

Mark Andrews's avatar
CHANGES  
Mark Andrews committed
862 863 864
	if(m_toolsOnly)
		return;

865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889
	SetCurrent(IDS_OPEN_SCM);
	hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (!hSCManager) {
		MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
		return;
	}

	DWORD dwStart = SERVICE_DEMAND_START;
	if (m_autoStart)
		dwStart = SERVICE_AUTO_START;

	DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;

	CString namedLoc;
	namedLoc.Format("%s\\bin\\named.exe", m_targetDir);

	SetCurrent(IDS_OPEN_SERVICE);
	hService = OpenService(hSCManager, BIND_SERVICE_NAME,
			       SERVICE_CHANGE_CONFIG);
	if (!hService)
	{
		MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
		if (hSCManager)
			CloseServiceHandle(hSCManager);
		return;
890
	} else {
891 892
		if (ChangeServiceConfig(hService, dwServiceType, dwStart,
			SERVICE_ERROR_NORMAL, namedLoc, NULL, NULL, NULL,
893
			StartName, m_accountPassword, BIND_DISPLAY_NAME)
894 895 896 897 898 899
			!= TRUE) {
			DWORD err = GetLastError();
			MsgBox(IDS_ERR_UPDATE_SERVICE, GetErrMessage());
		}
	}

900
	if (hService)
901 902
		CloseServiceHandle(hService);

903 904 905
	if (hSCManager)
		CloseServiceHandle(hSCManager);

906 907 908
	SetItemStatus(IDC_REG_SERVICE);
}

909
void CBINDInstallDlg::UnregisterService(BOOL uninstall) {
910
	BOOL rc = FALSE;
Mark Andrews's avatar
Mark Andrews committed
911 912
	SC_HANDLE hSCManager;
	SC_HANDLE hService;
913

914
	while(1) {
915 916
		SetCurrent(IDS_OPEN_SCM);
		hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
917
		if (!hSCManager && uninstall == TRUE) {
918 919 920 921 922
			MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
			break;
		}

		SetCurrent(IDS_OPEN_SERVICE);
923 924 925
		hService = OpenService(hSCManager, BIND_SERVICE_NAME,
				       STANDARD_RIGHTS_REQUIRED);
		if (!hService && uninstall == TRUE)
926
		{
927
			if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) {
928 929 930 931
				MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
				break;
			}
		}
932
		else {
933
			SetCurrent(IDS_REMOVE_SERVICE);
934
			if (!DeleteService(hService) && uninstall == TRUE) {
935
				DWORD err = GetLastError();
936 937
				if (err != ERROR_SERVICE_MARKED_FOR_DELETE &&
				   err != ERROR_SERVICE_DOES_NOT_EXIST) {
938 939 940 941 942 943 944 945 946 947
					MsgBox(IDS_ERR_REMOVE_SERVICE, GetErrMessage());
					break;
				}
			}
		}

		rc = TRUE;
		break;
	}

948
	if (hService)
949 950
		CloseServiceHandle(hService);

951 952 953
	if (hSCManager)
		CloseServiceHandle(hSCManager);

954
	if (uninstall)
955 956 957
		SetItemStatus(IDC_REG_SERVICE, rc);
}

958
void CBINDInstallDlg::RegisterMessages() {
959 960
	HKEY hKey;
	DWORD dwData;
961
	char pszMsgDLL[MAX_PATH];
962

963
	sprintf(pszMsgDLL, "%s\\%s", (LPCTSTR)m_binDir, "bindevt.dll");
964 965 966

	SetCurrent(IDS_REGISTER_MESSAGES);
	/* Create a new key for named */
967 968
	if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_MESSAGE_SUBKEY, &hKey)
		!= ERROR_SUCCESS)
969
		throw(Exception(IDS_ERR_CREATE_KEY, GetErrMessage()));
Automatic Updater's avatar
Automatic Updater committed
970

971
	/* Add the Event-ID message-file name to the subkey. */
972 973
	if (RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ,
		(LPBYTE)pszMsgDLL, strlen(pszMsgDLL) + 1) != ERROR_SUCCESS)
974 975 976 977
		throw(Exception(IDS_ERR_SET_VALUE, GetErrMessage()));

	/* Set the supported types flags and addit to the subkey. */
	dwData = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
978 979
	if (RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD,
		(LPBYTE)&dwData, sizeof(DWORD)) != ERROR_SUCCESS)
980 981 982
		throw(Exception(IDS_ERR_SET_VALUE, GetErrMessage()));

	RegCloseKey(hKey);
Automatic Updater's avatar
Automatic Updater committed
983

984 985 986
	SetItemStatus(IDC_REG_MESSAGE);
}

987
void CBINDInstallDlg::UnregisterMessages(BOOL uninstall) {
988 989 990
	BOOL rc = FALSE;
	HKEY hKey = NULL;

991
	while(1) {
992 993
		SetCurrent(IDS_UNREGISTER_MESSAGES);
		/* Open key for Application Event Log */
994 995
		if (RegOpenKey(HKEY_LOCAL_MACHINE, EVENTLOG_APP_SUBKEY, &hKey)
			!= ERROR_SUCCESS)
996 997 998
			break;

		/* Remove named from the list of messages sources */
Danny Mayer's avatar