BINDInstallDlg.cpp 31.5 KB
Newer Older
1
/*
Mark Andrews's avatar
Mark Andrews committed
2
3
 * Portions Copyright (C) 2004  Internet Systems Consortium, Inc. ("ISC")
 * Portions Copyright (C) 2001, 2003  Internet Software Consortium.
4
5
6
7
8
 *
 * 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.
 *
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
 */

Mark Andrews's avatar
Mark Andrews committed
18
/* $Id: BINDInstallDlg.cpp,v 1.14 2004/03/09 04:25:06 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
69
#define MAX_GROUPS	100
#define MAX_PRIVS	 50

70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

typedef struct _exception
{
	_exception(UINT string, ...);
	
	CString resString;
} Exception;

_exception::_exception(UINT string, ...)
{
	CString format;
	va_list va;

	format.LoadString(string);

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

95
typedef struct _filedata {
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
	enum FileDestinations {TargetDir, BinDir, EtcDir, WinSystem};
	enum FileImportance {Trivial, Normal, Critical};

	char *filename;
	int destination;
	int importance;
	BOOL checkVer;

} FileData;

const FileData installFiles[] =
{
#ifdef BINARIES_INSTALL
#  ifdef DEBUG_BINARIES
	{"msvcrtd.dll", FileData::WinSystem, FileData::Critical, TRUE},
#  endif
#  ifdef RELEASE_BINARIES
	{"msvcrt.dll", FileData::WinSystem, FileData::Critical, TRUE},
#  endif
#endif
Mark Andrews's avatar
Mark Andrews committed
116
117
	{"mfc70.dll", FileData::WinSystem, FileData::Critical, TRUE},
	{"msvcr70.dll", FileData::WinSystem, FileData::Critical, TRUE},
118
	{"bindevt.dll", FileData::WinSystem, FileData::Normal, FALSE},
119
	{"libbind9.dll", FileData::WinSystem, FileData::Critical, FALSE},
120
121
122
123
124
	{"libisc.dll", FileData::WinSystem, FileData::Critical, FALSE},
	{"libisccfg.dll", FileData::WinSystem, FileData::Critical, FALSE},
	{"libisccc.dll", FileData::WinSystem, FileData::Critical, FALSE},
	{"libdns.dll", FileData::WinSystem, FileData::Critical, FALSE},
	{"liblwres.dll", FileData::WinSystem, FileData::Critical, FALSE},
125
	{"libeay32.dll", FileData::BinDir, FileData::Critical, FALSE},
126
127
128
129
130
131
132
	{"named.exe", FileData::BinDir, FileData::Critical, FALSE},
	{"nsupdate.exe", FileData::BinDir, FileData::Normal, FALSE},
	{"BINDInstall.exe", FileData::BinDir, FileData::Normal, FALSE},
	{"rndc.exe", FileData::BinDir, FileData::Normal, FALSE},
	{"dig.exe", FileData::BinDir, FileData::Normal, FALSE},
	{"host.exe", FileData::BinDir, FileData::Normal, FALSE},
	{"nslookup.exe", FileData::BinDir, FileData::Normal, FALSE},
Danny Mayer's avatar
Danny Mayer committed
133
	{"rndc-confgen.exe", FileData::BinDir, FileData::Normal, FALSE},
134
135
136
	{"dnssec-keygen.exe", FileData::BinDir, FileData::Normal, FALSE},
	{"dnssec-makekeyset.exe", FileData::BinDir, FileData::Normal, FALSE},
	{"dnssec-signkey.exe", FileData::BinDir, FileData::Normal, FALSE},
137
	{"dnssec-signzone.exe", FileData::BinDir, FileData::Normal, FALSE},
138
139
	{"named-checkconf.exe", FileData::BinDir, FileData::Normal, FALSE},
	{"named-checkzone.exe", FileData::BinDir, FileData::Normal, FALSE},
140
141
142
143
	{"readme1st.txt", FileData::BinDir, FileData::Trivial, FALSE},
	{NULL, -1, -1}
};

144

145
146
147
148
/////////////////////////////////////////////////////////////////////////////
// CBINDInstallDlg dialog

CBINDInstallDlg::CBINDInstallDlg(CWnd* pParent /*=NULL*/)
149
	: CDialog(CBINDInstallDlg::IDD, pParent) {
150
151
152
153
154
155
156
157
158
	char buf[MAX_PATH];

	//{{AFX_DATA_INIT(CBINDInstallDlg)
	m_targetDir = _T("");
	m_version = _T("");
	m_autoStart = FALSE;
	m_keepFiles = FALSE;
	m_current = _T("");
	m_startOnInstall = FALSE;
159
160
161
	m_accountName = _T("");
	m_accountPassword = _T("");
	m_accountName = _T("");
162
163
164
165
166
167
168
169
	//}}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";
170
171
172
	m_installed = FALSE;
	m_accountExists = FALSE;
	m_accountUsed = FALSE;
173
	m_serviceExists = TRUE;
174
	GetCurrentServiceAccountName();
175
	m_currentAccount = m_accountName;
176
177
178
	if (m_accountName == "") {
		m_accountName = "named";
	}
179
180
}

