1
0
mirror of https://github.com/SoftEtherVPN/SoftEtherVPN.git synced 2025-04-03 18:00:08 +03:00
SoftEtherVPN/src/vpninstall/vpninstall.c
Davide Beatrici dbd4dd5ae7 Link to Windows libraries in CMake project, remove related #pragma directives
In addition to making the code cleaner, this also prevents potential issues due to #pragma directives being in headers.
2021-02-28 20:35:25 +01:00

1566 lines
29 KiB
C

// SoftEther VPN Source Code - Developer Edition Master Branch
// Cedar Communication Module
// vpninstall.c
// VPN Client Web Installer Bootstrap
#include <GlobalConst.h>
#include <winsock2.h>
#include <windows.h>
#include <wincrypt.h>
#include <wininet.h>
#include <shlobj.h>
#include <commctrl.h>
#include <Dbghelp.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>
#include <stdarg.h>
#include <time.h>
#include <Msiquery.h>
#include <Mayaqua/Mayaqua.h>
#include <Cedar/Cedar.h>
#include "vpninstall.h"
#include "resource.h"
static bool is_debug = true;
static LIST *string_table = NULL;
static VI_SETTING setting;
static bool sleep_before_exit = false;
static int skip = 0;
// Convert the URL to the file name
char *ViUrlToFileName(char *url)
{
UINT i, len;
char *ret = url;
bool b = true;
len = lstrlen(url);
for (i = 0;i < len;i++)
{
char c = url[i];
if (c == '?' || c == '#')
{
b = false;
}
if (b)
{
if (c == '/' || c == '\\')
{
if (lstrlen(url + i + 1) > 1)
{
ret = url + i + 1;
}
}
}
}
return ret;
}
// Check the signature of the EXE file, and displays a warning if dangerous
bool ViCheckExeSign(HWND hWnd, wchar_t *exew)
{
wchar_t tmp[2048];
bool danger = true;
wchar_t *warningMessage = _U(IDS_SIGN_WARNING+skip);
wchar_t *warningMessageTitle = _U(IDS_SIGN_WARNING_TITLE+skip);
// Validate arguments
if (hWnd == NULL || exew == NULL)
{
return false;
}
if (MsCheckFileDigitalSignatureW(hWnd, exew, &danger))
{
if (danger == false)
{
// Safe
return true;
}
else
{
wchar_t filename[MAX_PATH];
GetFileNameFromFilePathW(filename, sizeof(filename), exew);
// Show the message because there is potentially dangerous
swprintf(tmp, sizeof(tmp) / 2, warningMessage,
filename, filename, filename);
if (MessageBoxW(hWnd, tmp, warningMessageTitle,
MB_OKCANCEL | MB_DEFBUTTON2 | MB_ICONEXCLAMATION) == IDOK)
{
return true;
}
return false;
}
}
else
{
// Danger
return false;
}
}
// Start the installation process
void ViInstallProcessStart(HWND hWnd, VI_INSTALL_DLG *d)
{
wchar_t *exew;
bool ok;
char instdir[MAX_PATH];
char hamcore[MAX_PATH];
// Validate arguments
if (hWnd == NULL || d == NULL)
{
return;
}
ViGenerateVpnSMgrTempDirName(instdir, sizeof(instdir), ViGetSuitableArchForCpu()->Build);
ConbinePath(hamcore, sizeof(hamcore), instdir, "hamcore.se2");
exew = setting.DownloadedInstallerPathW;
d->NoClose = true;
Hide(hWnd, IDCANCEL);
SetPos(hWnd, P_PROGRESS, 100);
Hide(hWnd, P_PROGRESS);
Hide(hWnd, S_SIZEINFO);
SetText(hWnd, S_STATUS, _U(IDS_INSTALLSTART+skip));
ok = true;
if (setting.DownloadNotRequired == false)
{
if (setting.WebMode && ViCheckExeSign(hWnd, exew) == false)
{
// The digital signature is not reliable
ok = false;
}
else
{
// Installation
HANDLE hProcess;
SHELLEXECUTEINFOW info;
// Run
Zero(&info, sizeof(info));
info.cbSize = sizeof(info);
info.lpVerb = L"open";
info.lpFile = exew;
info.fMask = SEE_MASK_NOCLOSEPROCESS;
info.lpParameters = L"/HIDESTARTCOMMAND:1 /DISABLEAUTOIMPORT:1 /ISWEBINSTALLER:1";
info.nShow = SW_SHOWNORMAL;
if (ShellExecuteExW(&info) == false)
{
MsgBox(hWnd, MB_ICONSTOP, _U(IDS_INSTALLSTART_ERROR+skip));
ok = false;
}
else
{
hProcess = info.hProcess;
// Wait for the install process to complete
while (true)
{
if (WaitForSingleObject(hProcess, 50) != WAIT_TIMEOUT)
{
break;
}
DoEvents(hWnd);
}
CloseHandle(hProcess);
}
}
}
if (ok && d->WindowsShutdowning == false)
{
VI_SETTING_ARCH *a = ViGetSuitableArchForCpu();
wchar_t arg[MAX_PATH];
wchar_t exe[MAX_PATH];
char *arg1 = "/easy";
// Hide the screen
Hide(hWnd, 0);
if (setting.NormalMode)
{
arg1 = "/normal";
}
// (Just in case) start the VPN Client service
if (MsIsServiceRunning("vpnclient") == false)
{
MsStartService("vpnclient");
}
// Wait for that the service becomes available
SwWaitForVpnClientPortReady(0);
if (UniIsEmptyStr(setting.DownloadedSettingPathW) == false)
{
// Start a connection by importing the configuration file into the VPN Client
UniFormat(arg, sizeof(arg), L"%S \"%s\"", arg1, setting.DownloadedSettingPathW);
}
else
{
// Just start the Connection Manager
UniFormat(arg, sizeof(arg), L"%S", arg1);
}
// Get the installation state
ViLoadCurrentInstalledStatusForArch(a);
if (a->CurrentInstalled)
{
HANDLE h;
wchar_t filename[MAX_PATH];
StrToUni(filename, sizeof(filename), a->VpnCMgrExeFileName);
ConbinePathW(exe, sizeof(exe), a->CurrentInstalledPathW, filename);
// Start the Connection Manager
h = MsRunAsUserExW(exe, arg, false);
if (h != NULL)
{
if (UniIsEmptyStr(setting.DownloadedSettingPathW) == false)
{
sleep_before_exit = true;
}
CloseHandle(h);
}
}
}
d->NoClose = false;
Close(hWnd);
}
// End User License Agreement dialog
UINT ViEulaDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
{
wchar_t *text = (wchar_t *)param;
// Validate arguments
if (hWnd == NULL)
{
return 0;
}
switch (msg)
{
case WM_INITDIALOG:
SetText(hWnd, 0, _U(IDS_DLG_TITLE+skip));
SetText(hWnd, S_EULA_NOTICE1, _U(IDS_EULA_NOTICE1+skip));
SetText(hWnd, S_BOLD, _U(IDS_EULA_NOTICE2+skip));
SetText(hWnd, S_EULA_NOTICE3, _U(IDS_EULA_NOTICE3+skip));
SetText(hWnd, IDOK, _U(IDS_EULA_AGREE+skip));
SetText(hWnd, IDCANCEL, _U(IDS_EULA_DISAGREE+skip));
DlgFont(hWnd, S_BOLD, 0, true);
SetText(hWnd, E_EULA, text);
Focus(hWnd, E_EULA);
SendMsg(hWnd, E_EULA, EM_SETSEL, 0, 0);
Center(hWnd);
break;
case WM_COMMAND:
switch (wParam)
{
case IDOK:
EndDialog(hWnd, 1);
break;
case IDCANCEL:
Close(hWnd);
break;
}
break;
case WM_CLOSE:
EndDialog(hWnd, 0);
break;
}
return 0;
}
// Display the End User License Agreement
bool ViEulaDlg(HWND hWnd, wchar_t *text)
{
// Validate arguments
if (text == NULL)
{
return false;
}
if (Dialog(hWnd, D_EULA, ViEulaDlgProc, text) == 0)
{
return false;
}
return true;
}
// Extract the license agreement from the EXE file
wchar_t *ViExtractEula(char *exe)
{
BUF *b;
UINT tmp_size;
char *tmp;
wchar_t *ret;
// Validate arguments
if (exe == NULL)
{
return false;
}
b = ViExtractResource(exe, RT_RCDATA, "LICENSE");
if (b == NULL)
{
return NULL;
}
tmp_size = b->Size + 1;
tmp = ZeroMalloc(tmp_size);
Copy(tmp, b->Buf, b->Size);
FreeBuf(b);
ret = CopyStrToUni(tmp);
Free(tmp);
return ret;
}
// Extract the Cabinet file from the EXE file
bool ViExtractCabinetFile(char *exe, char *cab)
{
BUF *b;
// Validate arguments
if (exe == NULL || cab == NULL)
{
return false;
}
b = ViExtractResource(exe, RT_RCDATA, "CABINET");
if (b == NULL)
{
return false;
}
if (DumpBuf(b, cab) == false)
{
FreeBuf(b);
return false;
}
FreeBuf(b);
return true;
}
// Extract the resource from the EXE file
BUF *ViExtractResource(char *exe, char *type, char *name)
{
HINSTANCE h;
HRSRC hr;
HGLOBAL hg;
UINT size;
void *data;
BUF *buf;
// Validate arguments
if (exe == NULL || type == NULL || name == NULL)
{
return NULL;
}
h = LoadLibraryExA(exe, NULL, LOAD_LIBRARY_AS_DATAFILE);
if (h == NULL)
{
return NULL;
}
hr = FindResourceA(h, name, type);
if (hr == NULL)
{
FreeLibrary(h);
return NULL;
}
hg = LoadResource(h, hr);
if (hg == NULL)
{
FreeLibrary(h);
return NULL;
}
size = SizeofResource(h, hr);
data = (void *)LockResource(hg);
buf = NewBuf();
WriteBuf(buf, data, size);
FreeResource(hg);
FreeLibrary(h);
SeekBuf(buf, 0, 0);
return buf;
}
// Open the file
VI_FILE *ViOpenFile(char *path)
{
VI_FILE *f;
// Validate arguments
if (path == NULL)
{
return NULL;
}
if (ViIsInternetFile(path))
{
HINTERNET hHttpFile;
HINTERNET hInternet = InternetOpenA(DEFAULT_USER_AGENT,
INTERNET_OPEN_TYPE_PRECONFIG,
NULL, NULL, 0);
UINT size;
UINT sizesize;
if (hInternet == NULL)
{
return NULL;
}
hHttpFile = InternetOpenUrlA(hInternet, path, NULL, 0,
INTERNET_FLAG_NO_CACHE_WRITE | INTERNET_FLAG_RELOAD, 0);
if (hHttpFile == NULL)
{
InternetCloseHandle(hInternet);
return NULL;
}
size = 0;
sizesize = sizeof(size);
if (StartWith(path, "ftp://"))
{
// ftp
DWORD high = 0;
size = FtpGetFileSize(hHttpFile, &high);
}
else
{
UINT errorcode = 0;
UINT errorcode_size = sizeof(errorcode);
// http
if (HttpQueryInfo(hHttpFile, HTTP_QUERY_CONTENT_LENGTH | HTTP_QUERY_FLAG_NUMBER,
&size, &sizesize, NULL) == false)
{
size = 0;
}
if (HttpQueryInfo(hHttpFile, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER,
&errorcode, &errorcode_size, NULL) == false ||
(errorcode / 100) != 2)
{
// HTTP getting error
InternetCloseHandle(hInternet);
InternetCloseHandle(hHttpFile);
return NULL;
}
}
f = ZeroMalloc(sizeof(VI_FILE));
f->InternetFile = true;
f->hInternet = hInternet;
f->hHttpFile = hHttpFile;
f->FileSize = size;
return f;
}
else
{
IO *io;
char fullpath[MAX_PATH];
char exedir[MAX_PATH];
GetExeDir(exedir, sizeof(exedir));
ConbinePath(fullpath, sizeof(fullpath), exedir, path);
io = FileOpen(fullpath, false);
if (io == NULL)
{
return NULL;
}
f = ZeroMalloc(sizeof(VI_FILE));
f->InternetFile = false;
f->FileSize = FileSize(io);
f->io = io;
return f;
}
}
// Get the file size
UINT ViGetFileSize(VI_FILE *f)
{
// Validate arguments
if (f == NULL)
{
return 0;
}
return f->FileSize;
}
// Read from the file
UINT ViReadFile(VI_FILE *f, void *buf, UINT size)
{
// Validate arguments
if (f == NULL || buf == NULL)
{
return INFINITE;
}
if (f->InternetFile == false)
{
UINT readsize = MIN(size, f->FileSize - f->IoReadFileSize);
bool ret;
if (readsize == 0)
{
return 0;
}
ret = FileRead(f->io, buf, readsize);
if (ret == false)
{
return INFINITE;
}
f->IoReadFileSize += readsize;
return readsize;
}
else
{
UINT readsize = 0;
if (InternetReadFile(f->hHttpFile, buf, size, &readsize) == false)
{
return INFINITE;
}
return readsize;
}
}
// Close the file
void ViCloseFile(VI_FILE *f)
{
// Validate arguments
if (f == NULL)
{
return;
}
if (f->InternetFile == false)
{
FileClose(f->io);
}
else
{
InternetCloseHandle(f->hHttpFile);
InternetCloseHandle(f->hInternet);
}
Free(f);
}
// Determine whether the specified file name is the file on the Internet
bool ViIsInternetFile(char *path)
{
// Validate arguments
if (path == NULL)
{
return false;
}
if (StartWith(path, "http://") || StartWith(path, "https://") || StartWith(path, "ftp://"))
{
return true;
}
return false;
}
// Installer dialog initialization
void ViInstallDlgOnInit(HWND hWnd, VI_INSTALL_DLG *d)
{
// Validate arguments
if (hWnd == NULL || d == NULL)
{
return;
}
d->hWnd = hWnd;
SetIcon(hWnd, 0, IDI_MAIN);
SetText(hWnd, 0, _U(IDS_DLG_TITLE+skip));
SetText(hWnd, S_TITLE, _U(IDS_DLG_TITLE+skip));
SetText(hWnd, S_STATUS, _U(IDS_INSTALL_DLG__STATUS_INIT+skip));
SetText(hWnd, IDCANCEL, _U(IDS_INSTALL_CANCEL+skip));
DlgFont(hWnd, S_TITLE+skip, 12, true);
SetRange(hWnd, P_PROGRESS, 0, 100);
SetPos(hWnd, P_PROGRESS, 0);
SetTimer(hWnd, 1, 22, NULL);
}
// Start the download thread
void ViDownloadThreadStart(VI_INSTALL_DLG *d)
{
// Validate arguments
if (d == NULL)
{
return;
}
d->DownloadStarted = true;
d->DownloadThread = NewThread(ViDownloadThread, d);
}
// Stop the download thread
void ViDownloadThreadStop(VI_INSTALL_DLG *d)
{
// Validate arguments
if (d == NULL)
{
return;
}
if (d->DownloadStarted == false)
{
return;
}
d->DownloadStarted = false;
d->Halt = true;
while (true)
{
if (WaitThread(d->DownloadThread, 50))
{
break;
}
DoEvents(NULL);
}
ReleaseThread(d->DownloadThread);
}
// Download thread
void ViDownloadThread(THREAD *thread, void *param)
{
VI_INSTALL_DLG *d;
VI_SETTING_ARCH *a;
HWND hWnd;
UINT num_files = 2;
VI_DOWNLOAD_FILE files[2];
VI_DOWNLOAD_FILE *f;
UINT i;
// Validate arguments
if (thread == NULL || param == NULL)
{
return;
}
d = (VI_INSTALL_DLG *)param;
hWnd = d->hWnd;
Zero(files, sizeof(files));
a = ViGetSuitableArchForCpu();
// File body
f = &files[0];
StrCpy(f->SrcPath, sizeof(f->SrcPath), a->Path);
// Configuration file
if (IsEmptyStr(setting.SettingPath) == false)
{
f = &files[1];
StrCpy(f->SrcPath, sizeof(f->SrcPath), setting.SettingPath);
}
else
{
// No configuration file
num_files = 1;
}
for (i = 0;i < num_files;i++)
{
bool b = true;
if (i == 0 && setting.DownloadNotRequired)
{
b = false;
}
if (b)
{
wchar_t tmp[MAX_SIZE];
IO *dest = NULL;
VI_FILE *down;
UINT ret;
UINT totalsize;
UINT currentsize;
wchar_t filename_w[MAX_PATH];
f = &files[i];
GetFileNameFromFilePath(f->FileName, sizeof(f->FileName), f->SrcPath);
MakeSafeFileName(f->FileName, sizeof(f->FileName), f->FileName);
StrToUni(filename_w, sizeof(filename_w), f->FileName);
ConbinePathW(f->DestPathW, sizeof(f->DestPathW), MsGetMyTempDirW(), filename_w);
ViInstallDlgSetPos(hWnd, 0);
UniFormat(tmp, sizeof(tmp), _U(IDS_DOWNLOADSTART+skip), f->FileName);
ViInstallDlgSetText(d, hWnd, S_STATUS, tmp);
down = ViOpenFile(f->SrcPath);
if (down == NULL)
{
MsgBoxEx(hWnd, MB_ICONSTOP, _U(IDS_DOWNLOAD_ERROR+skip), f->FileName);
ViInstallDlgCancel(hWnd);
return;
}
dest = FileCreateW(f->DestPathW);
if (dest == NULL)
{
MsgBoxEx(hWnd, MB_ICONSTOP, _U(IDS_TEMP_ERROR+skip), f->DestPathW);
ViCloseFile(down);
ViInstallDlgCancel(hWnd);
return;
}
totalsize = ViGetFileSize(down);
currentsize = 0;
UniFormat(tmp, sizeof(tmp), _U(IDS_DOWNLOADING3+skip), f->FileName);
ViInstallDlgSetText(d, hWnd, S_STATUS, tmp);
while (true)
{
UINT pos = 0;
if (d->Halt)
{
// User cancel
FileClose(dest);
ViCloseFile(down);
return;
}
UniFormat(tmp, sizeof(tmp), _U(IDS_DOWNLOADING3+skip), f->FileName);
ViInstallDlgSetText(d, hWnd, IDS_DOWNLOADING3+skip, tmp);
ret = ViReadFile(down, d->Buf, d->BufSize);
if (ret == INFINITE)
{
// Communication error
MsgBoxEx(hWnd, MB_ICONSTOP, _U(IDS_DOWNLOAD_ERROR+skip), f->FileName);
FileClose(dest);
ViCloseFile(down);
ViInstallDlgCancel(hWnd);
return;
}
// Draw progress
currentsize += ret;
if (totalsize != 0)
{
UniFormat(tmp, sizeof(tmp), _U(IDS_DOWNLOADING+skip),
((float)totalsize) / 1024.0f / 1024.0f,
((float)currentsize) / 1024.0f / 1024.0f);
pos = (UINT)(((float)currentsize) * 100.0f / ((float)totalsize));
}
else
{
UniFormat(tmp, sizeof(tmp), _U(IDS_DOWNLOADING2+skip),
((float)currentsize) / 1024.0f / 1024.0f);
pos = (UINT)(((float)currentsize) * 100.0f / (1024.0f * 1024.0f * 10.0f));
}
ViInstallDlgSetText(d, hWnd, S_SIZEINFO, tmp);
ViInstallDlgSetPos(hWnd, pos);
if (ret == 0)
{
// Download Complete
break;
}
else
{
FileWrite(dest, d->Buf, ret);
}
}
ViCloseFile(down);
FileClose(dest);
}
}
UniStrCpy(setting.DownloadedInstallerPathW, sizeof(setting.DownloadedInstallerPathW),
files[0].DestPathW);
if (num_files >= 2)
{
UniStrCpy(setting.DownloadedSettingPathW, sizeof(setting.DownloadedSettingPathW),
files[1].DestPathW);
}
PostMessageA(hWnd, WM_VI_DOWNLOAD_FINISHED, 0, 0);
}
// Operation of the progress bar
void ViInstallDlgSetPos(HWND hWnd, UINT pos)
{
PostMessage(hWnd, WM_VI_SETPOS, 0, pos);
}
// Set the text
void ViInstallDlgSetText(VI_INSTALL_DLG *d, HWND hWnd, UINT id, wchar_t *text)
{
DWORD value = 0;
// Validate arguments
if (d == NULL)
{
return;
}
if (d->Halt)
{
return;
}
SendMessageTimeout(hWnd, WM_VI_SETTEXT, id, (LPARAM)text, SMTO_BLOCK, 200, &value);
}
// Cancel
void ViInstallDlgCancel(HWND hWnd)
{
PostMessageA(hWnd, WM_VI_CANCEL, 0, 0);
}
// Installer operation start
void ViInstallDlgOnStart(HWND hWnd, VI_INSTALL_DLG *d)
{
// Validate arguments
if (hWnd == NULL || d == NULL)
{
return;
}
// Start the download thread
ViDownloadThreadStart(d);
}
// Cancel the installation
void ViInstallDlgOnClose(HWND hWnd, VI_INSTALL_DLG *d)
{
// Validate arguments
if (hWnd == NULL || d == NULL)
{
return;
}
if (d->DialogCanceling)
{
return;
}
if (d->NoClose)
{
return;
}
d->DialogCanceling = true;
// Disable the cancel button
Disable(hWnd, IDCANCEL);
// Stop the download thread if it runs
ViDownloadThreadStop(d);
// Exit the dialog
EndDialog(hWnd, 0);
}
// Installer procedure
UINT ViInstallDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, void *param)
{
VI_INSTALL_DLG *d = (VI_INSTALL_DLG *)param;
UINT pos;
wchar_t *text;
// Validate arguments
if (hWnd == NULL)
{
return 0;
}
switch (msg)
{
case WM_INITDIALOG:
ViInstallDlgOnInit(hWnd, param);
break;
case WM_TIMER:
switch (wParam)
{
case 1:
KillTimer(hWnd, 1);
ViInstallDlgOnStart(hWnd, d);
break;
}
break;
case WM_VI_SETPOS:
// Setting the progress bar
pos = (UINT)lParam;
SetPos(hWnd, P_PROGRESS, MAKESURE(pos, 0, 100));
break;
case WM_VI_SETTEXT:
// Set the string
text = (wchar_t *)lParam;
SetText(hWnd, (UINT)wParam, text);
break;
case WM_VI_CANCEL:
// There was a cancellation from the thread side
ViInstallDlgOnClose(hWnd, d);
break;
case WM_VI_DOWNLOAD_FINISHED:
// Download Complete
ViInstallProcessStart(hWnd, d);
break;
case WM_COMMAND:
switch (wParam)
{
case IDCANCEL:
ViInstallDlgOnClose(hWnd, d);
break;
}
break;
case WM_QUERYENDSESSION:
d->WindowsShutdowning = true;
break;
case WM_CLOSE:
break;
}
return 0;
}
// Show the dialog
void ViInstallDlg()
{
VI_INSTALL_DLG d;
Zero(&d, sizeof(d));
d.BufSize = 65535;
d.Buf = Malloc(d.BufSize);
Dialog(NULL, D_INSTALL, ViInstallDlgProc, &d);
Free(d.Buf);
}
// Read the inf file from the buffer
bool ViLoadInfFromBuf(VI_SETTING *set, BUF *buf)
{
bool ret;
if (set == NULL || buf == NULL)
{
return false;
}
Zero(set, sizeof(VI_SETTING));
SeekBuf(buf, 0, 0);
while (true)
{
char *tmp = CfgReadNextLine(buf);
TOKEN_LIST *tokens;
if (tmp == NULL)
{
break;
}
tokens = ParseToken(tmp, " \t");
if (tokens != NULL)
{
if (tokens->NumTokens >= 2)
{
if (StartWith(tokens->Token[0], "#") == false
|| StartWith(tokens->Token[0], "//") == false)
{
char *name, *value;
name = tokens->Token[0];
value = tokens->Token[1];
if (StrCmpi(name, "VpnInstallBuild") == 0)
{
set->VpnInstallBuild = ToInt(value);
}
else if (StrCmpi(name, "NormalMode") == 0)
{
set->NormalMode = ToBool(value);
}
else if (StrCmpi(name, "VpnSettingPath") == 0)
{
StrCpy(set->SettingPath, sizeof(set->SettingPath), value);
}
else if (StrCmpi(name, "VpnClientBuild") == 0)
{
set->x86.Build = ToInt(value);
}
else if (StrCmpi(name, "VpnClientPath") == 0)
{
StrCpy(set->x86.Path, sizeof(set->x86.Path), value);
}
}
}
FreeToken(tokens);
}
Free(tmp);
}
ret = false;
StrCpy(set->x86.VpnCMgrExeFileName, sizeof(set->x86.VpnCMgrExeFileName), (MsIsX64() ? "vpncmgr_x64.exe" : "vpncmgr.exe"));
if (set->VpnInstallBuild != 0)
{
if (set->x86.Build != 0 && IsEmptyStr(set->x86.Path) == false)
{
set->x86.Supported = true;
ret = true;
}
}
return ret;
}
// Read the inf file
bool ViLoadInf(VI_SETTING *set, char *filename)
{
BUF *b;
bool ret = false;
// Validate arguments
if (set == NULL || filename == NULL)
{
return false;
}
b = ReadDump(filename);
if (b == NULL)
{
return false;
}
ret = ViLoadInfFromBuf(set, b);
FreeBuf(b);
return ret;
}
// Get the product information from the Msi
bool ViMsiGetProductInfo(char *product_code, char *name, char *buf, UINT size)
{
UINT ret;
char tmp[MAX_SIZE];
DWORD sz;
// Validate arguments
if (product_code == NULL || name == NULL || buf == NULL)
{
return false;
}
sz = sizeof(tmp);
ret = MsiGetProductInfoA(product_code, name, tmp, &sz);
if (ret != ERROR_SUCCESS)
{
return false;
}
StrCpy(buf, size, tmp);
return true;
}
// Extract the build number from the version string
UINT ViVersionStrToBuild(char *str)
{
TOKEN_LIST *t;
UINT ret;
// Validate arguments
if (str == NULL)
{
return 0;
}
t = ParseToken(str, ".");
if (t == NULL)
{
return 0;
}
ret = 0;
if (t->NumTokens == 3)
{
ret = ToInt(t->Token[2]);
}
FreeToken(t);
return ret;
}
// Get the current installation state for the given architecture
void ViLoadCurrentInstalledStatusForArch(VI_SETTING_ARCH *a)
{
char tmp[MAX_SIZE];
UINT build;
wchar_t *dir;
// Validate arguments
if (a == NULL)
{
return;
}
if (a->Supported == false)
{
// Unsupported
return;
}
// Read from the registry
Format(tmp, sizeof(tmp), "%s\\%s", SW_REG_KEY, "vpnclient");
build = MsRegReadIntEx2(REG_LOCAL_MACHINE, tmp, "InstalledBuild", false, true);
dir = MsRegReadStrEx2W(REG_LOCAL_MACHINE, tmp, "InstalledDir", false, true);
if (build == 0 || UniIsEmptyStr(dir))
{
// Not installed
a->CurrentInstalled = false;
}
else
{
// Installed
a->CurrentInstalled = true;
a->CurrentInstalledBuild = build;
UniStrCpy(a->CurrentInstalledPathW, sizeof(a->CurrentInstalledPathW), dir);
}
Free(dir);
}
// Get the best architecture for the current CPU
VI_SETTING_ARCH *ViGetSuitableArchForCpu()
{
return &setting.x86;
}
// Get the current installation state
void ViLoadCurrentInstalledStates()
{
ViLoadCurrentInstalledStatusForArch(&setting.x86);
}
// Main process
void ViMain()
{
char tmp[MAX_PATH];
UINT ostype = GetOsInfo()->OsType;
VI_SETTING_ARCH *suitable;
TOKEN_LIST *t;
UINT i;
if (OS_IS_WINDOWS_NT(ostype) == false ||
GET_KETA(ostype, 100) <= 1)
{
// The OS is too old
MsgBox(NULL, MB_ICONEXCLAMATION, _U(IDS_BAD_OS+skip));
return;
}
Zero(&setting, sizeof(setting));
// Read the inf file
Format(tmp, sizeof(tmp), "%s\\%s", MsGetExeDirName(), VI_INF_FILENAME);
if (ViLoadInf(&setting, tmp) == false)
{
// Failure
MsgBoxEx(NULL, MB_ICONSTOP, _U(IDS_INF_LOAD_FAILED+skip), VI_INF_FILENAME);
return;
}
ViSetSkip();
// Parse the command line options
t = GetCommandLineToken();
for (i = 0;i < t->NumTokens;i++)
{
char *s = t->Token[i];
if (IsEmptyStr(s) == false)
{
if (StartWith(s, "/") || StartWith(s, "-"))
{
if (StrCmpi(&s[1], "web") == 0)
{
setting.WebMode = true;
}
}
else
{
StrCpy(setting.SettingPath, sizeof(setting.SettingPath), s);
}
}
}
FreeToken(t);
suitable = ViGetSuitableArchForCpu();
// Security check
if (setting.WebMode)
{
bool ok = true;
if (ViIsInternetFile(suitable->Path) == false)
{
ok = false;
}
if (IsEmptyStr(setting.SettingPath) == false)
{
if (ViIsInternetFile(setting.SettingPath) == false)
{
ok = false;
}
}
if (ok == false)
{
// Security breach
MsgBox(NULL, MB_ICONEXCLAMATION, _U(IDS_SECURITY_ERROR+skip));
return;
}
}
// Get the current installation state
ViLoadCurrentInstalledStates();
if (suitable->Supported == false)
{
// This CPU isn't supported
MsgBox(NULL, MB_ICONEXCLAMATION, _U(IDS_CPU_NOT_SUPPORTED+skip));
return;
}
if (suitable->CurrentInstalled && suitable->Build <= suitable->CurrentInstalledBuild)
{
// Do not download client software since it has already been installed
setting.DownloadNotRequired = true;
}
// Show the dialog
ViInstallDlg();
}
// Generate the temporary directory name for vpnsmgr
void ViGenerateVpnSMgrTempDirName(char *name, UINT size, UINT build)
{
// Validate arguments
if (name == NULL)
{
return;
}
Format(name, size, "%s\\px_" GC_SW_SOFTETHER_PREFIX "vpnsmgr_%u", MsGetTempDir(), build);
}
// Compare the string resources
int ViCompareString(void *p1, void *p2)
{
VI_STRING *s1, *s2;
if (p1 == NULL || p2 == NULL)
{
return 0;
}
s1 = *(VI_STRING **)p1;
s2 = *(VI_STRING **)p2;
if (s1 == NULL || s2 == NULL)
{
return 0;
}
if (s1->Id > s2->Id)
{
return 1;
}
else if (s1->Id < s2->Id)
{
return -1;
}
return 0;
}
// Reading a string resource
wchar_t *ViLoadString(HINSTANCE hInst, UINT id)
{
wchar_t *ret = NULL;
if (OS_IS_WINDOWS_9X(GetOsInfo()->OsType))
{
char *a = ViLoadStringA(hInst, id);
if (a != NULL)
{
ret = CopyStrToUni(a);
Free(a);
}
}
else
{
UINT tmp_size = 60000;
wchar_t *tmp = Malloc(tmp_size);
if (LoadStringW(hInst, id, tmp, tmp_size) != 0)
{
ret = CopyUniStr(tmp);
}
Free(tmp);
}
return ret;
}
char *ViLoadStringA(HINSTANCE hInst, UINT id)
{
UINT tmp_size = 60000;
char *tmp = Malloc(tmp_size);
char *ret = NULL;
if (LoadStringA(hInst, id, tmp, tmp_size) != 0)
{
ret = CopyStr(tmp);
}
Free(tmp);
return ret;
}
// Acquisition of string
wchar_t *ViGetString(UINT id)
{
VI_STRING t, *s;
wchar_t *ret = NULL;
Zero(&t, sizeof(t));
t.Id = id;
LockList(string_table);
{
s = Search(string_table, &t);
if (s != NULL)
{
ret = s->String;
}
}
UnlockList(string_table);
return ret;
}
char *ViGetStringA(UINT id)
{
VI_STRING t, *s;
char *ret = NULL;
Zero(&t, sizeof(t));
t.Id = id;
LockList(string_table);
{
s = Search(string_table, &t);
if (s != NULL)
{
ret = s->StringA;
}
}
UnlockList(string_table);
return ret;
}
// Calculate the difference between the the current language configuration and the base of the string table
void ViSetSkip()
{
skip = 0;
if (MsIsCurrentUserLocaleIdJapanese() == false)
{
skip = MESSAGE_OFFSET_EN - MESSAGE_OFFSET_JP;
}
}
// Read the string table
void ViLoadStringTables()
{
UINT i, n;
HINSTANCE hInst = GetModuleHandle(NULL);
string_table = NewList(ViCompareString);
n = 0;
for (i = 1;;i++)
{
wchar_t *str = ViLoadString(hInst, i);
if (str != NULL)
{
VI_STRING *s;
n = 0;
s = ZeroMalloc(sizeof(VI_STRING));
s->Id = i;
s->String = str;
s->StringA = CopyUniToStr(str);
Insert(string_table, s);
}
else
{
n++;
if (n >= 1500)
{
break;
}
}
}
}
// Release the string table
void ViFreeStringTables()
{
UINT i;
if (string_table == NULL)
{
return;
}
for (i = 0;i < LIST_NUM(string_table);i++)
{
VI_STRING *s = LIST_DATA(string_table, i);
Free(s->String);
Free(s->StringA);
Free(s);
}
ReleaseList(string_table);
string_table = NULL;
}
// WinMain function
int PASCAL WinMain(HINSTANCE hInst, HINSTANCE hPrev, char *CmdLine, int CmdShow)
{
INSTANCE *instance;
InitProcessCallOnce();
#if defined(_DEBUG) || defined(DEBUG) // In VC++ compilers, the macro is "_DEBUG", not "DEBUG".
is_debug = true;
#else
is_debug = false;
#endif
MayaquaMinimalMode();
// If set memcheck = true, the program will be vitally slow since it will log all malloc() / realloc() / free() calls to find the cause of memory leak.
// For normal debug we set memcheck = false.
// Please set memcheck = true if you want to test the cause of memory leaks.
InitMayaqua(false, is_debug, 0, NULL);
InitCedar();
ViSetSkip();
ViLoadStringTables();
InitWinUi(_U(IDS_TITLE+skip), _A(IDS_FONT+skip), ToInt(_A(IDS_FONT_SIZE+skip)));
instance = NewSingleInstance(VI_INSTANCE_NAME);
if (instance == NULL)
{
MsgBox(NULL, MB_ICONINFORMATION, _U(IDS_INSTANCE_EXISTS+skip));
}
else
{
ViMain();
FreeSingleInstance(instance);
if (sleep_before_exit)
{
SleepThread(60 * 1000);
}
}
FreeWinUi();
ViFreeStringTables();
FreeCedar();
FreeMayaqua();
return 0;
}