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