181
void CBINDInstallDlg::DoDataExchange(CDataExchange* pDX) {
182
183
184
185
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CBINDInstallDlg)
	DDX_Text(pDX, IDC_TARGETDIR, m_targetDir);
	DDX_Text(pDX, IDC_VERSION, m_version);
186
187
188
	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);
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
	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

210
BOOL CBINDInstallDlg::OnInitDialog() {
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
	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;
	
	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 */
242
243
244
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SUBKEY, 0, KEY_READ, &hKey)
			== ERROR_SUCCESS) {
		m_installed = TRUE;
245
246
		memset(buf, 0, MAX_PATH);
		// Get the install directory
247
248
249
		if (RegQueryValueEx(hKey, "InstallDir", NULL, NULL, (LPBYTE)buf,
			&dwBufLen) == ERROR_SUCCESS)
			if (strcmp(buf, ""))
250
251
252
253
254
255
256
257
258
259
260
261
				m_defaultDir = buf;
		
		RegCloseKey(hKey);
	}
	m_targetDir = m_defaultDir;

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

	UpdateData(FALSE);

262
	return (TRUE); /* return(TRUE) unless you set the focus to a control */
263
264
}

265
266
267
268
269
/*
 *  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.
 */
270

271
272
void CBINDInstallDlg::OnPaint() {
	if (IsIconic())	{
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
		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);
	}
288
	else {
289
290
291
292
293
294
		CDialog::OnPaint();
	}
}

// The system calls this to obtain the cursor to display while the user drags
//  the minimized window.
295
HCURSOR CBINDInstallDlg::OnQueryDragIcon() {
296
297
298
	return((HCURSOR)m_hIcon);
}

299
void CBINDInstallDlg::OnBrowse() {
300
301
302

	CDirBrowse browse;

303
	if (browse.DoModal() == IDOK) 	{
304
305
306
307
308
309
310
311
		//m_targetDir = browse.m_selectedDir;
		UpdateData(FALSE);
	}
}

/*
 * User pressed the exit button
 */
312
void CBINDInstallDlg::OnExit() {
313
314
315
316
317
318
	EndDialog(0);	
}

/*
 * User pressed the uninstall button.  Make it go.
 */
