Browse Source

support starting OpenVPN via interactive service

pull/1/head
Heiko Hund 13 years ago
parent
commit
3670a4bd2a
  1. 199
      openvpn.c
  2. 1
      options.h

199
openvpn.c

@ -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;
}

1
options.h

@ -71,7 +71,6 @@ struct connection {
mgmt_cmd_t *cmd_queue;
} manage;
HANDLE hProcess;
HANDLE exit_event;
DWORD threadId;
HWND hwndStatus;

Loading…
Cancel
Save