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