319
void CBINDInstallDlg::OnUninstall() {
320
321
	UpdateData();	

322
323
	if (MsgBox(IDS_UNINSTALL, MB_YESNO) == IDYES) {
		if (CheckBINDService())
324
325
			StopBINDService();

326
327
		HANDLE hSCManager = OpenSCManager(NULL, NULL,
					SC_MANAGER_ALL_ACCESS);
328
		if (!hSCManager) {
329
330
331
332
			MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
			return;
		}
		
333
334
		HANDLE hService = OpenService(hSCManager, BIND_SERVICE_NAME,
					      SERVICE_ALL_ACCESS);
335
		if (!hService && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST){
336
337
338
339
340
341
			MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
			return;
		}

		SERVICE_STATUS ss;
		QueryServiceStatus(hService, &ss);
342
343
344
345
		if (ss.dwCurrentState == SERVICE_RUNNING) {
			BOOL rc = ControlService(hService,
					         SERVICE_CONTROL_STOP, &ss);
			if (rc == FALSE || ss.dwCurrentState != SERVICE_STOPPED) {
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
				MsgBox(IDS_ERR_STOP_SERVICE, GetErrMessage());
				return;
			}

		}
		CloseServiceHandle(hService);
		CloseServiceHandle(hSCManager);
		
		// Directories
		m_etcDir = m_targetDir + "\\etc";
		m_binDir = m_targetDir + "\\bin";

		UninstallTags();
		UnregisterMessages(TRUE);
		UnregisterService(TRUE);
		DeleteFiles(TRUE);
362
		if (m_keepFiles == FALSE)
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
			RemoveDirs(TRUE);
		else
			GetDlgItem(IDC_CREATE_DIR)->SetWindowText("Not Removed");

		
		// 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);
	
		ProgramGroup(FALSE);

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

/*
 * User pressed the install button.  Make it go.
 */
383
void CBINDInstallDlg::OnInstall() {
384
385
	BOOL success = FALSE;

386
	if (CheckBINDService())
387
388
389
390
391
392
		StopBINDService();

	InstallTags();

	UpdateData();

393
394
395
396
397
398
399
400
401
402
	/* Check that the Passwords entered match */ 
	if (m_accountPassword != m_accountPasswordConfirm) {
		MsgBox(IDS_ERR_PASSWORD);
		return;
	}

	/* Check the entered account name */
	if (ValidateServiceAccount() == FALSE)
		return;

403
404
405
406
407
408

	/* For Registration we need to know if account was changed */
	if(m_accountName != m_currentAccount)
		m_accountUsed = FALSE;

	/* Directories */
409
410
411
	m_etcDir = m_targetDir + "\\etc";
	m_binDir = m_targetDir + "\\bin";

412
413
	if (m_defaultDir != m_targetDir) {
		if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF)
414
		{
415
416
			int install = MsgBox(IDS_DIREXIST,
					MB_YESNO | MB_ICONQUESTION, m_targetDir);
417
			if (install == IDNO)
418
419
				return;
		}
420
		else {
421
422
			int createDir = MsgBox(IDS_CREATEDIR,
					MB_YESNO | MB_ICONQUESTION, m_targetDir);
423
			if (createDir == IDNO)
424
425
426
427
				return;
		}
	}

428
429
430
431
432
433
434
	if (m_accountExists == FALSE) {
		success = CreateServiceAccount(m_accountName.GetBuffer(30),
						m_accountPassword.GetBuffer(30));
		if (success == FALSE) {
			MsgBox(IDS_CREATEACCOUNT_FAILED);
			return;
		}
435
		m_accountExists = TRUE;
436
437
	}

438
439
	ProgramGroup();

440
	try {
441
442
443
444
445
446
447
448
449
		CreateDirs();
 		CopyFiles();
		RegisterService();
		RegisterMessages();

		HKEY hKey;

		/* Create a new key for named */
		SetCurrent(IDS_CREATE_KEY);
450
451
		if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_SUBKEY,
			&hKey) == ERROR_SUCCESS) {
452
			// Get the install directory
453
454
455
			RegSetValueEx(hKey, "InstallDir", 0, REG_SZ,
					(LPBYTE)(LPCTSTR)m_targetDir,
					m_targetDir.GetLength());
456
457
458
459
460
			RegCloseKey(hKey);
		}

		
		SetCurrent(IDS_ADD_REMOVE);
461
462
		if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_UNINSTALL_SUBKEY,
				&hKey) == ERROR_SUCCESS) {
463
464
465
466
			char winDir[MAX_PATH];
			CString buf(BIND_DISPLAY_NAME);
			GetWindowsDirectory(winDir, MAX_PATH);

467
468
			RegSetValueEx(hKey, "DisplayName", 0, REG_SZ,
					(LPBYTE)(LPCTSTR)buf, buf.GetLength());
469
470

			buf.Format("%s\\BINDInstall.exe", winDir);
471
472
			RegSetValueEx(hKey, "UninstallString", 0, REG_SZ,
					(LPBYTE)(LPCTSTR)buf, buf.GetLength());
473
474
475
476
477
			RegCloseKey(hKey);
		}
	
		ProgramGroup();
		
