2 * Portions Copyright (C) 2004-2009 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 2009/12/04 21:59:23 marka 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 {"pkcs11-destroy.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
162 {"pkcs11-keygen.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
163 {"pkcs11-list.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
164 {"readme1st.txt", FileData::BinDir
, FileData::Trivial
, FALSE
, TRUE
},
168 /////////////////////////////////////////////////////////////////////////////
169 // CBINDInstallDlg dialog
171 CBINDInstallDlg::CBINDInstallDlg(CWnd
* pParent
/*=NULL*/)
172 : CDialog(CBINDInstallDlg::IDD
, pParent
) {
175 //{{AFX_DATA_INIT(CBINDInstallDlg)
176 m_targetDir
= _T("");
182 m_startOnInstall
= FALSE
;
183 m_accountName
= _T("");
184 m_accountPassword
= _T("");
185 m_accountName
= _T("");
187 // Note that LoadIcon does not require a subsequent DestroyIcon in Win32
188 m_hIcon
= AfxGetApp()->LoadIcon(IDR_MAINFRAME
);
190 GetSystemDirectory(buf
, MAX_PATH
);
193 m_defaultDir
+= "\\dns";
195 m_accountExists
= FALSE
;
196 m_accountUsed
= FALSE
;
197 m_serviceExists
= TRUE
;
198 GetCurrentServiceAccountName();
199 m_currentAccount
= m_accountName
;
200 if (m_accountName
== "") {
201 m_accountName
= "named";
205 void CBINDInstallDlg::DoDataExchange(CDataExchange
* pDX
) {
206 CDialog::DoDataExchange(pDX
);
207 //{{AFX_DATA_MAP(CBINDInstallDlg)
208 DDX_Text(pDX
, IDC_TARGETDIR
, m_targetDir
);
209 DDX_Text(pDX
, IDC_VERSION
, m_version
);
210 DDX_Text(pDX
, IDC_ACCOUNT_NAME
, m_accountName
);
211 DDX_Text(pDX
, IDC_ACCOUNT_PASSWORD
, m_accountPassword
);
212 DDX_Text(pDX
, IDC_ACCOUNT_PASSWORD_CONFIRM
, m_accountPasswordConfirm
);
213 DDX_Check(pDX
, IDC_TOOLS_ONLY
, m_toolsOnly
);
214 DDX_Check(pDX
, IDC_AUTO_START
, m_autoStart
);
215 DDX_Check(pDX
, IDC_KEEP_FILES
, m_keepFiles
);
216 DDX_Text(pDX
, IDC_CURRENT
, m_current
);
217 DDX_Check(pDX
, IDC_START
, m_startOnInstall
);
221 BEGIN_MESSAGE_MAP(CBINDInstallDlg
, CDialog
)
222 //{{AFX_MSG_MAP(CBINDInstallDlg)
224 ON_WM_QUERYDRAGICON()
225 ON_BN_CLICKED(IDC_BROWSE
, OnBrowse
)
226 ON_BN_CLICKED(IDC_INSTALL
, OnInstall
)
227 ON_BN_CLICKED(IDC_EXIT
, OnExit
)
228 ON_BN_CLICKED(IDC_UNINSTALL
, OnUninstall
)
232 /////////////////////////////////////////////////////////////////////////////
233 // CBINDInstallDlg message handlers
235 BOOL
CBINDInstallDlg::OnInitDialog() {
236 CDialog::OnInitDialog();
238 // Set the icon for this dialog. The framework does this automatically
239 // when the application's main window is not a dialog
240 SetIcon(m_hIcon
, TRUE
); // Set big icon
241 SetIcon(m_hIcon
, FALSE
); // Set small icon
243 char filename
[MAX_PATH
];
244 char dirname
[MAX_PATH
];
245 char *fptr
= &filename
[0];
246 GetModuleFileName(NULL
, filename
, MAX_PATH
);
247 char *dptr
= strrchr(filename
,'\\');
248 size_t index
= dptr
- fptr
;
249 strncpy(dirname
, filename
, index
);
250 dirname
[index
] = '\0';
251 CString
Dirname(dirname
);
252 m_currentDir
= Dirname
;
254 CVersionInfo
bindInst(filename
);
255 if(bindInst
.IsValid())
256 m_version
.Format(IDS_VERSION
, bindInst
.GetFileVersionString());
258 m_version
.LoadString(IDS_NO_VERSION
);
260 DWORD dwBufLen
= MAX_PATH
;
264 m_startOnInstall
= CheckBINDService();
266 /* See if we are installed already */
267 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, BIND_SUBKEY
, 0, KEY_READ
, &hKey
)
270 memset(buf
, 0, MAX_PATH
);
271 // Get the install directory
272 if (RegQueryValueEx(hKey
, "InstallDir", NULL
, NULL
, (LPBYTE
)buf
,
273 &dwBufLen
) == ERROR_SUCCESS
)
279 m_targetDir
= m_defaultDir
;
281 // Set checkbox defaults
287 return (TRUE
); /* return(TRUE) unless you set the focus to a control */
291 * If you add a minimize button to your dialog, you will need the code below
292 * to draw the icon. For MFC applications using the document/view model,
293 * this is automatically done for you by the framework.
296 void CBINDInstallDlg::OnPaint() {
298 CPaintDC
dc(this); // device context for painting
300 SendMessage(WM_ICONERASEBKGND
, (WPARAM
) dc
.GetSafeHdc(), 0);
302 // Center icon in client rectangle
303 int cxIcon
= GetSystemMetrics(SM_CXICON
);
304 int cyIcon
= GetSystemMetrics(SM_CYICON
);
306 GetClientRect(&rect
);
307 int x
= (rect
.Width() - cxIcon
+ 1) / 2;
308 int y
= (rect
.Height() - cyIcon
+ 1) / 2;
311 dc
.DrawIcon(x
, y
, m_hIcon
);
318 // The system calls this to obtain the cursor to display while the user drags
319 // the minimized window.
320 HCURSOR
CBINDInstallDlg::OnQueryDragIcon() {
321 return((HCURSOR
)m_hIcon
);
324 void CBINDInstallDlg::OnBrowse() {
328 if (browse
.DoModal() == IDOK
) {
329 //m_targetDir = browse.m_selectedDir;
335 * User pressed the exit button
337 void CBINDInstallDlg::OnExit() {
342 * User pressed the uninstall button. Make it go.
344 void CBINDInstallDlg::OnUninstall() {
347 if (MsgBox(IDS_UNINSTALL
, MB_YESNO
) == IDYES
) {
348 if (CheckBINDService())
351 SC_HANDLE hSCManager
= OpenSCManager(NULL
, NULL
,
352 SC_MANAGER_ALL_ACCESS
);
354 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
358 SC_HANDLE hService
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
360 if (!hService
&& GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST
){
361 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
366 QueryServiceStatus(hService
, &ss
);
367 if (ss
.dwCurrentState
== SERVICE_RUNNING
) {
368 BOOL rc
= ControlService(hService
,
369 SERVICE_CONTROL_STOP
, &ss
);
370 if (rc
== FALSE
|| ss
.dwCurrentState
!= SERVICE_STOPPED
) {
371 MsgBox(IDS_ERR_STOP_SERVICE
, GetErrMessage());
376 CloseServiceHandle(hService
);
377 CloseServiceHandle(hSCManager
);
380 m_etcDir
= m_targetDir
+ "\\etc";
381 m_binDir
= m_targetDir
+ "\\bin";
384 UnregisterMessages(TRUE
);
385 UnregisterService(TRUE
);
387 if (m_keepFiles
== FALSE
)
390 GetDlgItem(IDC_CREATE_DIR
)->SetWindowText("Not Removed");
393 // Delete registry keys for named
394 RegDeleteKey(HKEY_LOCAL_MACHINE
, BIND_SESSION_SUBKEY
);
395 RegDeleteKey(HKEY_LOCAL_MACHINE
, BIND_SUBKEY
);
396 RegDeleteKey(HKEY_LOCAL_MACHINE
, BIND_UNINSTALL_SUBKEY
);
400 SetCurrent(IDS_UNINSTALL_DONE
);
401 MsgBox(IDS_UNINSTALL_DONE
);
406 * User pressed the install button. Make it go.
408 void CBINDInstallDlg::OnInstall() {
410 char Vcredist_x86
[MAX_PATH
];
412 BOOL success
= FALSE
;
415 if (CheckBINDService())
422 if (!m_toolsOnly
&& m_accountName
!= LOCAL_SERVICE
) {
424 * Check that the Passwords entered match.
426 if (m_accountPassword
!= m_accountPasswordConfirm
) {
427 MsgBox(IDS_ERR_PASSWORD
);
432 * Check that there is not leading / trailing whitespace.
433 * This is for compatibility with the standard password dialog.
434 * Passwords really should be treated as opaque blobs.
436 oldlen
= m_accountPassword
.GetLength();
437 m_accountPassword
.TrimLeft();
438 m_accountPassword
.TrimRight();
439 if (m_accountPassword
.GetLength() != oldlen
) {
440 MsgBox(IDS_ERR_WHITESPACE
);
445 * Check the entered account name.
447 if (ValidateServiceAccount() == FALSE
)
451 * For Registration we need to know if account was changed.
453 if (m_accountName
!= m_currentAccount
)
454 m_accountUsed
= FALSE
;
456 if (m_accountUsed
== FALSE
&& m_serviceExists
== FALSE
)
459 * Check that the Password is not null.
461 if (m_accountPassword
.GetLength() == 0) {
462 MsgBox(IDS_ERR_NULLPASSWORD
);
466 } else if (m_accountName
== LOCAL_SERVICE
) {
467 /* The LocalService always exists. */
468 m_accountExists
= TRUE
;
469 if (m_accountName
!= m_currentAccount
)
470 m_accountUsed
= FALSE
;
474 m_etcDir
= m_targetDir
+ "\\etc";
475 m_binDir
= m_targetDir
+ "\\bin";
477 if (m_defaultDir
!= m_targetDir
) {
478 if (GetFileAttributes(m_targetDir
) != 0xFFFFFFFF)
480 int install
= MsgBox(IDS_DIREXIST
,
481 MB_YESNO
| MB_ICONQUESTION
, m_targetDir
);
486 int createDir
= MsgBox(IDS_CREATEDIR
,
487 MB_YESNO
| MB_ICONQUESTION
, m_targetDir
);
488 if (createDir
== IDNO
)
494 if (m_accountExists
== FALSE
) {
495 success
= CreateServiceAccount(m_accountName
.GetBuffer(30),
496 m_accountPassword
.GetBuffer(30));
497 if (success
== FALSE
) {
498 MsgBox(IDS_CREATEACCOUNT_FAILED
);
501 m_accountExists
= TRUE
;
509 * Install Visual Studio libraries. As per:
510 * http://blogs.msdn.com/astebner/archive/2006/08/23/715755.aspx
512 * Vcredist_x86.exe /q:a /c:"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log"
514 /*system(".\\Vcredist_x86.exe /q:a /c:\"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log\"");*/
517 * Enclose full path to Vcredist_x86.exe in quotes as
518 * m_currentDir may contain spaces.
520 sprintf(Vcredist_x86
, "\"%s\\Vcredist_x86.exe\"",
521 (LPCTSTR
) m_currentDir
);
522 system(Vcredist_x86
);
533 /* Create a new key for named */
534 SetCurrent(IDS_CREATE_KEY
);
535 if (RegCreateKey(HKEY_LOCAL_MACHINE
, BIND_SUBKEY
,
536 &hKey
) == ERROR_SUCCESS
) {
537 // Get the install directory
538 RegSetValueEx(hKey
, "InstallDir", 0, REG_SZ
,
539 (LPBYTE
)(LPCTSTR
)m_targetDir
,
540 m_targetDir
.GetLength());
545 SetCurrent(IDS_ADD_REMOVE
);
546 if (RegCreateKey(HKEY_LOCAL_MACHINE
, BIND_UNINSTALL_SUBKEY
,
547 &hKey
) == ERROR_SUCCESS
) {
548 CString
buf(BIND_DISPLAY_NAME
);
550 RegSetValueEx(hKey
, "DisplayName", 0, REG_SZ
,
551 (LPBYTE
)(LPCTSTR
)buf
, buf
.GetLength());
553 buf
.Format("%s\\BINDInstall.exe", m_binDir
);
554 RegSetValueEx(hKey
, "UninstallString", 0, REG_SZ
,
555 (LPBYTE
)(LPCTSTR
)buf
, buf
.GetLength());
561 if (m_startOnInstall
)
565 MessageBox(e
.resString
);
566 SetCurrent(IDS_CLEANUP
);
573 msg
.Format("A fatal error occured\n(%s)", GetErrMessage(dw
));
575 SetCurrent(IDS_CLEANUP
);
581 SetCurrent(IDS_INSTALL_DONE
);
586 * Methods to do the work
588 void CBINDInstallDlg::CreateDirs() {
589 /* s'OK if the directories already exist */
590 SetCurrent(IDS_CREATE_DIR
, m_targetDir
);
591 if (!CreateDirectory(m_targetDir
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
592 throw(Exception(IDS_ERR_CREATE_DIR
, m_targetDir
, GetErrMessage()));
594 SetCurrent(IDS_CREATE_DIR
, m_etcDir
);
595 if (!CreateDirectory(m_etcDir
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
596 throw(Exception(IDS_ERR_CREATE_DIR
, m_etcDir
, GetErrMessage()));
598 SetCurrent(IDS_CREATE_DIR
, m_binDir
);
599 if (!CreateDirectory(m_binDir
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
600 throw(Exception(IDS_ERR_CREATE_DIR
, m_binDir
, GetErrMessage()));
602 SetItemStatus(IDC_CREATE_DIR
);
605 void CBINDInstallDlg::RemoveDirs(BOOL uninstall
) {
607 SetCurrent(IDS_REMOVE_DIR
, m_binDir
);
608 // Check for existence then remove if present
609 if (GetFileAttributes(m_binDir
) != 0xFFFFFFFF)
610 RemoveDirectory(m_binDir
);
612 SetCurrent(IDS_REMOVE_DIR
, m_etcDir
);
613 if (GetFileAttributes(m_etcDir
) != 0xFFFFFFFF)
614 RemoveDirectory(m_etcDir
);
616 SetCurrent(IDS_REMOVE_DIR
, m_targetDir
);
617 if (GetFileAttributes(m_targetDir
) != 0xFFFFFFFF)
618 RemoveDirectory(m_targetDir
);
622 SetItemStatus(IDC_CREATE_DIR
, TRUE
);
625 void CBINDInstallDlg::CopyFiles() {
628 for (int i
= 0; installFiles
[i
].filename
; i
++) {
629 if (m_toolsOnly
&& !installFiles
[i
].withTools
)
631 SetCurrent(IDS_COPY_FILE
, installFiles
[i
].filename
);
633 destFile
= DestDir(installFiles
[i
].destination
) + "\\" +
634 installFiles
[i
].filename
;
635 CString filespec
= m_currentDir
+ "\\" + installFiles
[i
].filename
;
636 CVersionInfo
bindFile(destFile
);
638 CVersionInfo
origFile(filespec
);
639 if (!origFile
.IsValid() && installFiles
[i
].checkVer
) {
640 if (MsgBox(IDS_FILE_BAD
, MB_YESNO
,
641 installFiles
[i
].filename
) == IDNO
)
642 throw(Exception(IDS_ERR_COPY_FILE
,
643 installFiles
[i
].filename
,
649 * Ignore Version checking. We need to make sure that all files get copied regardless
650 * of whether or not they are earlier or later versions since we cannot guarantee
651 * that we have either backward or forward compatibility between versions.
653 bindFile
.CopyFileNoVersion(origFile
);
656 if (installFiles
[i
].importance
!= FileData::Trivial
) {
657 if (installFiles
[i
].importance
==
658 FileData::Critical
||
659 MsgBox(IDS_ERR_NONCRIT_FILE
, MB_YESNO
,
660 installFiles
[i
].filename
,
661 GetErrMessage()) == IDNO
)
663 SetItemStatus(IDC_COPY_FILE
, FALSE
);
664 throw(Exception(IDS_ERR_COPY_FILE
,
665 installFiles
[i
].filename
,
672 SetItemStatus(IDC_COPY_FILE
);
675 void CBINDInstallDlg::DeleteFiles(BOOL uninstall
) {
678 for (int i
= 0; installFiles
[i
].filename
; i
++) {
679 if (installFiles
[i
].checkVer
)
682 destFile
= DestDir(installFiles
[i
].destination
) + "\\" +
683 installFiles
[i
].filename
;
686 SetCurrent(IDS_DELETE_FILE
, installFiles
[i
].filename
);
688 DeleteFile(destFile
);
692 WIN32_FIND_DATA findData
;
693 CString file
= m_etcDir
+ "\\*.*";
697 hFile
= FindFirstFile(file
, &findData
);
698 rc
= hFile
!= INVALID_HANDLE_VALUE
;
701 if (strcmp(findData
.cFileName
, ".") &&
702 strcmp(findData
.cFileName
, "..")) {
703 file
= m_etcDir
+ "\\" + findData
.cFileName
;
704 SetCurrent(IDS_DELETE_FILE
, file
);
707 rc
= FindNextFile(hFile
, &findData
);
713 SetItemStatus(IDC_COPY_FILE
, TRUE
);
717 * Get the service account name out of the registry, if any
720 CBINDInstallDlg::GetCurrentServiceAccountName() {
722 BOOL keyFound
= FALSE
;
723 char accountName
[MAX_PATH
];
724 DWORD nameLen
= MAX_PATH
;
726 m_accountUsed
= FALSE
;
728 memset(accountName
, 0, nameLen
);
729 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, BIND_SERVICE_SUBKEY
, 0, KEY_READ
,
730 &hKey
) == ERROR_SUCCESS
) {
734 m_serviceExists
= FALSE
;
737 if (keyFound
== TRUE
) {
738 /* Get the named service account, if one was specified */
739 if (RegQueryValueEx(hKey
, "ObjectName", NULL
, NULL
,
740 (LPBYTE
)accountName
, &nameLen
) != ERROR_SUCCESS
)
745 if (keyFound
== FALSE
)
747 else if (!strcmp(accountName
, LOCAL_SERVICE
)) {
748 m_accountName
= LOCAL_SERVICE
;
749 m_accountUsed
= TRUE
;
752 * LocalSystem is not a regular account and is equivalent
753 * to no account but with lots of privileges
756 if (Tmp
== ".\\LocalSystem")
758 /* Found account strip any ".\" from it */
759 if (Tmp
.Left(2) == ".\\") {
760 m_accountName
= Tmp
.Mid(2);
761 m_accountUsed
= TRUE
;
767 CBINDInstallDlg::ValidateServiceAccount() {
768 wchar_t *PrivList
[MAX_PRIVS
];
769 unsigned int PrivCount
= 0;
770 char *Groups
[MAX_GROUPS
];
771 unsigned int totalGroups
= 0;
775 name
= m_accountName
.GetBuffer(30);
777 status
= GetAccountPrivileges(name
, PrivList
, &PrivCount
,
778 Groups
, &totalGroups
, MAX_GROUPS
);
779 if (status
== RTN_NOACCOUNT
) {
780 m_accountExists
= FALSE
;
781 /* We need to do this in case an account was previously used */
782 m_accountUsed
= FALSE
;
785 if (status
!= RTN_OK
) {
786 MsgBox(IDS_ERR_BADACCOUNT
);
790 m_accountExists
= TRUE
;
792 if (MsgBox(IDS_ERR_TOOPRIVED
, MB_YESNO
) == IDYES
)
798 /* See if we have the correct privilege */
799 if (wcscmp(PrivList
[0], SE_SERVICE_LOGON_PRIV
) != 0) {
800 MsgBox(IDS_ERR_WRONGPRIV
, PrivList
[0]);
807 CBINDInstallDlg::RegisterService() {
808 SC_HANDLE hSCManager
;
812 if (m_accountName
== LOCAL_SERVICE
)
813 StartName
= LOCAL_SERVICE
;
815 StartName
= ".\\" + m_accountName
;
817 * We need to change the service rather than create it
818 * if the service already exists. Do nothing if we are already
821 if (m_serviceExists
== TRUE
) {
822 if (m_accountUsed
== FALSE
) {
823 UpdateService(StartName
);
824 SetItemStatus(IDC_REG_SERVICE
);
827 SetItemStatus(IDC_REG_SERVICE
);
832 SetCurrent(IDS_OPEN_SCM
);
833 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
835 throw(Exception(IDS_ERR_OPEN_SCM
, GetErrMessage()));
837 DWORD dwStart
= SERVICE_DEMAND_START
;
839 dwStart
= SERVICE_AUTO_START
;
841 DWORD dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
844 namedLoc
.Format("%s\\bin\\named.exe", m_targetDir
);
846 SetCurrent(IDS_CREATE_SERVICE
);
847 hService
= CreateService(hSCManager
, BIND_SERVICE_NAME
,
848 BIND_DISPLAY_NAME
, SERVICE_ALL_ACCESS
, dwServiceType
, dwStart
,
849 SERVICE_ERROR_NORMAL
, namedLoc
, NULL
, NULL
, NULL
, StartName
,
852 if (!hService
&& GetLastError() != ERROR_SERVICE_EXISTS
)
853 throw(Exception(IDS_ERR_CREATE_SERVICE
, GetErrMessage()));
856 CloseServiceHandle(hService
);
859 CloseServiceHandle(hSCManager
);
861 SetItemStatus(IDC_REG_SERVICE
);
865 CBINDInstallDlg::UpdateService(CString StartName
) {
866 SC_HANDLE hSCManager
;
872 SetCurrent(IDS_OPEN_SCM
);
873 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
875 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
879 DWORD dwStart
= SERVICE_DEMAND_START
;
881 dwStart
= SERVICE_AUTO_START
;
883 DWORD dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
886 namedLoc
.Format("%s\\bin\\named.exe", m_targetDir
);
888 SetCurrent(IDS_OPEN_SERVICE
);
889 hService
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
890 SERVICE_CHANGE_CONFIG
);
893 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
895 CloseServiceHandle(hSCManager
);
898 if (ChangeServiceConfig(hService
, dwServiceType
, dwStart
,
899 SERVICE_ERROR_NORMAL
, namedLoc
, NULL
, NULL
, NULL
,
900 StartName
, m_accountPassword
, BIND_DISPLAY_NAME
)
902 DWORD err
= GetLastError();
903 MsgBox(IDS_ERR_UPDATE_SERVICE
, GetErrMessage());
908 CloseServiceHandle(hService
);
911 CloseServiceHandle(hSCManager
);
913 SetItemStatus(IDC_REG_SERVICE
);
916 void CBINDInstallDlg::UnregisterService(BOOL uninstall
) {
918 SC_HANDLE hSCManager
;
922 SetCurrent(IDS_OPEN_SCM
);
923 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
924 if (!hSCManager
&& uninstall
== TRUE
) {
925 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
929 SetCurrent(IDS_OPEN_SERVICE
);
930 hService
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
931 STANDARD_RIGHTS_REQUIRED
);
932 if (!hService
&& uninstall
== TRUE
)
934 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST
) {
935 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
940 SetCurrent(IDS_REMOVE_SERVICE
);
941 if (!DeleteService(hService
) && uninstall
== TRUE
) {
942 DWORD err
= GetLastError();
943 if (err
!= ERROR_SERVICE_MARKED_FOR_DELETE
&&
944 err
!= ERROR_SERVICE_DOES_NOT_EXIST
) {
945 MsgBox(IDS_ERR_REMOVE_SERVICE
, GetErrMessage());
956 CloseServiceHandle(hService
);
959 CloseServiceHandle(hSCManager
);
962 SetItemStatus(IDC_REG_SERVICE
, rc
);
965 void CBINDInstallDlg::RegisterMessages() {
968 char pszMsgDLL
[MAX_PATH
];
970 sprintf(pszMsgDLL
, "%s\\%s", (LPCTSTR
)m_binDir
, "bindevt.dll");
972 SetCurrent(IDS_REGISTER_MESSAGES
);
973 /* Create a new key for named */
974 if (RegCreateKey(HKEY_LOCAL_MACHINE
, BIND_MESSAGE_SUBKEY
, &hKey
)
976 throw(Exception(IDS_ERR_CREATE_KEY
, GetErrMessage()));
978 /* Add the Event-ID message-file name to the subkey. */
979 if (RegSetValueEx(hKey
, "EventMessageFile", 0, REG_EXPAND_SZ
,
980 (LPBYTE
)pszMsgDLL
, (DWORD
)(strlen(pszMsgDLL
) + 1)) != ERROR_SUCCESS
)
981 throw(Exception(IDS_ERR_SET_VALUE
, GetErrMessage()));
983 /* Set the supported types flags and addit to the subkey. */
984 dwData
= EVENTLOG_ERROR_TYPE
| EVENTLOG_WARNING_TYPE
| EVENTLOG_INFORMATION_TYPE
;
985 if (RegSetValueEx(hKey
, "TypesSupported", 0, REG_DWORD
,
986 (LPBYTE
)&dwData
, sizeof(DWORD
)) != ERROR_SUCCESS
)
987 throw(Exception(IDS_ERR_SET_VALUE
, GetErrMessage()));
991 SetItemStatus(IDC_REG_MESSAGE
);
994 void CBINDInstallDlg::UnregisterMessages(BOOL uninstall
) {
999 SetCurrent(IDS_UNREGISTER_MESSAGES
);
1000 /* Open key for Application Event Log */
1001 if (RegOpenKey(HKEY_LOCAL_MACHINE
, EVENTLOG_APP_SUBKEY
, &hKey
)
1005 /* Remove named from the list of messages sources */
1006 if (RegDeleteKey(hKey
, BIND_MESSAGE_NAME
) != ERROR_SUCCESS
)
1017 SetItemStatus(IDC_REG_MESSAGE
, rc
);
1021 * Install failed - clean up quietly
1023 void CBINDInstallDlg::FailedInstall() {
1024 UnregisterMessages(FALSE
);
1025 UnregisterService(FALSE
);
1031 * Set the checklist tags for install
1033 void CBINDInstallDlg::InstallTags() {
1036 tag
.LoadString(IDS_INSTALL_FILE
);
1037 GetDlgItem(IDC_COPY_TAG
)->SetWindowText(tag
);
1038 GetDlgItem(IDC_COPY_FILE
)->SetWindowText("");
1040 tag
.LoadString(IDS_INSTALL_DIR
);
1041 GetDlgItem(IDC_DIR_TAG
)->SetWindowText(tag
);
1042 GetDlgItem(IDC_CREATE_DIR
)->SetWindowText("");
1043 GetDlgItem(IDC_REG_SERVICE
)->SetWindowText("");
1045 tag
.LoadString(IDS_INSTALL_SERVICE
);
1046 GetDlgItem(IDC_SERVICE_TAG
)->SetWindowText(tag
);
1048 tag
.LoadString(IDS_INSTALL_MESSAGE
);
1049 GetDlgItem(IDC_MESSAGE_TAG
)->SetWindowText(tag
);
1050 GetDlgItem(IDC_REG_MESSAGE
)->SetWindowText("");
1054 * Set the checklist tags for uninstall
1056 void CBINDInstallDlg::UninstallTags() {
1059 tag
.LoadString(IDS_UNINSTALL_FILES
);
1060 GetDlgItem(IDC_COPY_TAG
)->SetWindowText(tag
);
1061 GetDlgItem(IDC_COPY_FILE
)->SetWindowText("");
1063 tag
.LoadString(IDS_UNINSTALL_DIR
);
1064 GetDlgItem(IDC_DIR_TAG
)->SetWindowText(tag
);
1065 GetDlgItem(IDC_CREATE_DIR
)->SetWindowText("");
1067 tag
.LoadString(IDS_UNINSTALL_SERVICE
);
1068 GetDlgItem(IDC_SERVICE_TAG
)->SetWindowText(tag
);
1069 GetDlgItem(IDC_REG_SERVICE
)->SetWindowText("");
1071 tag
.LoadString(IDS_UNINSTALL_MESSAGE
);
1072 GetDlgItem(IDC_MESSAGE_TAG
)->SetWindowText(tag
);
1073 GetDlgItem(IDC_REG_MESSAGE
)->SetWindowText("");
1076 void CBINDInstallDlg::SetItemStatus(UINT nID
, BOOL bSuccess
) {
1077 GetDlgItem(nID
)->SetWindowText(bSuccess
== TRUE
? "Done" : "Failed");
1082 * Set the text in the current operation field - use a string table string
1084 void CBINDInstallDlg::SetCurrent(int id
, ...) {
1089 format
.LoadString(id
);
1090 memset(buf
, 0, 128);
1093 vsprintf(buf
, format
, va
);
1096 m_current
.Format("%s", buf
);
1101 * Stop the BIND service
1103 void CBINDInstallDlg::StopBINDService() {
1104 SERVICE_STATUS svcStatus
;
1106 SetCurrent(IDS_STOP_SERVICE
);
1108 SC_HANDLE hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
1110 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
1113 SC_HANDLE hBINDSvc
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
1114 SERVICE_ALL_ACCESS
);
1116 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
1119 BOOL rc
= ControlService(hBINDSvc
, SERVICE_CONTROL_STOP
, &svcStatus
);
1123 * Start the BIND service
1125 void CBINDInstallDlg::StartBINDService() {
1126 SetCurrent(IDS_START_SERVICE
);
1128 SC_HANDLE hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
1130 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
1133 SC_HANDLE hBINDSvc
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
1134 SERVICE_ALL_ACCESS
);
1136 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
1138 BOOL rc
= StartService(hBINDSvc
, 0, NULL
);
1142 * Check to see if the BIND service is running or not
1144 BOOL
CBINDInstallDlg::CheckBINDService() {
1145 SERVICE_STATUS svcStatus
;
1147 SC_HANDLE hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
1149 SC_HANDLE hBINDSvc
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
1150 SERVICE_ALL_ACCESS
);
1152 BOOL rc
= ControlService(hBINDSvc
,
1153 SERVICE_CONTROL_INTERROGATE
, &svcStatus
);
1155 DWORD err
= GetLastError();
1157 return (svcStatus
.dwCurrentState
== SERVICE_RUNNING
);
1164 * Display message boxes with variable args, using string table strings
1165 * for the format specifiers
1167 int CBINDInstallDlg::MsgBox(int id
, ...) {
1172 format
.LoadString(id
);
1173 memset(buf
, 0, BUFSIZ
);
1176 vsprintf(buf
, format
, va
);
1179 return (MessageBox(buf
));
1182 int CBINDInstallDlg::MsgBox(int id
, UINT type
, ...) {
1187 format
.LoadString(id
);
1188 memset(buf
, 0, BUFSIZ
);
1191 vsprintf(buf
, format
, va
);
1194 return(MessageBox(buf
, NULL
, type
));
1198 * Call GetLastError(), retrieve the message associated with the error
1200 CString
CBINDInstallDlg::GetErrMessage(DWORD err
) {
1202 static char buf
[BUFSIZ
];
1204 DWORD len
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
,
1205 NULL
, err
== -1 ? GetLastError() : err
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), (LPTSTR
) &msgBuf
, 0, NULL
);
1208 strcpy(buf
, (LPTSTR
)msgBuf
);
1210 /* Strip off the period and the \n */
1215 void CBINDInstallDlg::ProgramGroup(BOOL create
) {
1216 TCHAR path
[MAX_PATH
], commonPath
[MAX_PATH
], fileloc
[MAX_PATH
], linkpath
[MAX_PATH
];
1218 IShellLink
*psl
= NULL
;
1219 LPMALLOC pMalloc
= NULL
;
1220 ITEMIDLIST
*itemList
= NULL
;
1222 HRESULT hr
= SHGetMalloc(&pMalloc
);
1223 if (hr
!= NOERROR
) {
1224 MessageBox("Could not get a handle to Shell memory object");
1228 hr
= SHGetSpecialFolderLocation(m_hWnd
, CSIDL_COMMON_PROGRAMS
, &itemList
);
1229 if (hr
!= NOERROR
) {
1230 MessageBox("Could not get a handle to the Common Programs folder");
1232 pMalloc
->Free(itemList
);
1237 hr
= SHGetPathFromIDList(itemList
, commonPath
);
1238 pMalloc
->Free(itemList
);
1241 sprintf(path
, "%s\\ISC", commonPath
);
1242 CreateDirectory(path
, NULL
);
1244 sprintf(path
, "%s\\ISC\\BIND", commonPath
);
1245 CreateDirectory(path
, NULL
);
1247 hres
= CoInitialize(NULL
);
1249 if (SUCCEEDED(hres
)) {
1250 // Get a pointer to the IShellLink interface.
1251 hres
= CoCreateInstance(CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, IID_IShellLink
, (LPVOID
*)&psl
);
1252 if (SUCCEEDED(hres
))
1255 sprintf(linkpath
, "%s\\BINDCtrl.lnk", path
);
1256 sprintf(fileloc
, "%s\\BINDCtrl.exe", m_binDir
);
1258 psl
->SetPath(fileloc
);
1259 psl
->SetDescription("BIND Control Panel");
1261 hres
= psl
->QueryInterface(IID_IPersistFile
, (void **)&ppf
);
1262 if (SUCCEEDED(hres
)) {
1263 WCHAR wsz
[MAX_PATH
];
1265 MultiByteToWideChar(CP_ACP
, 0, linkpath
, -1, wsz
, MAX_PATH
);
1266 hres
= ppf
->Save(wsz
, TRUE
);
1270 if (GetFileAttributes("readme.txt") != -1) {
1271 sprintf(fileloc
, "%s\\Readme.txt", m_targetDir
);
1272 sprintf(linkpath
, "%s\\Readme.lnk", path
);
1274 psl
->SetPath(fileloc
);
1275 psl
->SetDescription("BIND Readme");
1277 hres
= psl
->QueryInterface(IID_IPersistFile
, (void **)&ppf
);
1278 if (SUCCEEDED(hres
)) {
1279 WCHAR wsz
[MAX_PATH
];
1281 MultiByteToWideChar(CP_ACP
, 0, linkpath
, -1, wsz
, MAX_PATH
);
1282 hres
= ppf
->Save(wsz
, TRUE
);
1292 TCHAR filename
[MAX_PATH
];
1295 sprintf(path
, "%s\\ISC\\BIND", commonPath
);
1297 sprintf(filename
, "%s\\*.*", path
);
1298 HANDLE hFind
= FindFirstFile(filename
, &fd
);
1299 if (hFind
!= INVALID_HANDLE_VALUE
) {
1301 if (strcmp(fd
.cFileName
, ".") && strcmp(fd
.cFileName
, "..")) {
1302 sprintf(filename
, "%s\\%s", path
, fd
.cFileName
);
1303 DeleteFile(filename
);
1305 } while (FindNextFile(hFind
, &fd
));
1308 RemoveDirectory(path
);
1309 sprintf(path
, "%s\\ISC", commonPath
);
1310 RemoveDirectory(path
);
1314 CString
CBINDInstallDlg::DestDir(int destination
) {
1315 switch(destination
) {
1316 case FileData::TargetDir
:
1318 case FileData::BinDir
:
1320 case FileData::EtcDir
:
1322 case FileData::WinSystem
: