2 * Portions Copyright (C) 2004-2010, 2013, 2014 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.48 2010/01/07 23:48:54 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
45 * is the debug c-runtime library for MSVC. If you have debug
46 * binaries you want to have DEBUG_BINARIES defined. If you have
47 * release binaries you want to have RELEASE_BINARIES defined.
48 * If you have both, then define them both.
49 * Of course, you need msvcrt[d].dll present to install it!
51 #ifdef BINARIES_INSTALL
52 // # define DEBUG_BINARIES
53 // # define RELEASE_BINARIES
57 #include "BINDInstall.h"
58 #include "BINDInstallDlg.h"
59 #include "DirBrowse.h"
62 #include <named/ntservice.h>
63 #include <isc/bind_registry.h>
64 #include <isc/ntgroups.h>
66 #include "AccountInfo.h"
67 #include "versioninfo.h"
71 #define MAX_GROUPS 100
74 #define LOCAL_SERVICE "NT AUTHORITY\\LocalService"
79 static char THIS_FILE
[] = __FILE__
;
82 typedef struct _xexception
84 _xexception(UINT string
, ...);
89 _xexception::_xexception(UINT string
, ...)
94 format
.LoadString(string
);
97 resString
.FormatV(format
, va
);
101 typedef struct _filedata
{
102 enum FileDestinations
{TargetDir
, BinDir
, EtcDir
, WinSystem
};
103 enum FileImportance
{Trivial
, Normal
, Critical
};
112 const FileData installFiles
[] =
114 #ifdef BINARIES_INSTALL
115 # ifdef DEBUG_BINARIES
116 {"msvcrtd.dll", FileData::WinSystem
, FileData::Critical
, TRUE
, TRUE
},
118 # ifdef RELEASE_BINARIES
119 {"msvcrt.dll", FileData::WinSystem
, FileData::Critical
, TRUE
, TRUE
},
124 {"mfc71.dll", FileData::WinSystem
, FileData::Critical
, TRUE
, TRUE
},
125 {"msvcr71.dll", FileData::WinSystem
, FileData::Critical
, TRUE
, TRUE
},
126 #elif _MSC_VER > 1200 && _MSC_VER < 1310
127 {"mfc70.dll", FileData::WinSystem
, FileData::Critical
, TRUE
, TRUE
},
128 {"msvcr70.dll", FileData::WinSystem
, FileData::Critical
, TRUE
, TRUE
},
131 {"bindevt.dll", FileData::BinDir
, FileData::Normal
, FALSE
, TRUE
},
132 {"libbind9.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
133 {"libisc.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
134 {"libisccfg.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
135 {"libisccc.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
136 {"libdns.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
137 {"liblwres.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
138 {"libirs.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
140 {"libeay32.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
143 {"libxml2.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
147 {"gssapi32.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
148 {"krb5_32.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
150 {"gssapi64.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
151 {"krb5_64.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
155 {"libgeoip.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
158 {"idnkit.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
159 {"iconv.dll", FileData::BinDir
, FileData::Critical
, FALSE
, TRUE
},
161 {"named.exe", FileData::BinDir
, FileData::Critical
, FALSE
, FALSE
},
162 {"nsupdate.exe", FileData::BinDir
, FileData::Normal
, FALSE
, TRUE
},
163 {"BINDInstall.exe", FileData::BinDir
, FileData::Normal
, FALSE
, TRUE
},
164 {"rndc.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
165 {"dig.exe", FileData::BinDir
, FileData::Normal
, FALSE
, TRUE
},
166 {"host.exe", FileData::BinDir
, FileData::Normal
, FALSE
, TRUE
},
167 {"nslookup.exe", FileData::BinDir
, FileData::Normal
, FALSE
, TRUE
},
168 {"delv.exe", FileData::BinDir
, FileData::Normal
, FALSE
, TRUE
},
169 {"arpaname.exe", FileData::BinDir
, FileData::Normal
, FALSE
, TRUE
},
170 {"nsec3hash.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
171 {"genrandom.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
172 {"rndc-confgen.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
173 {"ddns-confgen.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
174 {"tsig-keygen.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
175 {"dnssec-keygen.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
176 {"dnssec-signzone.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
177 {"dnssec-dsfromkey.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
178 {"dnssec-importkey.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
179 {"dnssec-keyfromlabel.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
180 {"dnssec-revoke.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
181 {"dnssec-settime.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
182 {"dnssec-verify.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
183 {"named-checkconf.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
184 {"named-checkzone.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
185 {"named-compilezone.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
186 {"named-journalprint.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
187 {"named-rrchecker.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
188 {"isc-hmax-fixup.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
190 {"pkcs11-destroy.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
191 {"pkcs11-keygen.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
192 {"pkcs11-list.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
193 {"pkcs11-tokens.exe", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
196 {"dnssec-checkds.py", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
197 {"dnssec-coverage.py", FileData::BinDir
, FileData::Normal
, FALSE
, FALSE
},
199 {"readme1st.txt", FileData::BinDir
, FileData::Trivial
, FALSE
, TRUE
},
203 /////////////////////////////////////////////////////////////////////////////
204 // CBINDInstallDlg dialog
206 CBINDInstallDlg::CBINDInstallDlg(CWnd
* pParent
/*=NULL*/)
207 : CDialog(CBINDInstallDlg::IDD
, pParent
) {
208 char winsys
[MAX_PATH
];
209 char progfiles
[MAX_PATH
];
211 //{{AFX_DATA_INIT(CBINDInstallDlg)
212 m_targetDir
= _T("");
218 m_startOnInstall
= FALSE
;
219 m_accountName
= _T("");
220 m_accountPassword
= _T("");
221 m_accountName
= _T("");
223 // Note that LoadIcon does not require a subsequent
224 // DestroyIcon in Win32
225 m_hIcon
= AfxGetApp()->LoadIcon(IDR_MAINFRAME
);
227 GetSystemDirectory(winsys
, MAX_PATH
);
228 m_winSysDir
= winsys
;
231 SHGetFolderPath(NULL
, CSIDL_FLAG_CREATE
|CSIDL_PROGRAM_FILESX86
,
232 NULL
, SHGFP_TYPE_CURRENT
, progfiles
);
234 SHGetFolderPath(NULL
, CSIDL_FLAG_CREATE
|CSIDL_PROGRAM_FILES
,
235 NULL
, SHGFP_TYPE_CURRENT
, progfiles
);
238 m_defaultDir
= progfiles
;
239 m_defaultDir
+= "\\ISC BIND 9";
241 m_accountExists
= FALSE
;
242 m_accountUsed
= FALSE
;
243 m_serviceExists
= TRUE
;
244 GetCurrentServiceAccountName();
245 m_currentAccount
= m_accountName
;
246 if (m_accountName
== "") {
247 m_accountName
= "named";
251 void CBINDInstallDlg::DoDataExchange(CDataExchange
* pDX
) {
252 CDialog::DoDataExchange(pDX
);
253 //{{AFX_DATA_MAP(CBINDInstallDlg)
254 DDX_Text(pDX
, IDC_TARGETDIR
, m_targetDir
);
255 DDX_Text(pDX
, IDC_VERSION
, m_version
);
256 DDX_Text(pDX
, IDC_ACCOUNT_NAME
, m_accountName
);
257 DDX_Text(pDX
, IDC_ACCOUNT_PASSWORD
, m_accountPassword
);
258 DDX_Text(pDX
, IDC_ACCOUNT_PASSWORD_CONFIRM
, m_accountPasswordConfirm
);
259 DDX_Check(pDX
, IDC_TOOLS_ONLY
, m_toolsOnly
);
260 DDX_Check(pDX
, IDC_AUTO_START
, m_autoStart
);
261 DDX_Check(pDX
, IDC_KEEP_FILES
, m_keepFiles
);
262 DDX_Text(pDX
, IDC_CURRENT
, m_current
);
263 DDX_Check(pDX
, IDC_START
, m_startOnInstall
);
267 BEGIN_MESSAGE_MAP(CBINDInstallDlg
, CDialog
)
268 //{{AFX_MSG_MAP(CBINDInstallDlg)
270 ON_WM_QUERYDRAGICON()
271 ON_BN_CLICKED(IDC_BROWSE
, OnBrowse
)
272 ON_BN_CLICKED(IDC_INSTALL
, OnInstall
)
273 ON_BN_CLICKED(IDC_EXIT
, OnExit
)
274 ON_BN_CLICKED(IDC_UNINSTALL
, OnUninstall
)
278 /////////////////////////////////////////////////////////////////////////////
279 // CBINDInstallDlg message handlers
281 BOOL
CBINDInstallDlg::OnInitDialog() {
282 CDialog::OnInitDialog();
284 // Set the icon for this dialog. The framework does this automatically
285 // when the application's main window is not a dialog
286 SetIcon(m_hIcon
, TRUE
); // Set big icon
287 SetIcon(m_hIcon
, FALSE
); // Set small icon
289 char filename
[MAX_PATH
];
290 char dirname
[MAX_PATH
];
291 char *fptr
= &filename
[0];
292 GetModuleFileName(NULL
, filename
, MAX_PATH
);
293 char *dptr
= strrchr(filename
,'\\');
294 size_t index
= dptr
- fptr
;
295 strncpy(dirname
, filename
, index
);
296 dirname
[index
] = '\0';
297 CString
Dirname(dirname
);
298 m_currentDir
= Dirname
;
300 CVersionInfo
bindInst(filename
);
301 if(bindInst
.IsValid())
302 m_version
.Format(IDS_VERSION
, bindInst
.GetFileVersionString());
304 m_version
.LoadString(IDS_NO_VERSION
);
306 DWORD dwBufLen
= MAX_PATH
;
310 m_startOnInstall
= CheckBINDService();
312 /* See if we are installed already */
313 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, BIND_SUBKEY
, 0, KEY_READ
, &hKey
)
316 memset(buf
, 0, MAX_PATH
);
317 // Get the install directory
318 if (RegQueryValueEx(hKey
, "InstallDir", NULL
, NULL
, (LPBYTE
)buf
,
319 &dwBufLen
) == ERROR_SUCCESS
)
325 m_targetDir
= m_defaultDir
;
327 // Set checkbox defaults
333 return (TRUE
); /* return(TRUE) unless you set the focus to a control */
337 * If you add a minimize button to your dialog, you will need the code below
338 * to draw the icon. For MFC applications using the document/view model,
339 * this is automatically done for you by the framework.
342 void CBINDInstallDlg::OnPaint() {
344 CPaintDC
dc(this); // device context for painting
346 SendMessage(WM_ICONERASEBKGND
, (WPARAM
) dc
.GetSafeHdc(), 0);
348 // Center icon in client rectangle
349 int cxIcon
= GetSystemMetrics(SM_CXICON
);
350 int cyIcon
= GetSystemMetrics(SM_CYICON
);
352 GetClientRect(&rect
);
353 int x
= (rect
.Width() - cxIcon
+ 1) / 2;
354 int y
= (rect
.Height() - cyIcon
+ 1) / 2;
357 dc
.DrawIcon(x
, y
, m_hIcon
);
364 // The system calls this to obtain the cursor to display while the user drags
365 // the minimized window.
366 HCURSOR
CBINDInstallDlg::OnQueryDragIcon() {
367 return((HCURSOR
)m_hIcon
);
370 void CBINDInstallDlg::OnBrowse() {
374 if (browse
.DoModal() == IDOK
) {
375 //m_targetDir = browse.m_selectedDir;
381 * User pressed the exit button
383 void CBINDInstallDlg::OnExit() {
388 * User pressed the uninstall button. Make it go.
390 void CBINDInstallDlg::OnUninstall() {
393 if (MsgBox(IDS_UNINSTALL
, MB_YESNO
) == IDYES
) {
394 if (CheckBINDService())
397 SC_HANDLE hSCManager
= OpenSCManager(NULL
, NULL
,
398 SC_MANAGER_ALL_ACCESS
);
400 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
404 SC_HANDLE hService
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
406 if (!hService
&& GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST
){
407 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
412 QueryServiceStatus(hService
, &ss
);
413 if (ss
.dwCurrentState
== SERVICE_RUNNING
) {
414 BOOL rc
= ControlService(hService
,
415 SERVICE_CONTROL_STOP
, &ss
);
416 if (rc
== FALSE
|| ss
.dwCurrentState
!= SERVICE_STOPPED
) {
417 MsgBox(IDS_ERR_STOP_SERVICE
, GetErrMessage());
422 CloseServiceHandle(hService
);
423 CloseServiceHandle(hSCManager
);
426 m_etcDir
= m_targetDir
+ "\\etc";
427 m_binDir
= m_targetDir
+ "\\bin";
430 UnregisterMessages(TRUE
);
431 UnregisterService(TRUE
);
433 if (m_keepFiles
== FALSE
)
436 GetDlgItem(IDC_CREATE_DIR
)->SetWindowText("Not Removed");
439 // Delete registry keys for named
440 RegDeleteKey(HKEY_LOCAL_MACHINE
, BIND_SESSION_SUBKEY
);
441 RegDeleteKey(HKEY_LOCAL_MACHINE
, BIND_SUBKEY
);
442 RegDeleteKey(HKEY_LOCAL_MACHINE
, BIND_UNINSTALL_SUBKEY
);
446 SetCurrent(IDS_UNINSTALL_DONE
);
447 MsgBox(IDS_UNINSTALL_DONE
);
452 * User pressed the install button. Make it go.
454 void CBINDInstallDlg::OnInstall() {
456 char Vcredist_x86
[MAX_PATH
];
458 BOOL success
= FALSE
;
461 if (CheckBINDService())
468 if (!m_toolsOnly
&& m_accountName
!= LOCAL_SERVICE
) {
470 * Check that the Passwords entered match.
472 if (m_accountPassword
!= m_accountPasswordConfirm
) {
473 MsgBox(IDS_ERR_PASSWORD
);
478 * Check that there is not leading / trailing whitespace.
479 * This is for compatibility with the standard password dialog.
480 * Passwords really should be treated as opaque blobs.
482 oldlen
= m_accountPassword
.GetLength();
483 m_accountPassword
.TrimLeft();
484 m_accountPassword
.TrimRight();
485 if (m_accountPassword
.GetLength() != oldlen
) {
486 MsgBox(IDS_ERR_WHITESPACE
);
491 * Check the entered account name.
493 if (ValidateServiceAccount() == FALSE
)
497 * For Registration we need to know if account was changed.
499 if (m_accountName
!= m_currentAccount
)
500 m_accountUsed
= FALSE
;
502 if (m_accountUsed
== FALSE
&& m_serviceExists
== FALSE
)
505 * Check that the Password is not null.
507 if (m_accountPassword
.GetLength() == 0) {
508 MsgBox(IDS_ERR_NULLPASSWORD
);
512 } else if (m_accountName
== LOCAL_SERVICE
) {
513 /* The LocalService always exists. */
514 m_accountExists
= TRUE
;
515 if (m_accountName
!= m_currentAccount
)
516 m_accountUsed
= FALSE
;
520 m_etcDir
= m_targetDir
+ "\\etc";
521 m_binDir
= m_targetDir
+ "\\bin";
523 if (m_defaultDir
!= m_targetDir
) {
524 if (GetFileAttributes(m_targetDir
) != 0xFFFFFFFF)
526 int install
= MsgBox(IDS_DIREXIST
,
527 MB_YESNO
| MB_ICONQUESTION
, m_targetDir
);
532 int createDir
= MsgBox(IDS_CREATEDIR
,
533 MB_YESNO
| MB_ICONQUESTION
, m_targetDir
);
534 if (createDir
== IDNO
)
540 if (m_accountExists
== FALSE
) {
541 success
= CreateServiceAccount(m_accountName
.GetBuffer(30),
542 m_accountPassword
.GetBuffer(30));
543 if (success
== FALSE
) {
544 MsgBox(IDS_CREATEACCOUNT_FAILED
);
547 m_accountExists
= TRUE
;
555 * Install Visual Studio libraries. As per:
556 * http://blogs.msdn.com/astebner/archive/2006/08/23/715755.aspx
558 * Vcredist_x86.exe /q:a /c:"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log"
560 /*system(".\\Vcredist_x86.exe /q:a /c:\"msiexec /i vcredist.msi /qn /l*v %temp%\vcredist_x86.log\"");*/
563 * Enclose full path to Vcredist_x86.exe in quotes as
564 * m_currentDir may contain spaces.
567 sprintf(Vcredist_x86
, "\"%s\\Vcredist_x86.exe\"",
568 (LPCTSTR
) m_currentDir
);
570 sprintf(Vcredist_x86
, "\"%s\\Vcredist_x64.exe\"",
571 (LPCTSTR
) m_currentDir
);
573 system(Vcredist_x86
);
584 /* Create a new key for named */
585 SetCurrent(IDS_CREATE_KEY
);
586 if (RegCreateKey(HKEY_LOCAL_MACHINE
, BIND_SUBKEY
,
587 &hKey
) == ERROR_SUCCESS
) {
588 // Get the install directory
589 RegSetValueEx(hKey
, "InstallDir", 0, REG_SZ
,
590 (LPBYTE
)(LPCTSTR
)m_targetDir
,
591 m_targetDir
.GetLength());
596 SetCurrent(IDS_ADD_REMOVE
);
597 if (RegCreateKey(HKEY_LOCAL_MACHINE
, BIND_UNINSTALL_SUBKEY
,
598 &hKey
) == ERROR_SUCCESS
) {
599 CString
buf(BIND_DISPLAY_NAME
);
601 RegSetValueEx(hKey
, "DisplayName", 0, REG_SZ
,
602 (LPBYTE
)(LPCTSTR
)buf
, buf
.GetLength());
604 buf
.Format("%s\\BINDInstall.exe", m_binDir
);
605 RegSetValueEx(hKey
, "UninstallString", 0, REG_SZ
,
606 (LPBYTE
)(LPCTSTR
)buf
, buf
.GetLength());
612 if (m_startOnInstall
)
616 MessageBox(e
.resString
);
617 SetCurrent(IDS_CLEANUP
);
624 msg
.Format("A fatal error occured\n(%s)", GetErrMessage(dw
));
626 SetCurrent(IDS_CLEANUP
);
632 SetCurrent(IDS_INSTALL_DONE
);
637 * Methods to do the work
639 void CBINDInstallDlg::CreateDirs() {
640 /* s'OK if the directories already exist */
641 SetCurrent(IDS_CREATE_DIR
, m_targetDir
);
642 if (!CreateDirectory(m_targetDir
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
643 throw(Exception(IDS_ERR_CREATE_DIR
, m_targetDir
, GetErrMessage()));
645 SetCurrent(IDS_CREATE_DIR
, m_etcDir
);
646 if (!CreateDirectory(m_etcDir
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
647 throw(Exception(IDS_ERR_CREATE_DIR
, m_etcDir
, GetErrMessage()));
649 SetCurrent(IDS_CREATE_DIR
, m_binDir
);
650 if (!CreateDirectory(m_binDir
, NULL
) && GetLastError() != ERROR_ALREADY_EXISTS
)
651 throw(Exception(IDS_ERR_CREATE_DIR
, m_binDir
, GetErrMessage()));
653 SetItemStatus(IDC_CREATE_DIR
);
656 void CBINDInstallDlg::RemoveDirs(BOOL uninstall
) {
658 SetCurrent(IDS_REMOVE_DIR
, m_binDir
);
659 // Check for existence then remove if present
660 if (GetFileAttributes(m_binDir
) != 0xFFFFFFFF)
661 RemoveDirectory(m_binDir
);
663 SetCurrent(IDS_REMOVE_DIR
, m_etcDir
);
664 if (GetFileAttributes(m_etcDir
) != 0xFFFFFFFF)
665 RemoveDirectory(m_etcDir
);
667 SetCurrent(IDS_REMOVE_DIR
, m_targetDir
);
668 if (GetFileAttributes(m_targetDir
) != 0xFFFFFFFF)
669 RemoveDirectory(m_targetDir
);
673 SetItemStatus(IDC_CREATE_DIR
, TRUE
);
676 void CBINDInstallDlg::CopyFiles() {
679 for (int i
= 0; installFiles
[i
].filename
; i
++) {
680 if (m_toolsOnly
&& !installFiles
[i
].withTools
)
682 SetCurrent(IDS_COPY_FILE
, installFiles
[i
].filename
);
684 destFile
= DestDir(installFiles
[i
].destination
) + "\\" +
685 installFiles
[i
].filename
;
686 CString filespec
= m_currentDir
+ "\\" + installFiles
[i
].filename
;
687 CVersionInfo
bindFile(destFile
);
689 CVersionInfo
origFile(filespec
);
690 if (!origFile
.IsValid() && installFiles
[i
].checkVer
) {
691 if (MsgBox(IDS_FILE_BAD
, MB_YESNO
,
692 installFiles
[i
].filename
) == IDNO
)
693 throw(Exception(IDS_ERR_COPY_FILE
,
694 installFiles
[i
].filename
,
700 * Ignore Version checking. We need to make sure that all files get
701 * copied regardless of whether or not they are earlier or later
702 * versions since we cannot guarantee that we have either backward or
703 * forward compatibility between versions.
705 bindFile
.CopyFileNoVersion(origFile
);
708 if (installFiles
[i
].importance
!= FileData::Trivial
) {
709 if (installFiles
[i
].importance
==
710 FileData::Critical
||
711 MsgBox(IDS_ERR_NONCRIT_FILE
, MB_YESNO
,
712 installFiles
[i
].filename
,
713 GetErrMessage()) == IDNO
)
715 SetItemStatus(IDC_COPY_FILE
, FALSE
);
716 throw(Exception(IDS_ERR_COPY_FILE
,
717 installFiles
[i
].filename
,
724 SetItemStatus(IDC_COPY_FILE
);
727 void CBINDInstallDlg::DeleteFiles(BOOL uninstall
) {
730 for (int i
= 0; installFiles
[i
].filename
; i
++) {
731 if (installFiles
[i
].checkVer
)
734 destFile
= DestDir(installFiles
[i
].destination
) + "\\" +
735 installFiles
[i
].filename
;
738 SetCurrent(IDS_DELETE_FILE
, installFiles
[i
].filename
);
740 DeleteFile(destFile
);
744 WIN32_FIND_DATA findData
;
745 CString file
= m_etcDir
+ "\\*.*";
749 hFile
= FindFirstFile(file
, &findData
);
750 rc
= hFile
!= INVALID_HANDLE_VALUE
;
753 if (strcmp(findData
.cFileName
, ".") &&
754 strcmp(findData
.cFileName
, "..")) {
755 file
= m_etcDir
+ "\\" + findData
.cFileName
;
756 SetCurrent(IDS_DELETE_FILE
, file
);
759 rc
= FindNextFile(hFile
, &findData
);
765 SetItemStatus(IDC_COPY_FILE
, TRUE
);
769 * Get the service account name out of the registry, if any
772 CBINDInstallDlg::GetCurrentServiceAccountName() {
774 BOOL keyFound
= FALSE
;
775 char accountName
[MAX_PATH
];
776 DWORD nameLen
= MAX_PATH
;
778 m_accountUsed
= FALSE
;
780 memset(accountName
, 0, nameLen
);
781 if (RegOpenKeyEx(HKEY_LOCAL_MACHINE
, BIND_SERVICE_SUBKEY
, 0, KEY_READ
,
782 &hKey
) == ERROR_SUCCESS
) {
786 m_serviceExists
= FALSE
;
789 if (keyFound
== TRUE
) {
790 /* Get the named service account, if one was specified */
791 if (RegQueryValueEx(hKey
, "ObjectName", NULL
, NULL
,
792 (LPBYTE
)accountName
, &nameLen
) != ERROR_SUCCESS
)
797 if (keyFound
== FALSE
)
799 else if (!strcmp(accountName
, LOCAL_SERVICE
)) {
800 m_accountName
= LOCAL_SERVICE
;
801 m_accountUsed
= TRUE
;
804 * LocalSystem is not a regular account and is equivalent
805 * to no account but with lots of privileges
808 if (Tmp
== ".\\LocalSystem")
810 /* Found account strip any ".\" from it */
811 if (Tmp
.Left(2) == ".\\") {
812 m_accountName
= Tmp
.Mid(2);
813 m_accountUsed
= TRUE
;
819 CBINDInstallDlg::ValidateServiceAccount() {
820 wchar_t *PrivList
[MAX_PRIVS
];
821 unsigned int PrivCount
= 0;
822 char *Groups
[MAX_GROUPS
];
823 unsigned int totalGroups
= 0;
827 name
= m_accountName
.GetBuffer(30);
829 status
= GetAccountPrivileges(name
, PrivList
, &PrivCount
,
830 Groups
, &totalGroups
, MAX_GROUPS
);
831 if (status
== RTN_NOACCOUNT
) {
832 m_accountExists
= FALSE
;
833 /* We need to do this in case an account was previously used */
834 m_accountUsed
= FALSE
;
837 if (status
!= RTN_OK
) {
838 MsgBox(IDS_ERR_BADACCOUNT
);
842 m_accountExists
= TRUE
;
844 if (MsgBox(IDS_ERR_TOOPRIVED
, MB_YESNO
) == IDYES
)
850 /* See if we have the correct privilege */
851 if (wcscmp(PrivList
[0], SE_SERVICE_LOGON_PRIV
) != 0) {
852 MsgBox(IDS_ERR_WRONGPRIV
, PrivList
[0]);
859 CBINDInstallDlg::RegisterService() {
860 SC_HANDLE hSCManager
;
864 if (m_accountName
== LOCAL_SERVICE
)
865 StartName
= LOCAL_SERVICE
;
867 StartName
= ".\\" + m_accountName
;
869 * We need to change the service rather than create it
870 * if the service already exists. Do nothing if we are already
873 if (m_serviceExists
== TRUE
) {
874 if (m_accountUsed
== FALSE
) {
875 UpdateService(StartName
);
876 SetItemStatus(IDC_REG_SERVICE
);
879 SetItemStatus(IDC_REG_SERVICE
);
884 SetCurrent(IDS_OPEN_SCM
);
885 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
887 throw(Exception(IDS_ERR_OPEN_SCM
, GetErrMessage()));
889 DWORD dwStart
= SERVICE_DEMAND_START
;
891 dwStart
= SERVICE_AUTO_START
;
893 DWORD dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
896 namedLoc
.Format("%s\\bin\\named.exe", m_targetDir
);
898 SetCurrent(IDS_CREATE_SERVICE
);
899 hService
= CreateService(hSCManager
, BIND_SERVICE_NAME
,
900 BIND_DISPLAY_NAME
, SERVICE_ALL_ACCESS
, dwServiceType
, dwStart
,
901 SERVICE_ERROR_NORMAL
, namedLoc
, NULL
, NULL
, NULL
, StartName
,
904 if (!hService
&& GetLastError() != ERROR_SERVICE_EXISTS
)
905 throw(Exception(IDS_ERR_CREATE_SERVICE
, GetErrMessage()));
908 CloseServiceHandle(hService
);
911 CloseServiceHandle(hSCManager
);
913 SetItemStatus(IDC_REG_SERVICE
);
917 CBINDInstallDlg::UpdateService(CString StartName
) {
918 SC_HANDLE hSCManager
;
924 SetCurrent(IDS_OPEN_SCM
);
925 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
927 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
931 DWORD dwStart
= SERVICE_DEMAND_START
;
933 dwStart
= SERVICE_AUTO_START
;
935 DWORD dwServiceType
= SERVICE_WIN32_OWN_PROCESS
;
938 namedLoc
.Format("%s\\bin\\named.exe", m_targetDir
);
940 SetCurrent(IDS_OPEN_SERVICE
);
941 hService
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
942 SERVICE_CHANGE_CONFIG
);
945 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
947 CloseServiceHandle(hSCManager
);
950 if (ChangeServiceConfig(hService
, dwServiceType
, dwStart
,
951 SERVICE_ERROR_NORMAL
, namedLoc
, NULL
, NULL
, NULL
,
952 StartName
, m_accountPassword
, BIND_DISPLAY_NAME
)
954 DWORD err
= GetLastError();
955 MsgBox(IDS_ERR_UPDATE_SERVICE
, GetErrMessage());
960 CloseServiceHandle(hService
);
963 CloseServiceHandle(hSCManager
);
965 SetItemStatus(IDC_REG_SERVICE
);
968 void CBINDInstallDlg::UnregisterService(BOOL uninstall
) {
970 SC_HANDLE hSCManager
;
974 SetCurrent(IDS_OPEN_SCM
);
975 hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
976 if (!hSCManager
&& uninstall
== TRUE
) {
977 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
981 SetCurrent(IDS_OPEN_SERVICE
);
982 hService
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
983 STANDARD_RIGHTS_REQUIRED
);
984 if (!hService
&& uninstall
== TRUE
)
986 if (GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST
) {
987 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
992 SetCurrent(IDS_REMOVE_SERVICE
);
993 if (!DeleteService(hService
) && uninstall
== TRUE
) {
994 DWORD err
= GetLastError();
995 if (err
!= ERROR_SERVICE_MARKED_FOR_DELETE
&&
996 err
!= ERROR_SERVICE_DOES_NOT_EXIST
) {
997 MsgBox(IDS_ERR_REMOVE_SERVICE
,
1009 CloseServiceHandle(hService
);
1012 CloseServiceHandle(hSCManager
);
1015 SetItemStatus(IDC_REG_SERVICE
, rc
);
1018 void CBINDInstallDlg::RegisterMessages() {
1021 char pszMsgDLL
[MAX_PATH
];
1023 sprintf(pszMsgDLL
, "%s\\%s", (LPCTSTR
)m_binDir
, "bindevt.dll");
1025 SetCurrent(IDS_REGISTER_MESSAGES
);
1026 /* Create a new key for named */
1027 if (RegCreateKey(HKEY_LOCAL_MACHINE
, BIND_MESSAGE_SUBKEY
, &hKey
)
1029 throw(Exception(IDS_ERR_CREATE_KEY
, GetErrMessage()));
1031 /* Add the Event-ID message-file name to the subkey. */
1032 if (RegSetValueEx(hKey
, "EventMessageFile", 0, REG_EXPAND_SZ
,
1033 (LPBYTE
)pszMsgDLL
, (DWORD
)(strlen(pszMsgDLL
) + 1)) != ERROR_SUCCESS
)
1034 throw(Exception(IDS_ERR_SET_VALUE
, GetErrMessage()));
1036 /* Set the supported types flags and addit to the subkey. */
1037 dwData
= EVENTLOG_ERROR_TYPE
| EVENTLOG_WARNING_TYPE
| EVENTLOG_INFORMATION_TYPE
;
1038 if (RegSetValueEx(hKey
, "TypesSupported", 0, REG_DWORD
,
1039 (LPBYTE
)&dwData
, sizeof(DWORD
)) != ERROR_SUCCESS
)
1040 throw(Exception(IDS_ERR_SET_VALUE
, GetErrMessage()));
1044 SetItemStatus(IDC_REG_MESSAGE
);
1047 void CBINDInstallDlg::UnregisterMessages(BOOL uninstall
) {
1052 SetCurrent(IDS_UNREGISTER_MESSAGES
);
1053 /* Open key for Application Event Log */
1054 if (RegOpenKey(HKEY_LOCAL_MACHINE
, EVENTLOG_APP_SUBKEY
, &hKey
)
1058 /* Remove named from the list of messages sources */
1059 if (RegDeleteKey(hKey
, BIND_MESSAGE_NAME
) != ERROR_SUCCESS
)
1070 SetItemStatus(IDC_REG_MESSAGE
, rc
);
1074 * Install failed - clean up quietly
1076 void CBINDInstallDlg::FailedInstall() {
1077 UnregisterMessages(FALSE
);
1078 UnregisterService(FALSE
);
1084 * Set the checklist tags for install
1086 void CBINDInstallDlg::InstallTags() {
1089 tag
.LoadString(IDS_INSTALL_FILE
);
1090 GetDlgItem(IDC_COPY_TAG
)->SetWindowText(tag
);
1091 GetDlgItem(IDC_COPY_FILE
)->SetWindowText("");
1093 tag
.LoadString(IDS_INSTALL_DIR
);
1094 GetDlgItem(IDC_DIR_TAG
)->SetWindowText(tag
);
1095 GetDlgItem(IDC_CREATE_DIR
)->SetWindowText("");
1096 GetDlgItem(IDC_REG_SERVICE
)->SetWindowText("");
1098 tag
.LoadString(IDS_INSTALL_SERVICE
);
1099 GetDlgItem(IDC_SERVICE_TAG
)->SetWindowText(tag
);
1101 tag
.LoadString(IDS_INSTALL_MESSAGE
);
1102 GetDlgItem(IDC_MESSAGE_TAG
)->SetWindowText(tag
);
1103 GetDlgItem(IDC_REG_MESSAGE
)->SetWindowText("");
1107 * Set the checklist tags for uninstall
1109 void CBINDInstallDlg::UninstallTags() {
1112 tag
.LoadString(IDS_UNINSTALL_FILES
);
1113 GetDlgItem(IDC_COPY_TAG
)->SetWindowText(tag
);
1114 GetDlgItem(IDC_COPY_FILE
)->SetWindowText("");
1116 tag
.LoadString(IDS_UNINSTALL_DIR
);
1117 GetDlgItem(IDC_DIR_TAG
)->SetWindowText(tag
);
1118 GetDlgItem(IDC_CREATE_DIR
)->SetWindowText("");
1120 tag
.LoadString(IDS_UNINSTALL_SERVICE
);
1121 GetDlgItem(IDC_SERVICE_TAG
)->SetWindowText(tag
);
1122 GetDlgItem(IDC_REG_SERVICE
)->SetWindowText("");
1124 tag
.LoadString(IDS_UNINSTALL_MESSAGE
);
1125 GetDlgItem(IDC_MESSAGE_TAG
)->SetWindowText(tag
);
1126 GetDlgItem(IDC_REG_MESSAGE
)->SetWindowText("");
1129 void CBINDInstallDlg::SetItemStatus(UINT nID
, BOOL bSuccess
) {
1130 GetDlgItem(nID
)->SetWindowText(bSuccess
== TRUE
? "Done" : "Failed");
1135 * Set the text in the current operation field - use a string table string
1137 void CBINDInstallDlg::SetCurrent(int id
, ...) {
1142 format
.LoadString(id
);
1143 memset(buf
, 0, 128);
1146 vsprintf(buf
, format
, va
);
1149 m_current
.Format("%s", buf
);
1154 * Stop the BIND service
1156 void CBINDInstallDlg::StopBINDService() {
1157 SERVICE_STATUS svcStatus
;
1159 SetCurrent(IDS_STOP_SERVICE
);
1161 SC_HANDLE hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
1163 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
1166 SC_HANDLE hBINDSvc
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
1167 SERVICE_ALL_ACCESS
);
1169 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
1172 BOOL rc
= ControlService(hBINDSvc
, SERVICE_CONTROL_STOP
, &svcStatus
);
1176 * Start the BIND service
1178 void CBINDInstallDlg::StartBINDService() {
1179 SetCurrent(IDS_START_SERVICE
);
1181 SC_HANDLE hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
1183 MsgBox(IDS_ERR_OPEN_SCM
, GetErrMessage());
1186 SC_HANDLE hBINDSvc
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
1187 SERVICE_ALL_ACCESS
);
1189 MsgBox(IDS_ERR_OPEN_SERVICE
, GetErrMessage());
1191 BOOL rc
= StartService(hBINDSvc
, 0, NULL
);
1195 * Check to see if the BIND service is running or not
1197 BOOL
CBINDInstallDlg::CheckBINDService() {
1198 SERVICE_STATUS svcStatus
;
1200 SC_HANDLE hSCManager
= OpenSCManager(NULL
, NULL
, SC_MANAGER_ALL_ACCESS
);
1202 SC_HANDLE hBINDSvc
= OpenService(hSCManager
, BIND_SERVICE_NAME
,
1203 SERVICE_ALL_ACCESS
);
1205 BOOL rc
= ControlService(hBINDSvc
,
1206 SERVICE_CONTROL_INTERROGATE
, &svcStatus
);
1208 DWORD err
= GetLastError();
1210 return (svcStatus
.dwCurrentState
== SERVICE_RUNNING
);
1217 * Display message boxes with variable args, using string table strings
1218 * for the format specifiers
1220 int CBINDInstallDlg::MsgBox(int id
, ...) {
1225 format
.LoadString(id
);
1226 memset(buf
, 0, BUFSIZ
);
1229 vsprintf(buf
, format
, va
);
1232 return (MessageBox(buf
));
1235 int CBINDInstallDlg::MsgBox(int id
, UINT type
, ...) {
1240 format
.LoadString(id
);
1241 memset(buf
, 0, BUFSIZ
);
1244 vsprintf(buf
, format
, va
);
1247 return(MessageBox(buf
, NULL
, type
));
1251 * Call GetLastError(), retrieve the message associated with the error
1253 CString
CBINDInstallDlg::GetErrMessage(DWORD err
) {
1255 static char buf
[BUFSIZ
];
1257 DWORD len
= FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER
| FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS
,
1258 NULL
, err
== -1 ? GetLastError() : err
, MAKELANGID(LANG_NEUTRAL
, SUBLANG_DEFAULT
), (LPTSTR
) &msgBuf
, 0, NULL
);
1261 strcpy(buf
, (LPTSTR
)msgBuf
);
1263 /* Strip off the period and the \n */
1268 void CBINDInstallDlg::ProgramGroup(BOOL create
) {
1269 TCHAR path
[MAX_PATH
], commonPath
[MAX_PATH
], fileloc
[MAX_PATH
], linkpath
[MAX_PATH
];
1271 IShellLink
*psl
= NULL
;
1272 LPMALLOC pMalloc
= NULL
;
1273 ITEMIDLIST
*itemList
= NULL
;
1275 HRESULT hr
= SHGetMalloc(&pMalloc
);
1276 if (hr
!= NOERROR
) {
1277 MessageBox("Could not get a handle to Shell memory object");
1281 hr
= SHGetSpecialFolderLocation(m_hWnd
, CSIDL_COMMON_PROGRAMS
, &itemList
);
1282 if (hr
!= NOERROR
) {
1283 MessageBox("Could not get a handle to the Common Programs folder");
1285 pMalloc
->Free(itemList
);
1290 hr
= SHGetPathFromIDList(itemList
, commonPath
);
1291 pMalloc
->Free(itemList
);
1294 sprintf(path
, "%s\\ISC", commonPath
);
1295 CreateDirectory(path
, NULL
);
1297 sprintf(path
, "%s\\ISC\\BIND", commonPath
);
1298 CreateDirectory(path
, NULL
);
1300 hres
= CoInitialize(NULL
);
1302 if (SUCCEEDED(hres
)) {
1303 // Get a pointer to the IShellLink interface.
1304 hres
= CoCreateInstance(CLSID_ShellLink
, NULL
, CLSCTX_INPROC_SERVER
, IID_IShellLink
, (LPVOID
*)&psl
);
1305 if (SUCCEEDED(hres
))
1308 sprintf(linkpath
, "%s\\BINDCtrl.lnk", path
);
1309 sprintf(fileloc
, "%s\\BINDCtrl.exe", m_binDir
);
1311 psl
->SetPath(fileloc
);
1312 psl
->SetDescription("BIND Control Panel");
1314 hres
= psl
->QueryInterface(IID_IPersistFile
, (void **)&ppf
);
1315 if (SUCCEEDED(hres
)) {
1316 WCHAR wsz
[MAX_PATH
];
1318 MultiByteToWideChar(CP_ACP
, 0, linkpath
, -1, wsz
, MAX_PATH
);
1319 hres
= ppf
->Save(wsz
, TRUE
);
1323 if (GetFileAttributes("readme.txt") != -1) {
1324 sprintf(fileloc
, "%s\\Readme.txt", m_targetDir
);
1325 sprintf(linkpath
, "%s\\Readme.lnk", path
);
1327 psl
->SetPath(fileloc
);
1328 psl
->SetDescription("BIND Readme");
1330 hres
= psl
->QueryInterface(IID_IPersistFile
, (void **)&ppf
);
1331 if (SUCCEEDED(hres
)) {
1332 WCHAR wsz
[MAX_PATH
];
1334 MultiByteToWideChar(CP_ACP
, 0, linkpath
, -1, wsz
, MAX_PATH
);
1335 hres
= ppf
->Save(wsz
, TRUE
);
1345 TCHAR filename
[MAX_PATH
];
1348 sprintf(path
, "%s\\ISC\\BIND", commonPath
);
1350 sprintf(filename
, "%s\\*.*", path
);
1351 HANDLE hFind
= FindFirstFile(filename
, &fd
);
1352 if (hFind
!= INVALID_HANDLE_VALUE
) {
1354 if (strcmp(fd
.cFileName
, ".") && strcmp(fd
.cFileName
, "..")) {
1355 sprintf(filename
, "%s\\%s", path
, fd
.cFileName
);
1356 DeleteFile(filename
);
1358 } while (FindNextFile(hFind
, &fd
));
1361 RemoveDirectory(path
);
1362 sprintf(path
, "%s\\ISC", commonPath
);
1363 RemoveDirectory(path
);
1367 CString
CBINDInstallDlg::DestDir(int destination
) {
1368 switch(destination
) {
1369 case FileData::TargetDir
:
1371 case FileData::BinDir
:
1373 case FileData::EtcDir
:
1375 case FileData::WinSystem
: