diff options
author | Martin Nagy <mnagy@redhat.com> | 2009-02-11 20:37:59 +0100 |
---|---|---|
committer | Martin Nagy <mnagy@redhat.com> | 2009-02-11 20:37:59 +0100 |
commit | f50ae72ec3417cae55dd4e085991c01af9fdc5f1 (patch) | |
tree | 0e36c9a3320f6d068df93d3ff6d84b821d23db40 /bin/win32/BINDInstall/BINDInstallDlg.cpp | |
download | bind_dynamic-f50ae72ec3417cae55dd4e085991c01af9fdc5f1.tar.gz bind_dynamic-f50ae72ec3417cae55dd4e085991c01af9fdc5f1.tar.xz bind_dynamic-f50ae72ec3417cae55dd4e085991c01af9fdc5f1.zip |
Initial commitstart
Diffstat (limited to 'bin/win32/BINDInstall/BINDInstallDlg.cpp')
-rw-r--r-- | bin/win32/BINDInstall/BINDInstallDlg.cpp | 1290 |
1 files changed, 1290 insertions, 0 deletions
diff --git a/bin/win32/BINDInstall/BINDInstallDlg.cpp b/bin/win32/BINDInstall/BINDInstallDlg.cpp new file mode 100644 index 0000000..1d493f7 --- /dev/null +++ b/bin/win32/BINDInstall/BINDInstallDlg.cpp @@ -0,0 +1,1290 @@ +/* + * Portions Copyright (C) 2004-2008 Internet Systems Consortium, Inc. ("ISC") + * Portions Copyright (C) 2001, 2003 Internet Software Consortium. + * + * Permission to use, copy, modify, and/or 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 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. + */ + +/* $Id: BINDInstallDlg.cpp,v 1.37.228.2 2008/12/14 21:33:07 tbox Exp $ */ + +/* + * 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> +#include <isc/ntgroups.h> +#include <direct.h> +#include "AccountInfo.h" +#include "versioninfo.h" + +#define MAX_GROUPS 100 +#define MAX_PRIVS 50 + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +typedef struct _xexception +{ + _xexception(UINT string, ...); + + CString resString; +} Exception; + +_xexception::_xexception(UINT string, ...) +{ + CString format; + va_list va; + + format.LoadString(string); + + va_start(va, string); + resString.FormatV(format, va); + va_end(va); +} + +typedef struct _filedata { + 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 +#if _MSC_VER < 1400 +#if _MSC_VER >= 1310 + {"mfc71.dll", FileData::WinSystem, FileData::Critical, TRUE}, + {"msvcr71.dll", FileData::WinSystem, FileData::Critical, TRUE}, +#elif _MSC_VER > 1200 && _MSC_VER < 1310 + {"mfc70.dll", FileData::WinSystem, FileData::Critical, TRUE}, + {"msvcr70.dll", FileData::WinSystem, FileData::Critical, TRUE}, +#endif +#endif + {"bindevt.dll", FileData::BinDir, FileData::Normal, FALSE}, + {"libbind9.dll", FileData::BinDir, FileData::Critical, FALSE}, + {"libisc.dll", FileData::BinDir, FileData::Critical, FALSE}, + {"libisccfg.dll", FileData::BinDir, FileData::Critical, FALSE}, + {"libisccc.dll", FileData::BinDir, FileData::Critical, FALSE}, + {"libdns.dll", FileData::BinDir, FileData::Critical, FALSE}, + {"liblwres.dll", FileData::BinDir, FileData::Critical, FALSE}, + {"libeay32.dll", FileData::BinDir, FileData::Critical, FALSE}, + {"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}, + {"rndc-confgen.exe", FileData::BinDir, FileData::Normal, FALSE}, + {"dnssec-keygen.exe", FileData::BinDir, FileData::Normal, FALSE}, + {"dnssec-signzone.exe", FileData::BinDir, FileData::Normal, FALSE}, + {"dnssec-dsfromkey.exe", FileData::BinDir, FileData::Normal, FALSE}, + {"dnssec-keyfromlabel.exe", FileData::BinDir, FileData::Normal, FALSE}, + {"named-checkconf.exe", FileData::BinDir, FileData::Normal, FALSE}, + {"named-checkzone.exe", FileData::BinDir, FileData::Normal, FALSE}, + {"named-compilezone.exe", FileData::BinDir, FileData::Normal, FALSE}, + {"readme1st.txt", FileData::BinDir, FileData::Trivial, FALSE}, + {NULL, -1, -1} +}; + + +///////////////////////////////////////////////////////////////////////////// +// CBINDInstallDlg dialog + +CBINDInstallDlg::CBINDInstallDlg(CWnd* pParent /*=NULL*/) + : CDialog(CBINDInstallDlg::IDD, pParent) { + 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; + m_accountName = _T(""); + m_accountPassword = _T(""); + m_accountName = _T(""); + //}}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"; + m_installed = FALSE; + m_accountExists = FALSE; + m_accountUsed = FALSE; + m_serviceExists = TRUE; + GetCurrentServiceAccountName(); + m_currentAccount = m_accountName; + if (m_accountName == "") { + m_accountName = "named"; + } +} + +void CBINDInstallDlg::DoDataExchange(CDataExchange* pDX) { + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CBINDInstallDlg) + DDX_Text(pDX, IDC_TARGETDIR, m_targetDir); + DDX_Text(pDX, IDC_VERSION, m_version); + 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); + 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 + +BOOL CBINDInstallDlg::OnInitDialog() { + 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 */ + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SUBKEY, 0, KEY_READ, &hKey) + == ERROR_SUCCESS) { + m_installed = TRUE; + memset(buf, 0, MAX_PATH); + // Get the install directory + if (RegQueryValueEx(hKey, "InstallDir", NULL, NULL, (LPBYTE)buf, + &dwBufLen) == ERROR_SUCCESS) + if (strcmp(buf, "")) + m_defaultDir = buf; + + RegCloseKey(hKey); + } + m_targetDir = m_defaultDir; + + // Set checkbox defaults + m_autoStart = TRUE; + m_keepFiles = TRUE; + + UpdateData(FALSE); + + return (TRUE); /* return(TRUE) unless you set the focus to a control */ +} + +/* + * 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. + */ + +void CBINDInstallDlg::OnPaint() { + if (IsIconic()) { + 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); + } + else { + CDialog::OnPaint(); + } +} + +// The system calls this to obtain the cursor to display while the user drags +// the minimized window. +HCURSOR CBINDInstallDlg::OnQueryDragIcon() { + return((HCURSOR)m_hIcon); +} + +void CBINDInstallDlg::OnBrowse() { + + CDirBrowse browse; + + if (browse.DoModal() == IDOK) { + //m_targetDir = browse.m_selectedDir; + UpdateData(FALSE); + } +} + +/* + * User pressed the exit button + */ +void CBINDInstallDlg::OnExit() { + EndDialog(0); +} + +/* + * User pressed the uninstall button. Make it go. + */ +void CBINDInstallDlg::OnUninstall() { + UpdateData(); + + if (MsgBox(IDS_UNINSTALL, MB_YESNO) == IDYES) { + if (CheckBINDService()) + StopBINDService(); + + SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, + SC_MANAGER_ALL_ACCESS); + if (!hSCManager) { + MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage()); + return; + } + + SC_HANDLE hService = OpenService(hSCManager, BIND_SERVICE_NAME, + SERVICE_ALL_ACCESS); + if (!hService && GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST){ + MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage()); + return; + } + + SERVICE_STATUS ss; + QueryServiceStatus(hService, &ss); + if (ss.dwCurrentState == SERVICE_RUNNING) { + BOOL rc = ControlService(hService, + SERVICE_CONTROL_STOP, &ss); + if (rc == FALSE || ss.dwCurrentState != SERVICE_STOPPED) { + 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); + if (m_keepFiles == FALSE) + 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. + */ +void CBINDInstallDlg::OnInstall() { +#if _MSC_VER >= 1400 + char Vcredist_x86[MAX_PATH]; +#endif + BOOL success = FALSE; + int oldlen; + + if (CheckBINDService()) + StopBINDService(); + + InstallTags(); + + UpdateData(); + + /* + * Check that the Passwords entered match. + */ + if (m_accountPassword != m_accountPasswordConfirm) { + MsgBox(IDS_ERR_PASSWORD); + return; + } + + /* + * Check that there is not leading / trailing whitespace. + * This is for compatability with the standard password dialog. + * Passwords really should be treated as opaque blobs. + */ + oldlen = m_accountPassword.GetLength(); + m_accountPassword.TrimLeft(); + m_accountPassword.TrimRight(); + if (m_accountPassword.GetLength() != oldlen) { + MsgBox(IDS_ERR_WHITESPACE); + return; + } + + /* + * Check the entered account name. + */ + if (ValidateServiceAccount() == FALSE) + return; + + /* + * For Registration we need to know if account was changed. + */ + if (m_accountName != m_currentAccount) + m_accountUsed = FALSE; + + if (m_accountUsed == FALSE && m_serviceExists == FALSE) + { + /* + * Check that the Password is not null. + */ + if (m_accountPassword.GetLength() == 0) { + MsgBox(IDS_ERR_NULLPASSWORD); + return; + } + } + + /* Directories */ + m_etcDir = m_targetDir + "\\etc"; + m_binDir = m_targetDir + "\\bin"; + + if (m_defaultDir != m_targetDir) { + if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF) + { + int install = MsgBox(IDS_DIREXIST, + MB_YESNO | MB_ICONQUESTION, m_targetDir); + if (install == IDNO) + return; + } + else { + int createDir = MsgBox(IDS_CREATEDIR, + MB_YESNO | MB_ICONQUESTION, m_targetDir); + if (createDir == IDNO) + return; + } + } + + if (m_accountExists == FALSE) { + success = CreateServiceAccount(m_accountName.GetBuffer(30), + m_accountPassword.GetBuffer(30)); + if (success == FALSE) { + MsgBox(IDS_CREATEACCOUNT_FAILED); + return; + } + m_accountExists = TRUE; + } + + ProgramGroup(FALSE); + +#if _MSC_VER >= 1400 + /* + * Install Visual Studio libraries. As per: + * http://blogs.msdn.com/astebner/archive/2006/08/23/715755.aspx + * + * Vcredist_x86.exe /q:a /c:"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log" + */ + /*system(".\\Vcredist_x86.exe /q:a /c:\"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log\"");*/ + + /* + * Enclose full path to Vcredist_x86.exe in quotes as + * m_currentDir may contain spaces. + */ + sprintf(Vcredist_x86, "\"%s\\Vcredist_x86.exe\"", + (LPCTSTR) m_currentDir); + system(Vcredist_x86); +#endif + try { + CreateDirs(); + CopyFiles(); + RegisterService(); + RegisterMessages(); + + HKEY hKey; + + /* Create a new key for named */ + SetCurrent(IDS_CREATE_KEY); + if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_SUBKEY, + &hKey) == ERROR_SUCCESS) { + // Get the install directory + RegSetValueEx(hKey, "InstallDir", 0, REG_SZ, + (LPBYTE)(LPCTSTR)m_targetDir, + m_targetDir.GetLength()); + RegCloseKey(hKey); + } + + + SetCurrent(IDS_ADD_REMOVE); + if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_UNINSTALL_SUBKEY, + &hKey) == ERROR_SUCCESS) { + CString buf(BIND_DISPLAY_NAME); + + RegSetValueEx(hKey, "DisplayName", 0, REG_SZ, + (LPBYTE)(LPCTSTR)buf, buf.GetLength()); + + buf.Format("%s\\BINDInstall.exe", m_binDir); + RegSetValueEx(hKey, "UninstallString", 0, REG_SZ, + (LPBYTE)(LPCTSTR)buf, buf.GetLength()); + RegCloseKey(hKey); + } + + ProgramGroup(FALSE); + + if (m_startOnInstall) + StartBINDService(); + } + catch(Exception e) { + MessageBox(e.resString); + SetCurrent(IDS_CLEANUP); + FailedInstall(); + MsgBox(IDS_FAIL); + return; + } + catch(DWORD dw) { + 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 + */ +void CBINDInstallDlg::CreateDirs() { + /* s'OK if the directories already exist */ + SetCurrent(IDS_CREATE_DIR, m_targetDir); + if (!CreateDirectory(m_targetDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) + throw(Exception(IDS_ERR_CREATE_DIR, m_targetDir, GetErrMessage())); + + SetCurrent(IDS_CREATE_DIR, m_etcDir); + if (!CreateDirectory(m_etcDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) + throw(Exception(IDS_ERR_CREATE_DIR, m_etcDir, GetErrMessage())); + + SetCurrent(IDS_CREATE_DIR, m_binDir); + if (!CreateDirectory(m_binDir, NULL) && GetLastError() != ERROR_ALREADY_EXISTS) + throw(Exception(IDS_ERR_CREATE_DIR, m_binDir, GetErrMessage())); + + SetItemStatus(IDC_CREATE_DIR); +} + +void CBINDInstallDlg::RemoveDirs(BOOL uninstall) { + if (!m_keepFiles) { + SetCurrent(IDS_REMOVE_DIR, m_binDir); + // Check for existence then remove if present + if (GetFileAttributes(m_binDir) != 0xFFFFFFFF) + RemoveDirectory(m_binDir); + + SetCurrent(IDS_REMOVE_DIR, m_etcDir); + if (GetFileAttributes(m_etcDir) != 0xFFFFFFFF) + RemoveDirectory(m_etcDir); + + SetCurrent(IDS_REMOVE_DIR, m_targetDir); + if (GetFileAttributes(m_targetDir) != 0xFFFFFFFF) + RemoveDirectory(m_targetDir); + } + + if (uninstall) + SetItemStatus(IDC_CREATE_DIR, TRUE); +} + +void CBINDInstallDlg::CopyFiles() { + CString destFile; + + for (int i = 0; installFiles[i].filename; i++) { + SetCurrent(IDS_COPY_FILE, installFiles[i].filename); + + destFile = DestDir(installFiles[i].destination) + "\\" + + installFiles[i].filename; + CString filespec = m_currentDir + "\\" + installFiles[i].filename; + CVersionInfo bindFile(destFile); + + CVersionInfo origFile(filespec); + 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())); + } + + 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. + */ + bindFile.CopyFileNoVersion(origFile); + } + 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) + { + SetItemStatus(IDC_COPY_FILE, FALSE); + throw(Exception(IDS_ERR_COPY_FILE, + installFiles[i].filename, + GetErrMessage())); + } + } + } + } + + SetItemStatus(IDC_COPY_FILE); +} + +void CBINDInstallDlg::DeleteFiles(BOOL uninstall) { + CString destFile; + + for (int i = 0; installFiles[i].filename; i++) { + if (installFiles[i].checkVer) + continue; + + destFile = DestDir(installFiles[i].destination) + "\\" + + installFiles[i].filename; + + if (uninstall) + SetCurrent(IDS_DELETE_FILE, installFiles[i].filename); + + DeleteFile(destFile); + } + + if (!m_keepFiles) { + WIN32_FIND_DATA findData; + CString file = m_etcDir + "\\*.*"; + BOOL rc; + HANDLE hFile; + + hFile = FindFirstFile(file, &findData); + rc = hFile != INVALID_HANDLE_VALUE; + + while (rc == TRUE) { + if (strcmp(findData.cFileName, ".") && + strcmp(findData.cFileName, "..")) { + file = m_etcDir + "\\" + findData.cFileName; + SetCurrent(IDS_DELETE_FILE, file); + DeleteFile(file); + } + rc = FindNextFile(hFile, &findData); + } + FindClose(hFile); + } + + if (uninstall) + SetItemStatus(IDC_COPY_FILE, TRUE); +} + +/* + * Get the service account name out of the registry, if any + */ +void +CBINDInstallDlg::GetCurrentServiceAccountName() { + HKEY hKey; + BOOL keyFound = FALSE; + char accountName[MAX_PATH]; + DWORD nameLen = MAX_PATH; + CString Tmp; + m_accountUsed = FALSE; + + memset(accountName, 0, nameLen); + if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, BIND_SERVICE_SUBKEY, 0, KEY_READ, + &hKey) == ERROR_SUCCESS) { + keyFound = TRUE; + } + else { + m_serviceExists = FALSE; + } + + 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; + } + + 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; + } + } +} + +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); + } + + /* 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); +} + +void +CBINDInstallDlg::RegisterService() { + SC_HANDLE hSCManager; + SC_HANDLE hService; + 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(); + SetItemStatus(IDC_REG_SERVICE); + return; + } + else { + SetItemStatus(IDC_REG_SERVICE); + return; + } + } + + SetCurrent(IDS_OPEN_SCM); + hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!hSCManager) + throw(Exception(IDS_ERR_OPEN_SCM, GetErrMessage())); + + 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_CREATE_SERVICE); + hService = CreateService(hSCManager, BIND_SERVICE_NAME, + BIND_DISPLAY_NAME, SERVICE_ALL_ACCESS, dwServiceType, dwStart, + SERVICE_ERROR_NORMAL, namedLoc, NULL, NULL, NULL, StartName, + m_accountPassword); + + if (!hService && GetLastError() != ERROR_SERVICE_EXISTS) + throw(Exception(IDS_ERR_CREATE_SERVICE, GetErrMessage())); + + if (hService) + CloseServiceHandle(hService); + + if (hSCManager) + CloseServiceHandle(hSCManager); + + SetItemStatus(IDC_REG_SERVICE); +} + +void +CBINDInstallDlg::UpdateService() { + SC_HANDLE hSCManager; + SC_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()); + } + } + + if (hService) + CloseServiceHandle(hService); + + if (hSCManager) + CloseServiceHandle(hSCManager); + + SetItemStatus(IDC_REG_SERVICE); +} + +void CBINDInstallDlg::UnregisterService(BOOL uninstall) { + BOOL rc = FALSE; + SC_HANDLE hSCManager; + SC_HANDLE hService; + + while(1) { + SetCurrent(IDS_OPEN_SCM); + hSCManager= OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!hSCManager && uninstall == TRUE) { + MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage()); + break; + } + + SetCurrent(IDS_OPEN_SERVICE); + hService = OpenService(hSCManager, BIND_SERVICE_NAME, + STANDARD_RIGHTS_REQUIRED); + if (!hService && uninstall == TRUE) + { + if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST) { + MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage()); + break; + } + } + else { + SetCurrent(IDS_REMOVE_SERVICE); + if (!DeleteService(hService) && uninstall == TRUE) { + DWORD err = GetLastError(); + if (err != ERROR_SERVICE_MARKED_FOR_DELETE && + err != ERROR_SERVICE_DOES_NOT_EXIST) { + MsgBox(IDS_ERR_REMOVE_SERVICE, GetErrMessage()); + break; + } + } + } + + rc = TRUE; + break; + } + + if (hService) + CloseServiceHandle(hService); + + if (hSCManager) + CloseServiceHandle(hSCManager); + + if (uninstall) + SetItemStatus(IDC_REG_SERVICE, rc); +} + +void CBINDInstallDlg::RegisterMessages() { + HKEY hKey; + DWORD dwData; + char pszMsgDLL[MAX_PATH]; + + sprintf(pszMsgDLL, "%s\\%s", (LPCTSTR)m_binDir, "bindevt.dll"); + + SetCurrent(IDS_REGISTER_MESSAGES); + /* Create a new key for named */ + if (RegCreateKey(HKEY_LOCAL_MACHINE, BIND_MESSAGE_SUBKEY, &hKey) + != ERROR_SUCCESS) + throw(Exception(IDS_ERR_CREATE_KEY, GetErrMessage())); + + /* Add the Event-ID message-file name to the subkey. */ + if (RegSetValueEx(hKey, "EventMessageFile", 0, REG_EXPAND_SZ, + (LPBYTE)pszMsgDLL, strlen(pszMsgDLL) + 1) != ERROR_SUCCESS) + 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; + if (RegSetValueEx(hKey, "TypesSupported", 0, REG_DWORD, + (LPBYTE)&dwData, sizeof(DWORD)) != ERROR_SUCCESS) + throw(Exception(IDS_ERR_SET_VALUE, GetErrMessage())); + + RegCloseKey(hKey); + + SetItemStatus(IDC_REG_MESSAGE); +} + +void CBINDInstallDlg::UnregisterMessages(BOOL uninstall) { + BOOL rc = FALSE; + HKEY hKey = NULL; + + while(1) { + SetCurrent(IDS_UNREGISTER_MESSAGES); + /* Open key for Application Event Log */ + if (RegOpenKey(HKEY_LOCAL_MACHINE, EVENTLOG_APP_SUBKEY, &hKey) + != ERROR_SUCCESS) + break; + + /* Remove named from the list of messages sources */ + if (RegDeleteKey(hKey, BIND_MESSAGE_NAME) != ERROR_SUCCESS) + break; + + rc = TRUE; + break; + } + + if (hKey) + RegCloseKey(hKey); + + if (uninstall) + SetItemStatus(IDC_REG_MESSAGE, rc); +} + +/* + * Install failed - clean up quietly + */ +void CBINDInstallDlg::FailedInstall() { + UnregisterMessages(FALSE); + UnregisterService(FALSE); + DeleteFiles(FALSE); + RemoveDirs(FALSE); +} + +/* + * Set the checklist tags for install + */ +void CBINDInstallDlg::InstallTags() { + 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 + */ +void CBINDInstallDlg::UninstallTags() { + 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(""); +} + +void CBINDInstallDlg::SetItemStatus(UINT nID, BOOL bSuccess) { + GetDlgItem(nID)->SetWindowText(bSuccess == TRUE ? "Done" : "Failed"); +} + + +/* + * Set the text in the current operation field - use a string table string + */ +void CBINDInstallDlg::SetCurrent(int id, ...) { + CString format; + va_list va; + char buf[128]; + + format.LoadString(id); + memset(buf, 0, 128); + + va_start(va, id); + vsprintf(buf, format, va); + va_end(va); + + m_current.Format("%s", buf); + UpdateData(FALSE); +} + +/* + * Stop the BIND service + */ +void CBINDInstallDlg::StopBINDService() { + SERVICE_STATUS svcStatus; + + SetCurrent(IDS_STOP_SERVICE); + + SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!hSCManager) { + MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage()); + } + + SC_HANDLE hBINDSvc = OpenService(hSCManager, BIND_SERVICE_NAME, + SERVICE_ALL_ACCESS); + if (!hBINDSvc) { + MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage()); + } + + BOOL rc = ControlService(hBINDSvc, SERVICE_CONTROL_STOP, &svcStatus); +} + +/* + * Start the BIND service + */ +void CBINDInstallDlg::StartBINDService() { + SetCurrent(IDS_START_SERVICE); + + SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (!hSCManager) { + MsgBox(IDS_ERR_OPEN_SCM, GetErrMessage()); + } + + SC_HANDLE hBINDSvc = OpenService(hSCManager, BIND_SERVICE_NAME, + SERVICE_ALL_ACCESS); + if (!hBINDSvc) { + MsgBox(IDS_ERR_OPEN_SERVICE, GetErrMessage()); + } + BOOL rc = StartService(hBINDSvc, 0, NULL); +} + +/* + * Check to see if the BIND service is running or not + */ +BOOL CBINDInstallDlg::CheckBINDService() { + SERVICE_STATUS svcStatus; + + SC_HANDLE hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (hSCManager) { + SC_HANDLE hBINDSvc = OpenService(hSCManager, BIND_SERVICE_NAME, + SERVICE_ALL_ACCESS); + if (hBINDSvc) { + BOOL rc = ControlService(hBINDSvc, + SERVICE_CONTROL_INTERROGATE, &svcStatus); + if (!rc) + DWORD err = GetLastError(); + + return (svcStatus.dwCurrentState == SERVICE_RUNNING); + } + } + return (FALSE); +} + +/* + * Display message boxes with variable args, using string table strings + * for the format specifiers + */ +int CBINDInstallDlg::MsgBox(int id, ...) { + CString format; + va_list va; + char buf[BUFSIZ]; + + format.LoadString(id); + memset(buf, 0, BUFSIZ); + + va_start(va, id); + vsprintf(buf, format, va); + va_end(va); + + return (MessageBox(buf)); +} + +int CBINDInstallDlg::MsgBox(int id, UINT type, ...) { + CString format; + va_list va; + char buf[BUFSIZ]; + + format.LoadString(id); + memset(buf, 0, BUFSIZ); + + va_start(va, type); + vsprintf(buf, format, va); + va_end(va); + + return(MessageBox(buf, NULL, type)); +} + +/* + * Call GetLastError(), retrieve the message associated with the error + */ +CString CBINDInstallDlg::GetErrMessage(DWORD err) { + LPVOID msgBuf; + static char buf[BUFSIZ]; + + DWORD len = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, err == -1 ? GetLastError() : err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &msgBuf, 0, NULL ); + + + strcpy(buf, (LPTSTR)msgBuf); + LocalFree(msgBuf); + /* Strip off the period and the \n */ + buf[len - 3] = 0; + return(buf); +} + +void CBINDInstallDlg::ProgramGroup(BOOL create) { + TCHAR path[MAX_PATH], commonPath[MAX_PATH], fileloc[MAX_PATH], linkpath[MAX_PATH]; + HRESULT hres; + IShellLink *psl = NULL; + LPMALLOC pMalloc = NULL; + ITEMIDLIST *itemList = NULL; + + HRESULT hr = SHGetMalloc(&pMalloc); + if (hr != NOERROR) { + MessageBox("Could not get a handle to Shell memory object"); + return; + } + + hr = SHGetSpecialFolderLocation(m_hWnd, CSIDL_COMMON_PROGRAMS, &itemList); + if (hr != NOERROR) { + MessageBox("Could not get a handle to the Common Programs folder"); + if (itemList) { + pMalloc->Free(itemList); + } + return; + } + + hr = SHGetPathFromIDList(itemList, commonPath); + pMalloc->Free(itemList); + + if (create) { + sprintf(path, "%s\\ISC", commonPath); + CreateDirectory(path, NULL); + + sprintf(path, "%s\\ISC\\BIND", commonPath); + CreateDirectory(path, NULL); + + hres = CoInitialize(NULL); + + if (SUCCEEDED(hres)) { + // Get a pointer to the IShellLink interface. + hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID *)&psl); + if (SUCCEEDED(hres)) + { + IPersistFile* ppf; + sprintf(linkpath, "%s\\BINDCtrl.lnk", path); + sprintf(fileloc, "%s\\BINDCtrl.exe", m_binDir); + + psl->SetPath(fileloc); + psl->SetDescription("BIND Control Panel"); + + hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf); + if (SUCCEEDED(hres)) { + WCHAR wsz[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, 0, linkpath, -1, wsz, MAX_PATH); + hres = ppf->Save(wsz, TRUE); + ppf->Release(); + } + + if (GetFileAttributes("readme.txt") != -1) { + sprintf(fileloc, "%s\\Readme.txt", m_targetDir); + sprintf(linkpath, "%s\\Readme.lnk", path); + + psl->SetPath(fileloc); + psl->SetDescription("BIND Readme"); + + hres = psl->QueryInterface(IID_IPersistFile, (void **)&ppf); + if (SUCCEEDED(hres)) { + WCHAR wsz[MAX_PATH]; + + MultiByteToWideChar(CP_ACP, 0, linkpath, -1, wsz, MAX_PATH); + hres = ppf->Save(wsz, TRUE); + ppf->Release(); + } + psl->Release(); + } + } + CoUninitialize(); + } + } + else { + TCHAR filename[MAX_PATH]; + WIN32_FIND_DATA fd; + + sprintf(path, "%s\\ISC\\BIND", commonPath); + + sprintf(filename, "%s\\*.*", path); + HANDLE hFind = FindFirstFile(filename, &fd); + if (hFind != INVALID_HANDLE_VALUE) { + do { + if (strcmp(fd.cFileName, ".") && strcmp(fd.cFileName, "..")) { + sprintf(filename, "%s\\%s", path, fd.cFileName); + DeleteFile(filename); + } + } while (FindNextFile(hFind, &fd)); + FindClose(hFind); + } + RemoveDirectory(path); + sprintf(path, "%s\\ISC", commonPath); + RemoveDirectory(path); + } +} + +CString CBINDInstallDlg::DestDir(int destination) { + switch(destination) { + case FileData::TargetDir: + return m_targetDir; + case FileData::BinDir: + return m_binDir; + case FileData::EtcDir: + return m_etcDir; + case FileData::WinSystem: + return m_winSysDir; + } + return(""); +} |