2 * Portions Copyright (C) 2004-2010 Internet Systems Consortium, Inc. ("ISC")
3 * Portions Copyright (C) 2001, 2003 Internet Software Consortium.
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.
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.
18 /* $Id: BINDInstallDlg.cpp,v 1.46.4.2 2010/01/07 23:48:15 tbox Exp $ */
21 * Copyright (c) 1999-2000 by Nortel Networks Corporation
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.
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
38 * Define this to make a standalone installer that will copy msvcrt.dll
39 * and/or msvcrtd.dll during the install
41 // #define BINARIES_INSTALL
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!
50 #ifdef BINARIES_INSTALL
51 // # define DEBUG_BINARIES
52 // # define RELEASE_BINARIES
56 #include "BINDInstall.h"
57 #include "BINDInstallDlg.h"
58 #include "DirBrowse.h"
60 #include <named/ntservice.h>
61 #include <isc/bind_registry.h>
62 #include <isc/ntgroups.h>
64 #include "AccountInfo.h"
65 #include "versioninfo.h"
69 #define MAX_GROUPS 100
72 #define LOCAL_SERVICE "NT AUTHORITY\\LocalService"
77 static char THIS_FILE[] = __FILE__;
80 typedef struct _xexception
82 _xexception(UINT string, ...);
87 _xexception::_xexception(UINT string, ...)
92 format.LoadString(string);
95 resString.FormatV(format, va);
99 typedef struct _filedata {
100 enum FileDestinations {TargetDir, BinDir, EtcDir, WinSystem};
101 enum FileImportance {Trivial, Normal, Critical};
110 const FileData installFiles[] =
112 #ifdef BINARIES_INSTALL
113 # ifdef DEBUG_BINARIES
114 {"msvcrtd.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
116 # ifdef RELEASE_BINARIES
117 {"msvcrt.dll", FileData::WinSystem, FileData::Critical, TRUE, TRUE},
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},
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},
138 {"libxml2.dll", FileData::BinDir, FileData::Critical, FALSE, TRUE},
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},
169 /////////////////////////////////////////////////////////////////////////////
170 // CBINDInstallDlg dialog
172 CBINDInstallDlg::CBINDInstallDlg(CWnd* pParent /*=NULL*/)
173 : CDialog(CBINDInstallDlg::IDD, pParent) {
176 //{{AFX_DATA_INIT(CBINDInstallDlg)
177 m_targetDir = _T("");
183 m_startOnInstall = FALSE;
184 m_accountName = _T("");
185 m_accountPassword = _T("");
186 m_accountName = _T("");
188 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
189 m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
191 GetSystemDirectory(buf, MAX_PATH);
194 m_defaultDir += "\\dns";
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";
206 void 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);
222 BEGIN_MESSAGE_MAP(CBINDInstallDlg, CDialog)
223 //{{AFX_MSG_MAP(CBINDInstallDlg)
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)
233 /////////////////////////////////////////////////////////////////////////////
234 // CBINDInstallDlg message handlers
236 BOOL CBINDInstallDlg::OnInitDialog() {
237 CDialog::OnInitDialog();
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
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;
255 CVersionInfo bindInst(filename);
256 if(bindInst.IsValid())
257 m_version.Format(IDS_VERSION, bindInst.GetFileVersionString());
259 m_version.LoadString(IDS_NO_VERSION);
261 DWORD dwBufLen = MAX_PATH;
265 m_startOnInstall = CheckBINDService();
267 /* See if we are installed already */
268 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SUBKEY, 0, KEY_READ, &hKey)
271 memset(buf, 0, MAX_PATH);
272 // Get the install directory
273 if (RegQueryValueEx(hKey, "InstallDir", NULL, NULL, (LPBYTE)buf,
274 &dwBufLen) == ERROR_SUCCESS)
280 m_targetDir = m_defaultDir;
282 // Set checkbox defaults
288 return (TRUE); /* return(TRUE) unless you set the focus to a control */
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.
297 void CBINDInstallDlg::OnPaint() {
299 CPaintDC dc(this); // device context for painting
301 SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
303 // Center icon in client rectangle
304 int cxIcon = GetSystemMetrics(SM_CXICON);
305 int cyIcon = GetSystemMetrics(SM_CYICON);
307 GetClientRect(&rect);
308 int x = (rect.Width() - cxIcon + 1) / 2;
309 int y = (rect.Height() - cyIcon + 1) / 2;
312 dc.DrawIcon(x, y, m_hIcon);
319 // The system calls this to obtain the cursor to display while the user drags
320 // the minimized window.
321 HCURSOR CBINDInstallDlg::OnQueryDragIcon() {
322 return((HCURSOR)m_hIcon);
325 void CBINDInstallDlg::OnBrowse() {
329 if (browse.DoModal() == IDOK) {
330 //m_targetDir = browse.m_selectedDir;
336 * User pressed the exit button
338 void CBINDInstallDlg::OnExit() {
343 * User pressed the uninstall button. Make it go.
345 void CBINDInstallDlg::OnUninstall() {
348 if (MsgBox(IDS_UNINSTALL, MB_YESNO) == IDYES) {
349 if (CheckBINDService())
352 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL,
353 SC_MANAGER_ALL_ACCESS);
355 MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
359 SC_HANDLE hService = OpenService(hSCManager, BIND_SERVICE_NAME,
361 if (!hService && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST){
362 MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
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());
377 CloseServiceHandle(hService);
378 CloseServiceHandle(hSCManager);
381 m_etcDir = m_targetDir + "\\etc";
382 m_binDir = m_targetDir + "\\bin";
385 UnregisterMessages(TRUE);
386 UnregisterService(TRUE);
388 if (m_keepFiles == FALSE)
391 GetDlgItem(IDC_CREATE_DIR)->SetWindowText("Not Removed");
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);
401 SetCurrent(IDS_UNINSTALL_DONE);
402 MsgBox(IDS_UNINSTALL_DONE);
407 * User pressed the install button. Make it go.
409 void CBINDInstallDlg::OnInstall() {
411 char Vcredist_x86[MAX_PATH];
413 BOOL success = FALSE;
416 if (CheckBINDService())
423 if (!m_toolsOnly && m_accountName != LOCAL_SERVICE) {
425 * Check that the Passwords entered match.
427 if (m_accountPassword != m_accountPasswordConfirm) {
428 MsgBox(IDS_ERR_PASSWORD);
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.
437 oldlen = m_accountPassword.GetLength();
438 m_accountPassword.TrimLeft();
439 m_accountPassword.TrimRight();
440 if (m_accountPassword.GetLength() != oldlen) {
441 MsgBox(IDS_ERR_WHITESPACE);
446 * Check the entered account name.
448 if (ValidateServiceAccount() == FALSE)
452 * For Registration we need to know if account was changed.
454 if (m_accountName != m_currentAccount)
455 m_accountUsed = FALSE;
457 if (m_accountUsed == FALSE && m_serviceExists == FALSE)
460 * Check that the Password is not null.
462 if (m_accountPassword.GetLength() == 0) {
463 MsgBox(IDS_ERR_NULLPASSWORD);
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;
475 m_etcDir = m_targetDir + "\\etc";
476 m_binDir = m_targetDir + "\\bin";
478 if (m_defaultDir != m_targetDir) {
479 if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF)
481 int install = MsgBox(IDS_DIREXIST,
482 MB_YESNO | MB_ICONQUESTION, m_targetDir);
487 int createDir = MsgBox(IDS_CREATEDIR,
488 MB_YESNO | MB_ICONQUESTION, m_targetDir);
489 if (createDir == IDNO)
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);
502 m_accountExists = TRUE;
510 * Install Visual Studio libraries. As per:
511 * http://blogs.msdn.com/astebner/archive/2006/08/23/715755.aspx
513 * Vcredist_x86.exe /q:a /c:"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log"
515 /*system(".\\Vcredist_x86.exe /q:a /c:\"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log\"");*/
518 * Enclose full path to Vcredist_x86.exe in quotes as
519 * m_currentDir may contain spaces.
521 sprintf(Vcredist_x86, "\"%s\\Vcredist_x86.exe\"",
522 (LPCTSTR) m_currentDir);
523 system(Vcredist_x86);
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());
546 SetCurrent(IDS_ADD_REMOVE);
547 if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_UNINSTALL_SUBKEY,
548 &hKey) == ERROR_SUCCESS) {
549 CString buf(BIND_DISPLAY_NAME);
551 RegSetValueEx(hKey, "DisplayName", 0, REG_SZ,
552 (LPBYTE)(LPCTSTR)buf, buf.GetLength());
554 buf.Format("%s\\BINDInstall.exe", m_binDir);
555 RegSetValueEx(hKey, "UninstallString", 0, REG_SZ,
556 (LPBYTE)(LPCTSTR)buf, buf.GetLength());
562 if (m_startOnInstall)
566 MessageBox(e.resString);
567 SetCurrent(IDS_CLEANUP);
574 msg.Format("A fatal error occured\n(%s)", GetErrMessage(dw));
576 SetCurrent(IDS_CLEANUP);
582 SetCurrent(IDS_INSTALL_DONE);
587 * Methods to do the work
589 void 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()));
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()));
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()));
603 SetItemStatus(IDC_CREATE_DIR);
606 void CBINDInstallDlg::RemoveDirs(BOOL uninstall) {
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);
613 SetCurrent(IDS_REMOVE_DIR, m_etcDir);
614 if (GetFileAttributes(m_etcDir) != 0xFFFFFFFF)
615 RemoveDirectory(m_etcDir);
617 SetCurrent(IDS_REMOVE_DIR, m_targetDir);
618 if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF)
619 RemoveDirectory(m_targetDir);
623 SetItemStatus(IDC_CREATE_DIR, TRUE);
626 void CBINDInstallDlg::CopyFiles() {
629 for (int i = 0; installFiles[i].filename; i++) {
630 if (m_toolsOnly && !installFiles[i].withTools)
632 SetCurrent(IDS_COPY_FILE, installFiles[i].filename);
634 destFile = DestDir(installFiles[i].destination) + "\\" +
635 installFiles[i].filename;
636 CString filespec = m_currentDir + "\\" + installFiles[i].filename;
637 CVersionInfo bindFile(destFile);
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,
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.
654 bindFile.CopyFileNoVersion(origFile);
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)
664 SetItemStatus(IDC_COPY_FILE, FALSE);
665 throw(Exception(IDS_ERR_COPY_FILE,
666 installFiles[i].filename,
673 SetItemStatus(IDC_COPY_FILE);
676 void CBINDInstallDlg::DeleteFiles(BOOL uninstall) {
679 for (int i = 0; installFiles[i].filename; i++) {
680 if (installFiles[i].checkVer)
683 destFile = DestDir(installFiles[i].destination) + "\\" +
684 installFiles[i].filename;
687 SetCurrent(IDS_DELETE_FILE, installFiles[i].filename);
689 DeleteFile(destFile);
693 WIN32_FIND_DATA findData;
694 CString file = m_etcDir + "\\*.*";
698 hFile = FindFirstFile(file, &findData);
699 rc = hFile != INVALID_HANDLE_VALUE;
702 if (strcmp(findData.cFileName, ".") &&
703 strcmp(findData.cFileName, "..")) {
704 file = m_etcDir + "\\" + findData.cFileName;
705 SetCurrent(IDS_DELETE_FILE, file);
708 rc = FindNextFile(hFile, &findData);
714 SetItemStatus(IDC_COPY_FILE, TRUE);
718 * Get the service account name out of the registry, if any
721 CBINDInstallDlg::GetCurrentServiceAccountName() {
723 BOOL keyFound = FALSE;
724 char accountName[MAX_PATH];
725 DWORD nameLen = MAX_PATH;
727 m_accountUsed = FALSE;
729 memset(accountName, 0, nameLen);
730 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SERVICE_SUBKEY, 0, KEY_READ,
731 &hKey) == ERROR_SUCCESS) {
735 m_serviceExists = FALSE;
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)
746 if (keyFound == FALSE)
748 else if (!strcmp(accountName, LOCAL_SERVICE)) {
749 m_accountName = LOCAL_SERVICE;
750 m_accountUsed = TRUE;
753 * LocalSystem is not a regular account and is equivalent
754 * to no account but with lots of privileges
757 if (Tmp == ".\\LocalSystem")
759 /* Found account strip any ".\" from it */
760 if (Tmp.Left(2) == ".\\") {
761 m_accountName = Tmp.Mid(2);
762 m_accountUsed = TRUE;
768 CBINDInstallDlg::ValidateServiceAccount() {
769 wchar_t *PrivList[MAX_PRIVS];
770 unsigned int PrivCount = 0;
771 char *Groups[MAX_GROUPS];
772 unsigned int totalGroups = 0;
776 name = m_accountName.GetBuffer(30);
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;
786 if (status != RTN_OK) {
787 MsgBox(IDS_ERR_BADACCOUNT);
791 m_accountExists = TRUE;
793 if (MsgBox(IDS_ERR_TOOPRIVED, MB_YESNO) == IDYES)
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]);
808 CBINDInstallDlg::RegisterService() {
809 SC_HANDLE hSCManager;
813 if (m_accountName == LOCAL_SERVICE)
814 StartName = LOCAL_SERVICE;
816 StartName = ".\\" + m_accountName;
818 * We need to change the service rather than create it
819 * if the service already exists. Do nothing if we are already
822 if (m_serviceExists == TRUE) {
823 if (m_accountUsed == FALSE) {
824 UpdateService(StartName);
825 SetItemStatus(IDC_REG_SERVICE);
828 SetItemStatus(IDC_REG_SERVICE);
833 SetCurrent(IDS_OPEN_SCM);
834 hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
836 throw(Exception(IDS_ERR_OPEN_SCM, GetErrMessage()));
838 DWORD dwStart = SERVICE_DEMAND_START;
840 dwStart = SERVICE_AUTO_START;
842 DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;
845 namedLoc.Format("%s\\bin\\named.exe", m_targetDir);
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,
853 if (!hService && GetLastError() != ERROR_SERVICE_EXISTS)
854 throw(Exception(IDS_ERR_CREATE_SERVICE, GetErrMessage()));
857 CloseServiceHandle(hService);
860 CloseServiceHandle(hSCManager);
862 SetItemStatus(IDC_REG_SERVICE);
866 CBINDInstallDlg::UpdateService(CString StartName) {
867 SC_HANDLE hSCManager;
873 SetCurrent(IDS_OPEN_SCM);
874 hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
876 MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
880 DWORD dwStart = SERVICE_DEMAND_START;
882 dwStart = SERVICE_AUTO_START;
884 DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;
887 namedLoc.Format("%s\\bin\\named.exe", m_targetDir);
889 SetCurrent(IDS_OPEN_SERVICE);
890 hService = OpenService(hSCManager, BIND_SERVICE_NAME,
891 SERVICE_CHANGE_CONFIG);
894 MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
896 CloseServiceHandle(hSCManager);
899 if (ChangeServiceConfig(hService, dwServiceType, dwStart,
900 SERVICE_ERROR_NORMAL, namedLoc, NULL, NULL, NULL,
901 StartName, m_accountPassword, BIND_DISPLAY_NAME)
903 DWORD err = GetLastError();
904 MsgBox(IDS_ERR_UPDATE_SERVICE, GetErrMessage());
909 CloseServiceHandle(hService);
912 CloseServiceHandle(hSCManager);
914 SetItemStatus(IDC_REG_SERVICE);
917 void CBINDInstallDlg::UnregisterService(BOOL uninstall) {
919 SC_HANDLE hSCManager;
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());
930 SetCurrent(IDS_OPEN_SERVICE);
931 hService = OpenService(hSCManager, BIND_SERVICE_NAME,
932 STANDARD_RIGHTS_REQUIRED);
933 if (!hService && uninstall == TRUE)
935 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) {
936 MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
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());
957 CloseServiceHandle(hService);
960 CloseServiceHandle(hSCManager);
963 SetItemStatus(IDC_REG_SERVICE, rc);
966 void CBINDInstallDlg::RegisterMessages() {
969 char pszMsgDLL[MAX_PATH];
971 sprintf(pszMsgDLL, "%s\\%s", (LPCTSTR)m_binDir, "bindevt.dll");
973 SetCurrent(IDS_REGISTER_MESSAGES);
974 /* Create a new key for named */
975 if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_MESSAGE_SUBKEY, &hKey)
977 throw(Exception(IDS_ERR_CREATE_KEY, GetErrMessage()));
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()));
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()));
992 SetItemStatus(IDC_REG_MESSAGE);
995 void CBINDInstallDlg::UnregisterMessages(BOOL uninstall) {
1000 SetCurrent(IDS_UNREGISTER_MESSAGES);
1001 /* Open key for Application Event Log */
1002 if (RegOpenKey(HKEY_LOCAL_MACHINE, EVENTLOG_APP_SUBKEY, &hKey)
1006 /* Remove named from the list of messages sources */
1007 if (RegDeleteKey(hKey, BIND_MESSAGE_NAME) != ERROR_SUCCESS)
1018 SetItemStatus(IDC_REG_MESSAGE, rc);
1022 * Install failed - clean up quietly
1024 void CBINDInstallDlg::FailedInstall() {
1025 UnregisterMessages(FALSE);
1026 UnregisterService(FALSE);
1032 * Set the checklist tags for install
1034 void CBINDInstallDlg::InstallTags() {
1037 tag.LoadString(IDS_INSTALL_FILE);
1038 GetDlgItem(IDC_COPY_TAG)->SetWindowText(tag);
1039 GetDlgItem(IDC_COPY_FILE)->SetWindowText("");
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("");
1046 tag.LoadString(IDS_INSTALL_SERVICE);
1047 GetDlgItem(IDC_SERVICE_TAG)->SetWindowText(tag);
1049 tag.LoadString(IDS_INSTALL_MESSAGE);
1050 GetDlgItem(IDC_MESSAGE_TAG)->SetWindowText(tag);
1051 GetDlgItem(IDC_REG_MESSAGE)->SetWindowText("");
1055 * Set the checklist tags for uninstall
1057 void CBINDInstallDlg::UninstallTags() {
1060 tag.LoadString(IDS_UNINSTALL_FILES);
1061 GetDlgItem(IDC_COPY_TAG)->SetWindowText(tag);
1062 GetDlgItem(IDC_COPY_FILE)->SetWindowText("");
1064 tag.LoadString(IDS_UNINSTALL_DIR);
1065 GetDlgItem(IDC_DIR_TAG)->SetWindowText(tag);
1066 GetDlgItem(IDC_CREATE_DIR)->SetWindowText("");
1068 tag.LoadString(IDS_UNINSTALL_SERVICE);
1069 GetDlgItem(IDC_SERVICE_TAG)->SetWindowText(tag);
1070 GetDlgItem(IDC_REG_SERVICE)->SetWindowText("");
1072 tag.LoadString(IDS_UNINSTALL_MESSAGE);
1073 GetDlgItem(IDC_MESSAGE_TAG)->SetWindowText(tag);
1074 GetDlgItem(IDC_REG_MESSAGE)->SetWindowText("");
1077 void CBINDInstallDlg::SetItemStatus(UINT nID, BOOL bSuccess) {
1078 GetDlgItem(nID)->SetWindowText(bSuccess == TRUE ? "Done" : "Failed");
1083 * Set the text in the current operation field - use a string table string
1085 void CBINDInstallDlg::SetCurrent(int id, ...) {
1090 format.LoadString(id);
1091 memset(buf, 0, 128);
1094 vsprintf(buf, format, va);
1097 m_current.Format("%s", buf);
1102 * Stop the BIND service
1104 void CBINDInstallDlg::StopBINDService() {
1105 SERVICE_STATUS svcStatus;
1107 SetCurrent(IDS_STOP_SERVICE);
1109 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1111 MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
1114 SC_HANDLE hBINDSvc = OpenService(hSCManager, BIND_SERVICE_NAME,
1115 SERVICE_ALL_ACCESS);
1117 MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
1120 BOOL rc = ControlService(hBINDSvc, SERVICE_CONTROL_STOP, &svcStatus);
1124 * Start the BIND service
1126 void CBINDInstallDlg::StartBINDService() {
1127 SetCurrent(IDS_START_SERVICE);
1129 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1131 MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage());
1134 SC_HANDLE hBINDSvc = OpenService(hSCManager, BIND_SERVICE_NAME,
1135 SERVICE_ALL_ACCESS);
1137 MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage());
1139 BOOL rc = StartService(hBINDSvc, 0, NULL);
1143 * Check to see if the BIND service is running or not
1145 BOOL CBINDInstallDlg::CheckBINDService() {
1146 SERVICE_STATUS svcStatus;
1148 SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
1150 SC_HANDLE hBINDSvc = OpenService(hSCManager, BIND_SERVICE_NAME,
1151 SERVICE_ALL_ACCESS);
1153 BOOL rc = ControlService(hBINDSvc,
1154 SERVICE_CONTROL_INTERROGATE, &svcStatus);
1156 DWORD err = GetLastError();
1158 return (svcStatus.dwCurrentState == SERVICE_RUNNING);
1165 * Display message boxes with variable args, using string table strings
1166 * for the format specifiers
1168 int CBINDInstallDlg::MsgBox(int id, ...) {
1173 format.LoadString(id);
1174 memset(buf, 0, BUFSIZ);
1177 vsprintf(buf, format, va);
1180 return (MessageBox(buf));
1183 int CBINDInstallDlg::MsgBox(int id, UINT type, ...) {
1188 format.LoadString(id);
1189 memset(buf, 0, BUFSIZ);
1192 vsprintf(buf, format, va);
1195 return(MessageBox(buf, NULL, type));
1199 * Call GetLastError(), retrieve the message associated with the error
1201 CString CBINDInstallDlg::GetErrMessage(DWORD err) {
1203 static char buf[BUFSIZ];
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 );
1209 strcpy(buf, (LPTSTR)msgBuf);
1211 /* Strip off the period and the \n */
1216 void CBINDInstallDlg::ProgramGroup(BOOL create) {
1217 TCHAR path[MAX_PATH], commonPath[MAX_PATH], fileloc[MAX_PATH], linkpath[MAX_PATH];
1219 IShellLink *psl = NULL;
1220 LPMALLOC pMalloc = NULL;
1221 ITEMIDLIST *itemList = NULL;
1223 HRESULT hr = SHGetMalloc(&pMalloc);
1224 if (hr != NOERROR) {
1225 MessageBox("Could not get a handle to Shell memory object");
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");
1233 pMalloc->Free(itemList);
1238 hr = SHGetPathFromIDList(itemList, commonPath);
1239 pMalloc->Free(itemList);
1242 sprintf(path, "%s\\ISC", commonPath);
1243 CreateDirectory(path, NULL);
1245 sprintf(path, "%s\\ISC\\BIND", commonPath);
1246 CreateDirectory(path, NULL);
1248 hres = CoInitialize(NULL);
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))
1256 sprintf(linkpath, "%s\\BINDCtrl.lnk", path);
1257 sprintf(fileloc, "%s\\BINDCtrl.exe", m_binDir);
1259 psl->SetPath(fileloc);
1260 psl->SetDescription("BIND Control Panel");
1262 hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
1263 if (SUCCEEDED(hres)) {
1264 WCHAR wsz[MAX_PATH];
1266 MultiByteToWideChar(CP_ACP, 0, linkpath, -1, wsz, MAX_PATH);
1267 hres = ppf->Save(wsz, TRUE);
1271 if (GetFileAttributes("readme.txt") != -1) {
1272 sprintf(fileloc, "%s\\Readme.txt", m_targetDir);
1273 sprintf(linkpath, "%s\\Readme.lnk", path);
1275 psl->SetPath(fileloc);
1276 psl->SetDescription("BIND Readme");
1278 hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf);
1279 if (SUCCEEDED(hres)) {
1280 WCHAR wsz[MAX_PATH];
1282 MultiByteToWideChar(CP_ACP, 0, linkpath, -1, wsz, MAX_PATH);
1283 hres = ppf->Save(wsz, TRUE);
1293 TCHAR filename[MAX_PATH];
1296 sprintf(path, "%s\\ISC\\BIND", commonPath);
1298 sprintf(filename, "%s\\*.*", path);
1299 HANDLE hFind = FindFirstFile(filename, &fd);
1300 if (hFind != INVALID_HANDLE_VALUE) {
1302 if (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..")) {
1303 sprintf(filename, "%s\\%s", path, fd.cFileName);
1304 DeleteFile(filename);
1306 } while (FindNextFile(hFind, &fd));
1309 RemoveDirectory(path);
1310 sprintf(path, "%s\\ISC", commonPath);
1311 RemoveDirectory(path);
1315 CString CBINDInstallDlg::DestDir(int destination) {
1316 switch(destination) {
1317 case FileData::TargetDir:
1319 case FileData::BinDir:
1321 case FileData::EtcDir:
1323 case FileData::WinSystem: