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