|
|
|
@ -645,31 +645,17 @@ BOOL
|
|
|
|
|
StartOpenVPN(connection_t *c) |
|
|
|
|
{ |
|
|
|
|
TCHAR cmdline[1024]; |
|
|
|
|
TCHAR *options = cmdline + 8; |
|
|
|
|
TCHAR proxy_string[100]; |
|
|
|
|
TCHAR exit_event_name[17]; |
|
|
|
|
HANDLE hStdInRead, hStdInWrite, hNul, hThread; |
|
|
|
|
PROCESS_INFORMATION pi; |
|
|
|
|
STARTUPINFO si; |
|
|
|
|
DWORD priority, written; |
|
|
|
|
HANDLE hStdInRead = NULL, hStdInWrite = NULL; |
|
|
|
|
HANDLE hNul = NULL, hThread = NULL, service = NULL; |
|
|
|
|
DWORD written; |
|
|
|
|
BOOL retval = FALSE; |
|
|
|
|
|
|
|
|
|
/* Make I/O handles inheritable and accessible by all */ |
|
|
|
|
SECURITY_DESCRIPTOR sd; |
|
|
|
|
SECURITY_ATTRIBUTES sa = { |
|
|
|
|
.nLength = sizeof(sa), |
|
|
|
|
.lpSecurityDescriptor = &sd, |
|
|
|
|
.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; |
|
|
|
|
} |
|
|
|
|
CLEAR(c->ip); |
|
|
|
|
|
|
|
|
|
RunPreconnectScript(c); |
|
|
|
|
|
|
|
|
|
/* Check that log append flag has a valid value */ |
|
|
|
|
if ((o.append_string[0] != '0') && (o.append_string[0] != '1')) |
|
|
|
@ -678,33 +664,12 @@ StartOpenVPN(connection_t *c)
|
|
|
|
|
return FALSE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Set process priority */ |
|
|
|
|
if (!SetProcessPriority(&priority)) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
/* Get a handle of the NUL device */ |
|
|
|
|
hNul = CreateFile(_T("NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, NULL); |
|
|
|
|
if (hNul == INVALID_HANDLE_VALUE) |
|
|
|
|
return FALSE; |
|
|
|
|
|
|
|
|
|
/* Create the pipe for STDIN with only the read end inheritable */ |
|
|
|
|
if (!CreatePipe(&hStdInRead, &hStdInWrite, &sa, 0)) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_PIPE_IN_READ); |
|
|
|
|
goto out_nul; |
|
|
|
|
} |
|
|
|
|
if (!SetHandleInformation(hStdInWrite, HANDLE_FLAG_INHERIT, 0)) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_DUP_HANDLE_IN_WRITE); |
|
|
|
|
goto out_pipe; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Create thread to show the connection's status dialog */ |
|
|
|
|
hThread = CreateThread(NULL, 0, ThreadOpenVPNStatus, c, CREATE_SUSPENDED, &c->threadId); |
|
|
|
|
if (hThread == NULL) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_THREAD_STATUS); |
|
|
|
|
goto out_pipe; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Create an event object to signal OpenVPN to exit */ |
|
|
|
@ -713,7 +678,7 @@ StartOpenVPN(connection_t *c)
|
|
|
|
|
if (c->exit_event == NULL) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_EVENT, exit_event_name); |
|
|
|
|
goto out_thread; |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Create a management interface password */ |
|
|
|
@ -731,45 +696,131 @@ StartOpenVPN(connection_t *c)
|
|
|
|
|
(o.append_string[0] == '1' ? _T("-append") : _T("")), |
|
|
|
|
c->log_path, c->manage.port); |
|
|
|
|
|
|
|
|
|
CLEAR(c->ip); |
|
|
|
|
RunPreconnectScript(c); |
|
|
|
|
|
|
|
|
|
/* Fill in STARTUPINFO struct */ |
|
|
|
|
GetStartupInfo(&si); |
|
|
|
|
si.cb = sizeof(si); |
|
|
|
|
si.dwFlags = STARTF_USESTDHANDLES; |
|
|
|
|
si.hStdInput = hStdInRead; |
|
|
|
|
si.hStdOutput = hNul; |
|
|
|
|
si.hStdError = hNul; |
|
|
|
|
/* Try to open the service pipe */ |
|
|
|
|
service = CreateFile(_T("\\\\.\\pipe\\openvpn\\service"), |
|
|
|
|
GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); |
|
|
|
|
|
|
|
|
|
/* Create an OpenVPN process for the connection */ |
|
|
|
|
if (!CreateProcess(o.exe_path, cmdline, NULL, NULL, TRUE, |
|
|
|
|
priority | CREATE_NO_WINDOW, NULL, c->config_dir, &si, &pi)) |
|
|
|
|
if (service != INVALID_HANDLE_VALUE) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_PROCESS, o.exe_path, cmdline, c->config_dir); |
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
goto out_thread; |
|
|
|
|
DWORD size = _tcslen(c->config_dir) + _tcslen(options) + sizeof(c->manage.password) + 3; |
|
|
|
|
TCHAR startup_info[1024]; |
|
|
|
|
DWORD dwMode = PIPE_READMODE_MESSAGE; |
|
|
|
|
if (!SetNamedPipeHandleState(service, &dwMode, NULL, NULL)) |
|
|
|
|
{ |
|
|
|
|
// TODO: add error message
|
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
c->manage.password[sizeof(c->manage.password) - 1] = '\n'; |
|
|
|
|
_sntprintf_0(startup_info, _T("%s%c%s%c%.*S"), c->config_dir, _T('\0'), |
|
|
|
|
options, _T('\0'), sizeof(c->manage.password), c->manage.password); |
|
|
|
|
c->manage.password[sizeof(c->manage.password) - 1] = '\0'; |
|
|
|
|
|
|
|
|
|
if (!WriteFile(service, startup_info, size * sizeof (TCHAR), &written, NULL)) |
|
|
|
|
{ |
|
|
|
|
// TODO: add error message
|
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
else |
|
|
|
|
{ |
|
|
|
|
/* Start OpenVPN directly */ |
|
|
|
|
DWORD priority; |
|
|
|
|
STARTUPINFO si; |
|
|
|
|
PROCESS_INFORMATION pi; |
|
|
|
|
SECURITY_DESCRIPTOR sd; |
|
|
|
|
|
|
|
|
|
/* Make I/O handles inheritable and accessible by all */ |
|
|
|
|
SECURITY_ATTRIBUTES sa = { |
|
|
|
|
.nLength = sizeof(sa), |
|
|
|
|
.lpSecurityDescriptor = &sd, |
|
|
|
|
.bInheritHandle = TRUE |
|
|
|
|
}; |
|
|
|
|
if (!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION)) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_INIT_SEC_DESC); |
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
return FALSE; |
|
|
|
|
} |
|
|
|
|
if (!SetSecurityDescriptorDacl(&sd, TRUE, NULL, FALSE)) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_SET_SEC_DESC_ACL); |
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
return FALSE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Pass management password to OpenVPN process */ |
|
|
|
|
c->manage.password[sizeof(c->manage.password) - 1] = '\n'; |
|
|
|
|
WriteFile(hStdInWrite, c->manage.password, sizeof(c->manage.password), &written, NULL); |
|
|
|
|
c->manage.password[sizeof(c->manage.password) - 1] = '\0'; |
|
|
|
|
c->hProcess = pi.hProcess; |
|
|
|
|
/* Set process priority */ |
|
|
|
|
if (!SetProcessPriority(&priority)) |
|
|
|
|
{ |
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
return FALSE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Get a handle of the NUL device */ |
|
|
|
|
hNul = CreateFile(_T("NUL"), GENERIC_WRITE, FILE_SHARE_WRITE, &sa, OPEN_EXISTING, 0, NULL); |
|
|
|
|
if (hNul == INVALID_HANDLE_VALUE) |
|
|
|
|
{ |
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
return FALSE; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Create the pipe for STDIN with only the read end inheritable */ |
|
|
|
|
if (!CreatePipe(&hStdInRead, &hStdInWrite, &sa, 0)) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_PIPE_IN_READ); |
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
if (!SetHandleInformation(hStdInWrite, HANDLE_FLAG_INHERIT, 0)) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_DUP_HANDLE_IN_WRITE); |
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Fill in STARTUPINFO struct */ |
|
|
|
|
GetStartupInfo(&si); |
|
|
|
|
si.cb = sizeof(si); |
|
|
|
|
si.dwFlags = STARTF_USESTDHANDLES; |
|
|
|
|
si.hStdInput = hStdInRead; |
|
|
|
|
si.hStdOutput = hNul; |
|
|
|
|
si.hStdError = hNul; |
|
|
|
|
|
|
|
|
|
/* Create an OpenVPN process for the connection */ |
|
|
|
|
if (!CreateProcess(o.exe_path, cmdline, NULL, NULL, TRUE, |
|
|
|
|
priority | CREATE_NO_WINDOW, NULL, c->config_dir, &si, &pi)) |
|
|
|
|
{ |
|
|
|
|
ShowLocalizedMsg(IDS_ERR_CREATE_PROCESS, o.exe_path, cmdline, c->config_dir); |
|
|
|
|
CloseHandle(c->exit_event); |
|
|
|
|
goto out; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Pass management password to OpenVPN process */ |
|
|
|
|
c->manage.password[sizeof(c->manage.password) - 1] = '\n'; |
|
|
|
|
WriteFile(hStdInWrite, c->manage.password, sizeof(c->manage.password), &written, NULL); |
|
|
|
|
c->manage.password[sizeof(c->manage.password) - 1] = '\0'; |
|
|
|
|
|
|
|
|
|
CloseHandle(pi.hProcess); |
|
|
|
|
CloseHandle(pi.hThread); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Start the status dialog thread */ |
|
|
|
|
ResumeThread(hThread); |
|
|
|
|
|
|
|
|
|
CloseHandle(pi.hThread); |
|
|
|
|
retval = TRUE; |
|
|
|
|
|
|
|
|
|
out_thread: |
|
|
|
|
CloseHandle(hThread); |
|
|
|
|
out_pipe: |
|
|
|
|
CloseHandle(hStdInWrite); |
|
|
|
|
CloseHandle(hStdInRead); |
|
|
|
|
out_nul: |
|
|
|
|
CloseHandle(hNul); |
|
|
|
|
out: |
|
|
|
|
if (service && service != INVALID_HANDLE_VALUE) |
|
|
|
|
CloseHandle(service); |
|
|
|
|
if (hThread && hThread != INVALID_HANDLE_VALUE) |
|
|
|
|
CloseHandle(hThread); |
|
|
|
|
if (hStdInWrite && hStdInWrite != INVALID_HANDLE_VALUE) |
|
|
|
|
CloseHandle(hStdInWrite); |
|
|
|
|
if (hStdInRead && hStdInRead != INVALID_HANDLE_VALUE) |
|
|
|
|
CloseHandle(hStdInRead); |
|
|
|
|
if (hNul && hNul != INVALID_HANDLE_VALUE) |
|
|
|
|
CloseHandle(hNul); |
|
|
|
|
return retval; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|