478
		if (m_startOnInstall)
479
480
			StartBINDService();
	}
481
	catch(Exception e) {
482
483
484
485
486
487
		MessageBox(e.resString);
		SetCurrent(IDS_CLEANUP);
		FailedInstall();
		MsgBox(IDS_FAIL);
		return;
	}
488
	catch(DWORD dw)	{
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
		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
 */
505
void CBINDInstallDlg::CreateDirs() {
506
507
	/* s'OK if the directories already exist */
	SetCurrent(IDS_CREATE_DIR, m_targetDir);
508
	if (!CreateDirectory(m_targetDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
509
510
511
		throw(Exception(IDS_ERR_CREATE_DIR, m_targetDir, GetErrMessage()));

	SetCurrent(IDS_CREATE_DIR, m_etcDir);
512
	if (!CreateDirectory(m_etcDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
513
514
515
		throw(Exception(IDS_ERR_CREATE_DIR, m_etcDir, GetErrMessage()));

	SetCurrent(IDS_CREATE_DIR, m_binDir);
516
	if (!CreateDirectory(m_binDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS)
517
518
519
520
521
		throw(Exception(IDS_ERR_CREATE_DIR, m_binDir, GetErrMessage()));
		
	SetItemStatus(IDC_CREATE_DIR);
}

522
523
void CBINDInstallDlg::RemoveDirs(BOOL uninstall) {
	if (!m_keepFiles) {
524
525
		SetCurrent(IDS_REMOVE_DIR, m_binDir);
		// Check for existence then remove if present
526
		if (GetFileAttributes(m_binDir) != 0xFFFFFFFF)
527
528
529
			RemoveDirectory(m_binDir);

		SetCurrent(IDS_REMOVE_DIR, m_etcDir);
530
		if (GetFileAttributes(m_etcDir) != 0xFFFFFFFF)
531
532
533
			RemoveDirectory(m_etcDir);

		SetCurrent(IDS_REMOVE_DIR, m_targetDir);
534
		if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF)
535
536
537
			RemoveDirectory(m_targetDir);
	}

538
	if (uninstall)
539
540
541
		SetItemStatus(IDC_CREATE_DIR, TRUE);
}

542
void CBINDInstallDlg::CopyFiles() {
543
544
	CString destFile;

545
	for (int i = 0; installFiles[i].filename; i++) {
546
547
		SetCurrent(IDS_COPY_FILE, installFiles[i].filename);

548
549
		destFile = DestDir(installFiles[i].destination) + "\\" +
				   installFiles[i].filename;
550
		CString filespec = m_currentDir + "\\" + installFiles[i].filename;
551
		CVersionInfo bindFile(destFile);
552
553
		
		CVersionInfo origFile(filespec);
554
555
556
557
558
559
		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()));
560
561
		}
		
562
563
564
565
566
567
		try {
/* 
 * 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.
 */
568
569
			bindFile.CopyFileNoVersion(origFile);
		}
570
571
572
573
574
575
576
		catch(...) {
			if (installFiles[i].importance != FileData::Trivial) {
				if (installFiles[i].importance == 
					FileData::Critical ||
					MsgBox(IDS_ERR_NONCRIT_FILE, MB_YESNO,
					installFiles[i].filename,
					GetErrMessage()) == IDNO)
577
578
				{
					SetItemStatus(IDC_COPY_FILE, FALSE);
579
580
581
					throw(Exception(IDS_ERR_COPY_FILE,
						installFiles[i].filename,
						GetErrMessage()));
582
583
584
585
586
587
588
589
				}
			}
		}
	}

	SetItemStatus(IDC_COPY_FILE);
}

590
void CBINDInstallDlg::DeleteFiles(BOOL uninstall) {
591
592
	CString destFile;

593
594
	for (int i = 0; installFiles[i].filename; i++) {
		if (installFiles[i].checkVer)
595
596
			continue;

597
598
		destFile = DestDir(installFiles[i].destination) + "\\" +
				   installFiles[i].filename;
599
	
600
		if (uninstall)
601
602
603
604
605
			SetCurrent(IDS_DELETE_FILE, installFiles[i].filename);
		
		DeleteFile(destFile);
	}

606
	if (!m_keepFiles) {
607
608
609
610
611
612
613
614
		WIN32_FIND_DATA findData;
		CString file = m_etcDir + "\\*.*";
		BOOL rc;
		HANDLE hFile;
			
		hFile = FindFirstFile(file, &findData);
		rc = hFile != INVALID_HANDLE_VALUE;
		
615
616
617
		while (rc == TRUE) {
			if (strcmp(findData.cFileName, ".") &&
			    strcmp(findData.cFileName, "..")) {
618
619
620
621
622
623
624
625
626
				file = m_etcDir + "\\" + findData.cFileName;
				SetCurrent(IDS_DELETE_FILE, file);
				DeleteFile(file);
			}
			rc = FindNextFile(hFile, &findData);
		}
		FindClose(hFile);
	}

627
	if (uninstall)
628
629
630
		SetItemStatus(IDC_COPY_FILE, TRUE);
}	

631
632
633
634
635
636
637
/*
 * Get the service account name out of the registry, if any
 */
void
CBINDInstallDlg::GetCurrentServiceAccountName() {
	HKEY hKey;
	BOOL keyFound = FALSE;
638
639
	char accountName[MAX_PATH];
	DWORD nameLen = MAX_PATH;
640
641
642
643
644
	CString Tmp;
	m_accountUsed = FALSE;

	memset(accountName, 0, nameLen);
	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SERVICE_SUBKEY, 0, KEY_READ,
645
		&hKey) == ERROR_SUCCESS) {
646
		keyFound = TRUE;
647
648
649
650
	}
	else {
		m_serviceExists = FALSE;
	}
651
652
653
654
655
656
657
	
	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;
	}
