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