mirror of https://github.com/OpenVPN/openvpn-gui
692 lines
20 KiB
C
692 lines
20 KiB
C
/*
|
|
* OpenVPN-GUI -- A Windows GUI for OpenVPN.
|
|
*
|
|
* Copyright (C) 2004 Mathias Sundman <mathias@nilings.se>
|
|
* 2010 Heiko Hund <heikoh@users.sf.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program (see the file COPYING included with this
|
|
* distribution); if not, write to the Free Software Foundation, Inc.,
|
|
* 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Parts of this sourcefile is taken from openvpnserv.c from the
|
|
* OpenVPN source, with approval from the author, James Yonan
|
|
* <jim@yonan.net>.
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <tchar.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <process.h>
|
|
#include <richedit.h>
|
|
|
|
#include "config.h"
|
|
#include "tray.h"
|
|
#include "main.h"
|
|
#include "openvpn.h"
|
|
#include "openvpn_monitor_process.h"
|
|
#include "openvpn_config.h"
|
|
#include "openvpn-gui-res.h"
|
|
#include "options.h"
|
|
#include "scripts.h"
|
|
#include "viewlog.h"
|
|
#include "proxy.h"
|
|
#include "passphrase.h"
|
|
#include "localization.h"
|
|
|
|
extern options_t o;
|
|
|
|
/*
|
|
* Creates a unique exit_event name based on the
|
|
* config file number.
|
|
*/
|
|
static BOOL
|
|
CreateExitEvent(int config)
|
|
{
|
|
_sntprintf_0(o.conn[config].exit_event_name, _T("openvpngui_exit_event_%d"), config);
|
|
o.conn[config].exit_event = CreateEvent(NULL, TRUE, FALSE, o.conn[config].exit_event_name);
|
|
if (o.conn[config].exit_event == NULL) {
|
|
/* error creating exit event */
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_EVENT, o.conn[config].exit_event_name);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Set priority based on the registry or cmd-line value
|
|
*/
|
|
int SetProcessPriority(DWORD *priority)
|
|
{
|
|
|
|
/* set process priority */
|
|
*priority = NORMAL_PRIORITY_CLASS;
|
|
if (!_tcscmp(o.priority_string, _T("IDLE_PRIORITY_CLASS")))
|
|
*priority = IDLE_PRIORITY_CLASS;
|
|
else if (!_tcscmp(o.priority_string, _T("BELOW_NORMAL_PRIORITY_CLASS")))
|
|
*priority = BELOW_NORMAL_PRIORITY_CLASS;
|
|
else if (!_tcscmp(o.priority_string, _T("NORMAL_PRIORITY_CLASS")))
|
|
*priority = NORMAL_PRIORITY_CLASS;
|
|
else if (!_tcscmp(o.priority_string, _T("ABOVE_NORMAL_PRIORITY_CLASS")))
|
|
*priority = ABOVE_NORMAL_PRIORITY_CLASS;
|
|
else if (!_tcscmp(o.priority_string, _T("HIGH_PRIORITY_CLASS")))
|
|
*priority = HIGH_PRIORITY_CLASS;
|
|
else
|
|
{
|
|
/* unknown priority */
|
|
ShowLocalizedMsg(IDS_ERR_UNKNOWN_PRIORITY, o.priority_string);
|
|
return (false);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
|
|
static BOOL
|
|
GetPipeHandles(PHANDLE phInputRead, PHANDLE phInputWrite,
|
|
PHANDLE phOutputRead, PHANDLE phOutputWrite)
|
|
{
|
|
HANDLE hProc = GetCurrentProcess();
|
|
HANDLE hOutputReadTmp, hInputWriteTmp;
|
|
SECURITY_DESCRIPTOR sd;
|
|
SECURITY_ATTRIBUTES sa;
|
|
|
|
CLEAR(sa);
|
|
CLEAR(sd);
|
|
|
|
/* Make security attributes for the pipes so they can be inherited */
|
|
sa.nLength = sizeof(sa);
|
|
sa.lpSecurityDescriptor = &sd;
|
|
sa.bInheritHandle = TRUE;
|
|
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) {
|
|
ShowLocalizedMsg(IDS_ERR_INIT_SEC_DESC);
|
|
return FALSE;
|
|
}
|
|
if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)) {
|
|
ShowLocalizedMsg(IDS_ERR_SET_SEC_DESC_ACL);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Create the stdin pipe with uninheritable write end */
|
|
if (!CreatePipe(phInputRead, &hInputWriteTmp, &sa, 0)) {
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_PIPE_IN_READ);
|
|
return FALSE;
|
|
}
|
|
if (!DuplicateHandle(hProc, hInputWriteTmp, hProc, phInputWrite, 0, FALSE,
|
|
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
|
|
ShowLocalizedMsg(IDS_ERR_DUP_HANDLE_IN_WRITE);
|
|
CloseHandle(*phInputRead);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Create the stdout pipe with uninheritable read end */
|
|
if (!CreatePipe(&hOutputReadTmp, phOutputWrite, &sa, 0)) {
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_PIPE_OUTPUT);
|
|
CloseHandle(*phInputRead);
|
|
CloseHandle(*phInputWrite);
|
|
return FALSE;
|
|
}
|
|
if (!DuplicateHandle(hProc, hOutputReadTmp, hProc, phOutputRead, 0, FALSE,
|
|
DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) {
|
|
ShowLocalizedMsg(IDS_ERR_DUP_HANDLE_OUT_READ);
|
|
CloseHandle(*phInputRead);
|
|
CloseHandle(*phInputWrite);
|
|
CloseHandle(*phOutputWrite);
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Launch an OpenVPN process
|
|
*/
|
|
int StartOpenVPN(int config)
|
|
{
|
|
HANDLE hOutputRead = NULL;
|
|
HANDLE hOutputWrite = NULL;
|
|
HANDLE hInputRead = NULL;
|
|
HANDLE hInputWrite = NULL;
|
|
HANDLE hErrorWrite = NULL;
|
|
|
|
HANDLE hThread;
|
|
DWORD IDThread;
|
|
DWORD priority;
|
|
STARTUPINFO start_info;
|
|
PROCESS_INFORMATION proc_info;
|
|
TCHAR command_line[256];
|
|
TCHAR proxy_string[100];
|
|
|
|
CLEAR (start_info);
|
|
CLEAR (proc_info);
|
|
|
|
/* Warn if "log" or "log-append" option is found in config file */
|
|
if ((ConfigFileOptionExist(config, "log ")) ||
|
|
(ConfigFileOptionExist(config, "log-append ")))
|
|
{
|
|
if (MessageBox(NULL, LoadLocalizedString(IDS_ERR_OPTION_LOG_IN_CONFIG), _T(PACKAGE_NAME), MB_YESNO | MB_DEFBUTTON2 | MB_ICONWARNING) != IDYES)
|
|
return(false);
|
|
}
|
|
|
|
/* Clear connection unique vars */
|
|
o.conn[config].failed_psw = 0;
|
|
CLEAR (o.conn[config].ip);
|
|
|
|
/* Create our exit event */
|
|
if (!CreateExitEvent(config))
|
|
return(false);
|
|
|
|
/* set process priority */
|
|
if (!SetProcessPriority(&priority))
|
|
goto failed;
|
|
|
|
/* Check that log append flag has a valid value */
|
|
if ((o.append_string[0] != '0') && (o.append_string[0] != '1'))
|
|
{
|
|
/* append_log must be 0 or 1 */
|
|
ShowLocalizedMsg(IDS_ERR_LOG_APPEND_BOOL, o.append_string);
|
|
goto failed;
|
|
}
|
|
|
|
/* construct proxy string to append to command line */
|
|
ConstructProxyCmdLine(proxy_string, _tsizeof(proxy_string));
|
|
|
|
/* construct command line */
|
|
_sntprintf_0(command_line, _T("openvpn --service %s 0 --config \"%s\" %s"),
|
|
o.conn[config].exit_event_name,
|
|
o.conn[config].config_file,
|
|
proxy_string);
|
|
|
|
if (!GetPipeHandles(&hInputRead, &hInputWrite, &hOutputRead, &hOutputWrite))
|
|
return false;
|
|
|
|
// Create a duplicate of the output write handle for the std error
|
|
// write handle. This is necessary in case the child application
|
|
// closes one of its std output handles.
|
|
if (!DuplicateHandle(GetCurrentProcess(),hOutputWrite,
|
|
GetCurrentProcess(),&hErrorWrite,0,
|
|
TRUE,DUPLICATE_SAME_ACCESS))
|
|
{
|
|
/* DuplicateHandle failed. */
|
|
ShowLocalizedMsg(IDS_ERR_DUP_HANDLE_ERR_WRITE);
|
|
goto failed;
|
|
}
|
|
|
|
|
|
/* fill in STARTUPINFO struct */
|
|
GetStartupInfo(&start_info);
|
|
start_info.cb = sizeof(start_info);
|
|
start_info.dwFlags = STARTF_USESTDHANDLES;
|
|
start_info.hStdInput = hInputRead;
|
|
start_info.hStdOutput = hOutputWrite;
|
|
start_info.hStdError = hErrorWrite;
|
|
|
|
/* Run Pre-connect script */
|
|
RunPreconnectScript(config);
|
|
|
|
/* create an OpenVPN process for one config file */
|
|
if (!CreateProcess(o.exe_path,
|
|
command_line,
|
|
NULL,
|
|
NULL,
|
|
TRUE,
|
|
priority | CREATE_NO_WINDOW,
|
|
NULL,
|
|
o.conn[config].config_dir,
|
|
&start_info,
|
|
&proc_info))
|
|
{
|
|
/* CreateProcess failed */
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_PROCESS,
|
|
o.exe_path,
|
|
command_line,
|
|
o.conn[config].config_dir);
|
|
goto failed;
|
|
}
|
|
|
|
|
|
/* close unneeded handles */
|
|
Sleep (250); /* try to prevent race if we close logfile
|
|
handle before child process DUPs it */
|
|
|
|
if(!CloseHandle (proc_info.hThread) ||
|
|
!CloseHandle (hOutputWrite) ||
|
|
!CloseHandle (hInputRead) ||
|
|
!CloseHandle (hErrorWrite))
|
|
{
|
|
/* CloseHandle failed */
|
|
ShowLocalizedMsg(IDS_ERR_CLOSE_HANDLE);
|
|
CloseHandle (o.conn[config].exit_event);
|
|
return(false);
|
|
}
|
|
hOutputWrite = NULL;
|
|
hInputRead = NULL;
|
|
hErrorWrite = NULL;
|
|
|
|
/* Save StdIn and StdOut handles in our options struct */
|
|
o.conn[config].hStdIn = hInputWrite;
|
|
o.conn[config].hStdOut = hOutputRead;
|
|
|
|
/* Save Process Handle */
|
|
o.conn[config].hProcess=proc_info.hProcess;
|
|
|
|
|
|
/* Start Thread to show Status Dialog */
|
|
hThread = CreateThread(NULL, 0,
|
|
(LPTHREAD_START_ROUTINE) ThreadOpenVPNStatus,
|
|
(int *) config, // pass config nr
|
|
0, &IDThread);
|
|
if (hThread == NULL)
|
|
{
|
|
/* CreateThread failed */
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_THREAD_STATUS);
|
|
goto failed;
|
|
}
|
|
|
|
|
|
return(true);
|
|
|
|
failed:
|
|
if (o.conn[config].exit_event) CloseHandle (o.conn[config].exit_event);
|
|
if (hOutputWrite) CloseHandle (hOutputWrite);
|
|
if (hOutputRead) CloseHandle (hOutputRead);
|
|
if (hInputWrite) CloseHandle (hInputWrite);
|
|
if (hInputRead) CloseHandle (hInputRead);
|
|
if (hErrorWrite) CloseHandle (hOutputWrite);
|
|
return(false);
|
|
|
|
}
|
|
|
|
|
|
void StopOpenVPN(int config)
|
|
{
|
|
o.conn[config].state = disconnecting;
|
|
|
|
if (o.conn[config].exit_event) {
|
|
/* Run Disconnect script */
|
|
RunDisconnectScript(config, false);
|
|
|
|
EnableWindow(GetDlgItem(o.conn[config].hwndStatus, ID_DISCONNECT), FALSE);
|
|
EnableWindow(GetDlgItem(o.conn[config].hwndStatus, ID_RESTART), FALSE);
|
|
SetMenuStatus(config, disconnecting);
|
|
/* UserInfo: waiting for OpenVPN termination... */
|
|
SetDlgItemText(o.conn[config].hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM));
|
|
SetEvent(o.conn[config].exit_event);
|
|
}
|
|
}
|
|
|
|
void SuspendOpenVPN(int config)
|
|
{
|
|
o.conn[config].state = suspending;
|
|
o.conn[config].restart = true;
|
|
|
|
if (o.conn[config].exit_event) {
|
|
EnableWindow(GetDlgItem(o.conn[config].hwndStatus, ID_DISCONNECT), FALSE);
|
|
EnableWindow(GetDlgItem(o.conn[config].hwndStatus, ID_RESTART), FALSE);
|
|
SetMenuStatus(config, disconnecting);
|
|
SetDlgItemText(o.conn[config].hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_WAIT_TERM));
|
|
SetEvent(o.conn[config].exit_event);
|
|
}
|
|
}
|
|
|
|
|
|
void StopAllOpenVPN()
|
|
{
|
|
int i;
|
|
|
|
for(i=0; i < o.num_configs; i++) {
|
|
if(o.conn[i].state != disconnected)
|
|
StopOpenVPN(i);
|
|
}
|
|
|
|
/* Wait for all connections to terminate (Max 5 sec) */
|
|
for (i=0; i<20; i++, Sleep(250))
|
|
if (CountConnState(disconnected) == o.num_configs) break;
|
|
|
|
}
|
|
|
|
|
|
BOOL CALLBACK StatusDialogFunc (HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
static const TCHAR cfgProp[] = _T("config");
|
|
HWND hwndLogWindow;
|
|
RECT rect;
|
|
CHARFORMAT charformat;
|
|
UINT config;
|
|
|
|
switch (msg) {
|
|
|
|
case WM_INITDIALOG:
|
|
/* Set Window Icon "DisConnected" */
|
|
SetStatusWinIcon(hwndDlg, ID_ICO_CONNECTING);
|
|
|
|
/* Set config number for this dialog */
|
|
SetProp(hwndDlg, cfgProp, (HANDLE) lParam);
|
|
|
|
/* Create LogWindow */
|
|
hwndLogWindow = CreateWindowEx (0, RICHEDIT_CLASS, NULL,
|
|
WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | \
|
|
ES_SUNKEN | ES_LEFT | ES_MULTILINE | \
|
|
ES_READONLY | ES_AUTOHSCROLL | ES_AUTOVSCROLL,
|
|
20, 25, 350, 160, // Posision and Size
|
|
hwndDlg, // Parent window handle
|
|
(HMENU) ID_EDT_LOG, // hMenu
|
|
o.hInstance, // hInstance
|
|
NULL); // WM_CREATE lpParam
|
|
|
|
|
|
if (!hwndLogWindow)
|
|
{
|
|
/* Create RichEd LogWindow Failed */
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_EDIT_LOGWINDOW);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Set font and fontsize of the LogWindow */
|
|
charformat.cbSize = sizeof(CHARFORMAT);
|
|
charformat.dwMask = CFM_SIZE | CFM_FACE | CFM_BOLD | CFM_ITALIC | \
|
|
CFM_UNDERLINE | CFM_STRIKEOUT | CFM_PROTECTED;
|
|
charformat.dwEffects = 0;
|
|
charformat.yHeight = 100;
|
|
_tcscpy(charformat.szFaceName, _T("MS Sans Serif"));
|
|
if ((SendMessage(hwndLogWindow, EM_SETCHARFORMAT, SCF_DEFAULT, (LPARAM) &charformat) && CFM_SIZE) == 0) {
|
|
/* set size failed */
|
|
ShowLocalizedMsg(IDS_ERR_SET_SIZE);
|
|
}
|
|
|
|
/* Set Size and Posision of controls */
|
|
GetClientRect(hwndDlg, &rect);
|
|
MoveWindow (hwndLogWindow, 20, 25, rect.right - 40, rect.bottom - 70, TRUE);
|
|
MoveWindow (GetDlgItem(hwndDlg, ID_TXT_STATUS), 20, 5, rect.right - 25, 15, TRUE);
|
|
MoveWindow (GetDlgItem(hwndDlg, ID_DISCONNECT), 20, rect.bottom - 30, 90, 23, TRUE);
|
|
MoveWindow (GetDlgItem(hwndDlg, ID_RESTART), 125, rect.bottom - 30, 90, 23, TRUE);
|
|
MoveWindow (GetDlgItem(hwndDlg, ID_HIDE), rect.right - 110, rect.bottom - 30, 90, 23, TRUE);
|
|
|
|
/* Set focus on the LogWindow so it scrolls automatically */
|
|
SetFocus(hwndLogWindow);
|
|
|
|
return FALSE;
|
|
|
|
case WM_SIZE:
|
|
MoveWindow (GetDlgItem(hwndDlg, ID_EDT_LOG), 20, 25, LOWORD (lParam) - 40,
|
|
HIWORD (lParam) - 70, TRUE);
|
|
MoveWindow (GetDlgItem(hwndDlg, ID_DISCONNECT), 20,
|
|
HIWORD (lParam) - 30, 90, 23, TRUE);
|
|
MoveWindow (GetDlgItem(hwndDlg, ID_RESTART), 125,
|
|
HIWORD (lParam) - 30, 90, 23, TRUE);
|
|
MoveWindow (GetDlgItem(hwndDlg, ID_HIDE), LOWORD (lParam) - 110,
|
|
HIWORD (lParam) - 30, 90, 23, TRUE);
|
|
MoveWindow (GetDlgItem(hwndDlg, ID_TXT_STATUS), 20, 5, LOWORD (lParam) - 25, 15, TRUE);
|
|
InvalidateRect(hwndDlg, NULL, TRUE);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
config = (UINT) GetProp(hwndDlg, cfgProp);
|
|
switch (LOWORD(wParam)) {
|
|
|
|
case ID_DISCONNECT:
|
|
SetFocus(GetDlgItem(o.conn[config].hwndStatus, ID_EDT_LOG));
|
|
StopOpenVPN(config);
|
|
return TRUE;
|
|
|
|
case ID_HIDE:
|
|
if (o.conn[config].state != disconnected)
|
|
{
|
|
ShowWindow(hwndDlg, SW_HIDE);
|
|
}
|
|
else
|
|
{
|
|
DestroyWindow(hwndDlg);
|
|
}
|
|
return TRUE;
|
|
|
|
case ID_RESTART:
|
|
SetFocus(GetDlgItem(o.conn[config].hwndStatus, ID_EDT_LOG));
|
|
o.conn[config].restart = true;
|
|
StopOpenVPN(config);
|
|
return TRUE;
|
|
}
|
|
break;
|
|
|
|
case WM_SHOWWINDOW:
|
|
if (wParam == TRUE)
|
|
{
|
|
config = (UINT) GetProp(hwndDlg, cfgProp);
|
|
if (o.conn[config].hwndStatus)
|
|
SetFocus(GetDlgItem(o.conn[config].hwndStatus, ID_EDT_LOG));
|
|
}
|
|
return FALSE;
|
|
|
|
case WM_CLOSE:
|
|
config = (UINT) GetProp(hwndDlg, cfgProp);
|
|
if (o.conn[config].state != disconnected)
|
|
{
|
|
ShowWindow(hwndDlg, SW_HIDE);
|
|
}
|
|
else
|
|
{
|
|
DestroyWindow(hwndDlg);
|
|
}
|
|
return TRUE;
|
|
|
|
case WM_NCDESTROY:
|
|
RemoveProp(hwndDlg, cfgProp);
|
|
break;
|
|
|
|
case WM_DESTROY:
|
|
PostQuitMessage(0);
|
|
break;
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
void SetStatusWinIcon(HWND hwndDlg, int IconID)
|
|
{
|
|
/* Set Window Icon */
|
|
HICON hIcon = LoadLocalizedIcon(IconID);
|
|
if (hIcon) {
|
|
SendMessage(hwndDlg, WM_SETICON, (WPARAM) (ICON_SMALL), (LPARAM) (hIcon));
|
|
SendMessage(hwndDlg, WM_SETICON, (WPARAM) (ICON_BIG), (LPARAM) (hIcon));
|
|
}
|
|
}
|
|
|
|
int AutoStartConnections()
|
|
{
|
|
int i;
|
|
|
|
for (i=0; i < o.num_configs; i++)
|
|
{
|
|
if (o.conn[i].auto_connect)
|
|
StartOpenVPN(i);
|
|
}
|
|
|
|
return(true);
|
|
}
|
|
|
|
int VerifyAutoConnections()
|
|
{
|
|
int i,j;
|
|
BOOL match;
|
|
|
|
for (i=0; (o.auto_connect[i] != 0) && (i < MAX_CONFIGS); i++)
|
|
{
|
|
match = false;
|
|
for (j=0; j < MAX_CONFIGS; j++)
|
|
{
|
|
if (_tcsicmp(o.conn[j].config_file, o.auto_connect[i]) == 0)
|
|
{
|
|
match=true;
|
|
break;
|
|
}
|
|
}
|
|
if (match == false)
|
|
{
|
|
/* autostart config not found */
|
|
ShowLocalizedMsg(IDS_ERR_AUTOSTART_CONF, o.auto_connect[i]);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
BOOL
|
|
CheckVersion()
|
|
{
|
|
HANDLE hOutputRead;
|
|
HANDLE hOutputWrite;
|
|
HANDLE hInputRead;
|
|
HANDLE hInputWrite;
|
|
|
|
BOOL retval = FALSE;
|
|
STARTUPINFO si;
|
|
PROCESS_INFORMATION pi;
|
|
TCHAR cmdline[] = _T("openvpn --version");
|
|
char match_version[] = "OpenVPN 2.";
|
|
TCHAR pwd[MAX_PATH];
|
|
char line[1024];
|
|
TCHAR *p;
|
|
|
|
CLEAR(si);
|
|
CLEAR(pi);
|
|
|
|
if (!GetPipeHandles(&hInputRead, &hInputWrite, &hOutputRead, &hOutputWrite))
|
|
return FALSE;
|
|
|
|
/* Construct the process' working directory */
|
|
_tcsncpy(pwd, o.exe_path, _tsizeof(pwd));
|
|
p = _tcsrchr(pwd, _T('\\'));
|
|
if (p != NULL)
|
|
*p = _T('\0');
|
|
|
|
/* Fill in STARTUPINFO struct */
|
|
si.cb = sizeof(si);
|
|
si.dwFlags = STARTF_USESTDHANDLES;
|
|
si.hStdInput = hInputRead;
|
|
si.hStdOutput = hOutputWrite;
|
|
si.hStdError = hOutputWrite;
|
|
|
|
/* Start OpenVPN to check version */
|
|
if (!CreateProcess(o.exe_path, cmdline, NULL, NULL, TRUE,
|
|
CREATE_NO_WINDOW, NULL, pwd, &si, &pi)) {
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_PROCESS, o.exe_path, cmdline, pwd);
|
|
}
|
|
else if (ReadLineFromStdOut(hOutputRead, 0, line)) {
|
|
#ifdef DEBUG
|
|
PrintDebug("VersionString: %s", line);
|
|
#endif
|
|
CloseHandle(pi.hThread);
|
|
CloseHandle(pi.hProcess);
|
|
|
|
/* OpenVPN version 2.x */
|
|
if (strstr(line, match_version))
|
|
retval = TRUE;
|
|
}
|
|
|
|
if (!CloseHandle(hInputRead) || !CloseHandle(hInputWrite)
|
|
|| !CloseHandle(hOutputRead) || !CloseHandle(hOutputWrite))
|
|
ShowLocalizedMsg(IDS_ERR_CLOSE_HANDLE);
|
|
|
|
return retval;
|
|
}
|
|
|
|
|
|
void CheckAndSetTrayIcon()
|
|
{
|
|
|
|
/* Show green icon if service is running */
|
|
if (o.service_state == service_connected)
|
|
{
|
|
SetTrayIcon(connected);
|
|
return;
|
|
}
|
|
|
|
/* Change tray icon if no more connections is running */
|
|
if (CountConnState(connected) != 0)
|
|
SetTrayIcon(connected);
|
|
else
|
|
{
|
|
if ((CountConnState(connecting) != 0) ||
|
|
(CountConnState(reconnecting) != 0) ||
|
|
(o.service_state == service_connecting))
|
|
SetTrayIcon(connecting);
|
|
else
|
|
SetTrayIcon(disconnected);
|
|
}
|
|
}
|
|
|
|
void ThreadOpenVPNStatus(int config)
|
|
{
|
|
TCHAR conn_name[200];
|
|
HANDLE hThread;
|
|
DWORD IDThread;
|
|
MSG messages;
|
|
|
|
/* Cut of extention from config filename. */
|
|
_tcsncpy(conn_name, o.conn[config].config_file, _tsizeof(conn_name));
|
|
conn_name[_tcslen(conn_name) - (_tcslen(o.ext_string)+1)]=0;
|
|
|
|
if (o.conn[config].restart)
|
|
{
|
|
/* UserInfo: Connecting */
|
|
SetDlgItemText(o.conn[config].hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_CONNECTING));
|
|
SetStatusWinIcon(o.conn[config].hwndStatus, ID_ICO_CONNECTING);
|
|
EnableWindow(GetDlgItem(o.conn[config].hwndStatus, ID_DISCONNECT), TRUE);
|
|
EnableWindow(GetDlgItem(o.conn[config].hwndStatus, ID_RESTART), TRUE);
|
|
SetFocus(GetDlgItem(o.conn[config].hwndStatus, ID_EDT_LOG));
|
|
o.conn[config].restart = false;
|
|
}
|
|
else
|
|
{
|
|
/* Create and Show Status Dialog */
|
|
o.conn[config].hwndStatus = CreateLocalizedDialogParam(ID_DLG_STATUS, StatusDialogFunc, config);
|
|
if (!o.conn[config].hwndStatus)
|
|
ExitThread(1);
|
|
/* UserInfo: Connecting */
|
|
SetDlgItemText(o.conn[config].hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_CONNECTING));
|
|
SetWindowText(o.conn[config].hwndStatus, LoadLocalizedString(IDS_NFO_CONNECTION_XXX, conn_name));
|
|
|
|
if (o.silent_connection[0]=='0')
|
|
ShowWindow(o.conn[config].hwndStatus, SW_SHOW);
|
|
}
|
|
|
|
|
|
/* Start Thread to monitor our OpenVPN process */
|
|
hThread = CreateThread(NULL, 0,
|
|
(LPTHREAD_START_ROUTINE) WatchOpenVPNProcess,
|
|
(int *) config, // pass config nr
|
|
0, &IDThread);
|
|
if (hThread == NULL)
|
|
{
|
|
/* CreateThread failed */
|
|
ShowLocalizedMsg(IDS_ERR_THREAD_READ_STDOUT);
|
|
ExitThread(0);
|
|
}
|
|
|
|
/* Run the message loop. It will run until GetMessage() returns 0 */
|
|
while (GetMessage (&messages, NULL, 0, 0))
|
|
{
|
|
if(!IsDialogMessage(o.conn[config].hwndStatus, &messages))
|
|
{
|
|
TranslateMessage(&messages);
|
|
DispatchMessage(&messages);
|
|
}
|
|
}
|
|
|
|
ExitThread(0);
|
|
}
|
|
|