658

659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
	RegCloseKey(hKey);
	if(keyFound == FALSE)
		m_accountName = "";
	else {
	/*
	 * LocalSystem is not a regular account and is equivalent
	 * to no account but with lots of privileges
	 */
		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;
		}
	}
}
677

678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
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);
	}

710
711
712
713
714
715
	/* 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);
716
717
718
719
}

void
CBINDInstallDlg::RegisterService() {
720
721
	HANDLE hSCManager;
	HANDLE hService;
722
723
724
725
726
727
728
729
730
731
	CString StartName = ".\\" + m_accountName;

	/*
	 * We need to change the service rather than create it
	 * if the service already exists. Do nothing if we are already
	 * using that account
	 */
	if(m_serviceExists == TRUE) {
		if(m_accountUsed == FALSE) {
			UpdateService();
732
			SetItemStatus(IDC_REG_SERVICE);
733
734
735
			return;
		}
		else {
736
			SetItemStatus(IDC_REG_SERVICE);
737
738
739
			return;
		}
	}
740
741
742

	SetCurrent(IDS_OPEN_SCM);
	hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
743
	if (!hSCManager)
744
745
746
		throw(Exception(IDS_ERR_OPEN_SCM, GetErrMessage()));

	DWORD dwStart = SERVICE_DEMAND_START;
747
	if (m_autoStart)
748
749
750
751
752
753
754
755
		dwStart = SERVICE_AUTO_START;

	DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;

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

	SetCurrent(IDS_CREATE_SERVICE);
756
757
	hService = CreateService(hSCManager, BIND_SERVICE_NAME,
		BIND_DISPLAY_NAME, SERVICE_ALL_ACCESS, dwServiceType, dwStart,
758
759
		SERVICE_ERROR_NORMAL, namedLoc, NULL, NULL, NULL, StartName,
		m_accountPassword);	
760
	
