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