761
	if (!hService && GetLastError() != ERROR_SERVICE_EXISTS)
762
763
		throw(Exception(IDS_ERR_CREATE_SERVICE, GetErrMessage()));

764
765
766
	if (hService)
		CloseServiceHandle(hService);

767
	if (hSCManager)
768
769
		CloseServiceHandle(hSCManager);

770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
	SetItemStatus(IDC_REG_SERVICE);
}

void
CBINDInstallDlg::UpdateService() {
	HANDLE hSCManager;
	HANDLE hService;
	CString StartName = ".\\" + m_accountName;

	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;
	}
	else {
		if (ChangeServiceConfig(hService, dwServiceType, dwStart,
			SERVICE_ERROR_NORMAL, namedLoc, NULL, NULL, NULL,
			StartName, m_accountPassword,BIND_DISPLAY_NAME)
			!= TRUE) {
			DWORD err = GetLastError();
			MsgBox(IDS_ERR_UPDATE_SERVICE, GetErrMessage());
		}
	}

815
	if (hService)
816
817
		CloseServiceHandle(hService);

818
819
820
	if (hSCManager)
		CloseServiceHandle(hSCManager);

821
822
823
	SetItemStatus(IDC_REG_SERVICE);
}

824
void CBINDInstallDlg::UnregisterService(BOOL uninstall) {
825
826
827
828
	BOOL rc = FALSE;
	HANDLE hSCManager;
	HANDLE hService;

829
	while(1) {
830
831
		SetCurrent(IDS_OPEN_SCM);
		hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
832
		if (!hSCManager && uninstall == TRUE) {
833
834
835
836
837
			MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
			break;
		}

		SetCurrent(IDS_OPEN_SERVICE);
838
839
840
		hService = OpenService(hSCManager, BIND_SERVICE_NAME,
				       STANDARD_RIGHTS_REQUIRED);
		if (!hService && uninstall == TRUE)
841
		{
842
			if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) {
843
844
845
846
				MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
				break;
			}
		}
847
		else {
848
			SetCurrent(IDS_REMOVE_SERVICE);
849
			if (!DeleteService(hService) && uninstall == TRUE) {
850
				DWORD err = GetLastError();
851
852
				if (err != ERROR_SERVICE_MARKED_FOR_DELETE &&
				   err != ERROR_SERVICE_DOES_NOT_EXIST) {
853
854
855
856
857
858
859
860
861
862
					MsgBox(IDS_ERR_REMOVE_SERVICE, GetErrMessage());
					break;
				}
			}
		}

		rc = TRUE;
		break;
	}

863
	if (hService)
864
865
		CloseServiceHandle(hService);

866
867
868
	if (hSCManager)
		CloseServiceHandle(hSCManager);

869
	if (uninstall)
870
871
872
		SetItemStatus(IDC_REG_SERVICE, rc);
}

873
void CBINDInstallDlg::RegisterMessages() {
874
875
876
877
878
879
880
881
882
	HKEY hKey;
	DWORD dwData;
	char pszMsgDLL[MAX_PATH], buf[MAX_PATH];

	GetSystemDirectory(buf, MAX_PATH);
	sprintf(pszMsgDLL, "%s\\%s", buf, "bindevt.dll");

	SetCurrent(IDS_REGISTER_MESSAGES);
	/* Create a new key for named */
883
884
	if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_MESSAGE_SUBKEY, &hKey)
		!= ERROR_SUCCESS)
885
886
887
		throw(Exception(IDS_ERR_CREATE_KEY, GetErrMessage()));
	
	/* Add the Event-ID message-file name to the subkey. */
888
889
	if (RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ,
		(LPBYTE)pszMsgDLL, strlen(pszMsgDLL) + 1) != ERROR_SUCCESS)
890
891
892
893
		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;
894
895
	if (RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD,
		(LPBYTE)&dwData, sizeof(DWORD)) != ERROR_SUCCESS)
896
897
898
899
900
901
902
		throw(Exception(IDS_ERR_SET_VALUE, GetErrMessage()));

	RegCloseKey(hKey);
			
	SetItemStatus(IDC_REG_MESSAGE);
}

903
void CBINDInstallDlg::UnregisterMessages(BOOL uninstall) {
904
905
906
	BOOL rc = FALSE;
	HKEY hKey = NULL;

907
	while(1) {
908
909
		SetCurrent(IDS_UNREGISTER_MESSAGES);
		/* Open key for Application Event Log */
910
911
		if (RegOpenKey(HKEY_LOCAL_MACHINE, EVENTLOG_APP_SUBKEY, &hKey)
			!= ERROR_SUCCESS)
912
913
914
			break;

		/* Remove named from the list of messages sources */
915
		if (RegDeleteKey(hKey, BIND_MESSAGE_NAME) != ERROR_SUCCESS)
916
917
918
919
920
921
			break;
		
		rc = TRUE;
		break;
	}

922
	if (hKey)
923
924
		RegCloseKey(hKey);

925
	if (uninstall)
926
927
928
929
930
931
		SetItemStatus(IDC_REG_MESSAGE, rc);
}

/*
 * Install failed - clean up quietly
 */
932
void CBINDInstallDlg::FailedInstall() {
933
934
935
936
937
938
939
940
941
	UnregisterMessages(FALSE);
	UnregisterService(FALSE);
	DeleteFiles(FALSE);
	RemoveDirs(FALSE);
}

/*
 * Set the checklist tags for install
 */
942
void CBINDInstallDlg::InstallTags() {
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
	CString tag;
	
	tag.LoadString(IDS_INSTALL_FILE);
	GetDlgItem(IDC_COPY_TAG)->SetWindowText(tag);
	GetDlgItem(IDC_COPY_FILE)->SetWindowText("");

	tag.LoadString(IDS_INSTALL_DIR);
	GetDlgItem(IDC_DIR_TAG)->SetWindowText(tag);
	GetDlgItem(IDC_CREATE_DIR)->SetWindowText("");
	GetDlgItem(IDC_REG_SERVICE)->SetWindowText("");

	tag.LoadString(IDS_INSTALL_SERVICE);
	GetDlgItem(IDC_SERVICE_TAG)->SetWindowText(tag);
	
	tag.LoadString(IDS_INSTALL_MESSAGE);
	GetDlgItem(IDC_MESSAGE_TAG)->SetWindowText(tag);
	GetDlgItem(IDC_REG_MESSAGE)->SetWindowText("");
}

/*
 * Set the checklist tags for uninstall
 */
965
void CBINDInstallDlg::UninstallTags() {
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
	CString tag;
	
	tag.LoadString(IDS_UNINSTALL_FILES);
	GetDlgItem(IDC_COPY_TAG)->SetWindowText(tag);
	GetDlgItem(IDC_COPY_FILE)->SetWindowText("");

	tag.LoadString(IDS_UNINSTALL_DIR);
	GetDlgItem(IDC_DIR_TAG)->SetWindowText(tag);
	GetDlgItem(IDC_CREATE_DIR)->SetWindowText("");

	tag.LoadString(IDS_UNINSTALL_SERVICE);
	GetDlgItem(IDC_SERVICE_TAG)->SetWindowText(tag);
	GetDlgItem(IDC_REG_SERVICE)->SetWindowText("");
	
	tag.LoadString(IDS_UNINSTALL_MESSAGE);
	GetDlgItem(IDC_MESSAGE_TAG)->SetWindowText(tag);
	GetDlgItem(IDC_REG_MESSAGE)->SetWindowText("");
}

985
void CBINDInstallDlg::SetItemStatus(UINT nID, BOOL bSuccess) {
986
987
988
989
990
991
992
	GetDlgItem(nID)->SetWindowText(bSuccess == TRUE ? "Done" : "Failed");
}


/*
 * Set the text in the current operation field - use a string table string
 */
993
void CBINDInstallDlg::SetCurrent(int id, ...) {
994
995
996
997
998
999
1000
	CString format;
	va_list va;
	char buf[128];

	format.LoadString(id);
	memset(buf, 0, 128);