static void AddConfigFileToList(int config, const TCHAR *filename, const TCHAR *config_dir) { connection_t *c = &o.conn[config]; int i; _tcsncpy(c->config_file, filename, _countof(c->config_file) - 1); _tcsncpy(c->config_dir, config_dir, _countof(c->config_dir) - 1); _tcsncpy(c->config_name, c->config_file, _countof(c->config_name) - 1); c->config_name[_tcslen(c->config_name) - _tcslen(o.ext_string) - 1] = _T('\0'); _sntprintf_0(c->log_path, _T("%s\\%s.log"), o.log_dir, c->config_name); c->manage.sk = INVALID_SOCKET; c->manage.skaddr.sin_family = AF_INET; c->manage.skaddr.sin_addr.s_addr = inet_addr("127.0.0.1"); c->manage.skaddr.sin_port = htons(25340 + config); /* Check if connection should be autostarted */ for (i = 0; i < MAX_CONFIGS && o.auto_connect[i]; ++i) { if (_tcsicmp(c->config_file, o.auto_connect[i]) == 0) { c->auto_connect = true; break; } } }
void RunDisconnectScript(connection_t *c, int run_as_service) { STARTUPINFO si; PROCESS_INFORMATION pi; TCHAR cmdline[256]; DWORD exit_code; struct _stat st; int i; /* Cut off extention from config filename and add "_down.bat" */ int len = _tcslen(c->config_file) - _tcslen(o.ext_string) - 1; _sntprintf_0(cmdline, _T("%s\\%.*s_down.bat"), c->config_dir, len, c->config_file); /* Return if no script exists */ if (_tstat(cmdline, &st) == -1) return; if (!run_as_service) SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_DISCONN_SCRIPT)); CLEAR(si); CLEAR(pi); /* fill in STARTUPINFO struct */ GetStartupInfo(&si); si.cb = sizeof(si); si.dwFlags = 0; si.wShowWindow = SW_SHOWDEFAULT; si.hStdInput = NULL; si.hStdOutput = NULL; /* make an env array with confg specific env appended to the process's env */ WCHAR *env = c->es ? merge_env_block(c->es) : NULL; DWORD flags = CREATE_UNICODE_ENVIRONMENT; if (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, (o.show_script_window ? flags|CREATE_NEW_CONSOLE : flags|CREATE_NO_WINDOW), NULL, c->config_dir, &si, &pi)) { free(env); return; } for (i = 0; i <= (int) o.disconnectscript_timeout; i++) { if (!GetExitCodeProcess(pi.hProcess, &exit_code)) goto out; if (exit_code != STILL_ACTIVE) goto out; Sleep(1000); } out: free(env); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); }
void RunPreconnectScript(connection_t *c) { STARTUPINFO si; PROCESS_INFORMATION pi; TCHAR cmdline[256]; DWORD exit_code; struct _stat st; int i; /* Cut off extention from config filename and add "_pre.bat" */ int len = _tcslen(c->config_file) - _tcslen(o.ext_string) - 1; _sntprintf_0(cmdline, _T("%s\\%.*s_pre.bat"), c->config_dir, len, c->config_file); /* Return if no script exists */ if (_tstat(cmdline, &st) == -1) return; CLEAR(si); CLEAR(pi); /* fill in STARTUPINFO struct */ GetStartupInfo(&si); si.cb = sizeof(si); si.dwFlags = 0; si.wShowWindow = SW_SHOWDEFAULT; si.hStdInput = NULL; si.hStdOutput = NULL; /* Preconnect script is run too early for config env to be available * so we use the default process env here. */ if (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, (o.show_script_window ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW), NULL, c->config_dir, &si, &pi)) return; for (i = 0; i <= (int) o.preconnectscript_timeout; i++) { if (!GetExitCodeProcess(pi.hProcess, &exit_code)) goto out; if (exit_code != STILL_ACTIVE) goto out; Sleep(1000); } out: CloseHandle(pi.hThread); CloseHandle(pi.hProcess); }
void EditConfig(int config) { TCHAR filename[200]; STARTUPINFO start_info; PROCESS_INFORMATION proc_info; SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; CLEAR (start_info); CLEAR (proc_info); CLEAR (sa); CLEAR (sd); _sntprintf_0(filename, _T("%s \"%s\\%s\""), o.editor, o.conn[config].config_dir, o.conn[config].config_file); /* fill in STARTUPINFO struct */ GetStartupInfo(&start_info); start_info.cb = sizeof(start_info); start_info.dwFlags = 0; start_info.wShowWindow = SW_SHOWDEFAULT; start_info.hStdInput = NULL; start_info.hStdOutput = NULL; if (!CreateProcess(NULL, filename, //commandline NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, o.conn[config].config_dir, //start-up dir &start_info, &proc_info)) { /* could not start editor */ ShowLocalizedMsg(IDS_ERR_START_CONF_EDITOR, o.editor); } CloseHandle(proc_info.hThread); CloseHandle(proc_info.hProcess); }
void ViewLog(int config) { TCHAR filename[200]; STARTUPINFO start_info; PROCESS_INFORMATION proc_info; SECURITY_ATTRIBUTES sa; SECURITY_DESCRIPTOR sd; CLEAR (start_info); CLEAR (proc_info); CLEAR (sa); CLEAR (sd); _sntprintf_0(filename, _T("%s \"%s\""), o.log_viewer, o.conn[config].log_path); /* fill in STARTUPINFO struct */ GetStartupInfo(&start_info); start_info.cb = sizeof(start_info); start_info.dwFlags = 0; start_info.wShowWindow = SW_SHOWDEFAULT; start_info.hStdInput = NULL; start_info.hStdOutput = NULL; if (!CreateProcess(NULL, filename, //commandline NULL, NULL, TRUE, CREATE_NEW_CONSOLE, NULL, o.log_dir, //start-up dir &start_info, &proc_info)) { /* could not start log viewer */ ShowLocalizedMsg(IDS_ERR_START_LOG_VIEWER, o.log_viewer); } }
void RunConnectScript(connection_t *c, int run_as_service) { STARTUPINFO si; PROCESS_INFORMATION pi; TCHAR cmdline[256]; DWORD exit_code; struct _stat st; int i; /* Cut off extention from config filename and add "_up.bat" */ int len = _tcslen(c->config_file) - _tcslen(o.ext_string) - 1; _sntprintf_0(cmdline, _T("%s\\%.*s_up.bat"), c->config_dir, len, c->config_file); /* Return if no script exists */ if (_tstat(cmdline, &st) == -1) return; if (!run_as_service) SetDlgItemText(c->hwndStatus, ID_TXT_STATUS, LoadLocalizedString(IDS_NFO_STATE_CONN_SCRIPT)); CLEAR(si); CLEAR(pi); /* fill in STARTUPINFO struct */ GetStartupInfo(&si); si.cb = sizeof(si); si.dwFlags = 0; si.wShowWindow = SW_SHOWDEFAULT; si.hStdInput = NULL; si.hStdOutput = NULL; if (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, (o.show_script_window[0] == '1' ? CREATE_NEW_CONSOLE : CREATE_NO_WINDOW), NULL, c->config_dir, &si, &pi)) { ShowLocalizedMsg(IDS_ERR_RUN_CONN_SCRIPT, cmdline); return; } if (o.connectscript_timeout == 0) goto out; for (i = 0; i <= o.connectscript_timeout; i++) { if (!GetExitCodeProcess(pi.hProcess, &exit_code)) { ShowLocalizedMsg(IDS_ERR_GET_EXIT_CODE, cmdline); goto out; } if (exit_code != STILL_ACTIVE) { if (exit_code != 0) ShowLocalizedMsg(IDS_ERR_CONN_SCRIPT_FAILED, exit_code); goto out; } Sleep(1000); } ShowLocalizedMsg(IDS_ERR_RUN_CONN_SCRIPT_TIMEOUT, o.connectscript_timeout); out: CloseHandle(pi.hThread); CloseHandle(pi.hProcess); }
static void BuildFileList0(const TCHAR *config_dir, bool warn_duplicates) { WIN32_FIND_DATA find_obj; HANDLE find_handle; TCHAR find_string[MAX_PATH]; TCHAR subdir_table[MAX_CONFIG_SUBDIRS][MAX_PATH]; TCHAR fullpath[MAX_PATH]; int subdirs = 0; int i; _sntprintf_0(find_string, _T("%s\\*"), config_dir); find_handle = FindFirstFile(find_string, &find_obj); if (find_handle == INVALID_HANDLE_VALUE) return; /* Loop over each config file in main config dir */ do { if (o.num_configs >= MAX_CONFIGS) { ShowLocalizedMsg(IDS_ERR_MANY_CONFIGS, MAX_CONFIGS); break; } match_t match_type = match(&find_obj, o.ext_string); if (match_type == match_file) { _sntprintf_0(fullpath, _T("%s\\%s"), config_dir, find_obj.cFileName); if (ConfigAlreadyExists(find_obj.cFileName)) { if (warn_duplicates) ShowLocalizedMsg(IDS_ERR_CONFIG_EXIST, find_obj.cFileName); continue; } if (CheckReadAccess (fullpath)) AddConfigFileToList(o.num_configs++, find_obj.cFileName, config_dir); } else if (match_type == match_dir) { if (_tcsncmp(find_obj.cFileName, _T("."), _tcslen(find_obj.cFileName)) != 0 && _tcsncmp(find_obj.cFileName, _T(".."), _tcslen(find_obj.cFileName)) != 0 && subdirs < MAX_CONFIG_SUBDIRS) { /* Add dir to dir_table */ _sntprintf_0(subdir_table[subdirs], _T("%s\\%s"), config_dir, find_obj.cFileName); subdirs++; } } } while (FindNextFile(find_handle, &find_obj)); FindClose(find_handle); /* Loop over each config file in every subdir */ for (i = 0; i < subdirs; ++i) { _sntprintf_0(find_string, _T("%s\\*"), subdir_table[i]); find_handle = FindFirstFile (find_string, &find_obj); if (find_handle == INVALID_HANDLE_VALUE) continue; do { if (o.num_configs >= MAX_CONFIGS) { ShowLocalizedMsg(IDS_ERR_MANY_CONFIGS, MAX_CONFIGS); FindClose(find_handle); return; } /* does file have the correct type and extension? */ if (match(&find_obj, o.ext_string) != match_file) continue; if (ConfigAlreadyExists(find_obj.cFileName)) { if (warn_duplicates) ShowLocalizedMsg(IDS_ERR_CONFIG_EXIST, find_obj.cFileName); continue; } AddConfigFileToList(o.num_configs++, find_obj.cFileName, subdir_table[i]); } while (FindNextFile(find_handle, &find_obj)); FindClose(find_handle); } }
/* * Launch an OpenVPN process and the accompanying thread to monitor it */ BOOL StartOpenVPN(connection_t *c) { TCHAR cmdline[1024]; TCHAR *options = cmdline + 8; TCHAR exit_event_name[17]; HANDLE hStdInRead = NULL, hStdInWrite = NULL; HANDLE hNul = NULL, hThread = NULL; DWORD written; BOOL retval = FALSE; CLEAR(c->ip); if (c->hwndStatus) { PrintDebug(L"Connection request when previous status window is still open -- ignored"); WriteStatusLog(c, L"OpenVPN GUI> ", L"Complete the pending dialog before starting a new connection", false); SetForegroundWindow(c->hwndStatus); return FALSE; } RunPreconnectScript(c); /* 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; } /* Create an event object to signal OpenVPN to exit */ _sntprintf_0(exit_event_name, _T("%x%08x"), GetCurrentProcessId(), c->threadId); c->exit_event = CreateEvent(NULL, TRUE, FALSE, exit_event_name); if (c->exit_event == NULL) { ShowLocalizedMsg(IDS_ERR_CREATE_EVENT, exit_event_name); goto out; } /* Create a management interface password */ GetRandomPassword(c->manage.password, sizeof(c->manage.password) - 1); /* Construct command line -- put log first */ _sntprintf_0(cmdline, _T("openvpn --log%s \"%s\" --config \"%s\" " "--setenv IV_GUI_VER \"%S\" --service %s 0 --auth-retry interact " "--management %S %hd stdin --management-query-passwords %s" "--management-hold"), (o.log_append ? _T("-append") : _T("")), c->log_path, c->config_file, PACKAGE_STRING, exit_event_name, inet_ntoa(c->manage.skaddr.sin_addr), ntohs(c->manage.skaddr.sin_port), (o.proxy_source != config ? _T("--management-query-proxy ") : _T(""))); /* Try to open the service pipe */ if (!IsUserAdmin() && InitServiceIO (&c->iserv)) { DWORD size = _tcslen(c->config_dir) + _tcslen(options) + sizeof(c->manage.password) + 3; TCHAR startup_info[1024]; if ( !AuthorizeConfig(c)) { CloseHandle(c->exit_event); goto out; } c->hProcess = NULL; 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 (!WritePipe(c->iserv.pipe, startup_info, size * sizeof (TCHAR))) { ShowLocalizedMsg (IDS_ERR_WRITE_SERVICE_PIPE); CloseHandle(c->exit_event); CloseServiceIO(&c->iserv); 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; } /* 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'; c->hProcess = pi.hProcess; /* Will be closed in the event loop on exit */ CloseHandle(pi.hThread); } /* Start the status dialog thread */ ResumeThread(hThread); retval = TRUE; out: 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; } void StopOpenVPN(connection_t *c) { PostMessage(c->hwndStatus, WM_OVPN_STOP, 0, 0); }
int GetRegistryKeys() { TCHAR windows_dir[MAX_PATH]; TCHAR temp_path[MAX_PATH]; TCHAR openvpn_path[MAX_PATH]; TCHAR profile_dir[MAX_PATH]; HKEY regkey; if (!GetWindowsDirectory(windows_dir, _countof(windows_dir))) { /* can't get windows dir */ ShowLocalizedMsg(IDS_ERR_GET_WINDOWS_DIR); return(false); } if (SHGetFolderPath(NULL, CSIDL_PROFILE, NULL, SHGFP_TYPE_CURRENT, profile_dir) != S_OK) { ShowLocalizedMsg(IDS_ERR_GET_PROFILE_DIR); return(false); } /* Get path to OpenVPN installation. */ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\OpenVPN"), 0, KEY_READ, ®key) != ERROR_SUCCESS) { /* registry key not found */ ShowLocalizedMsg(IDS_ERR_OPEN_REGISTRY); return(false); } if (!GetRegistryValue(regkey, _T(""), openvpn_path, _countof(openvpn_path))) { /* error reading registry value */ ShowLocalizedMsg(IDS_ERR_READING_REGISTRY); RegCloseKey(regkey); return(false); } if (openvpn_path[_tcslen(openvpn_path) - 1] != _T('\\')) _tcscat(openvpn_path, _T("\\")); /* an admin-defined global config dir defined in HKLM\OpenVPN\config_dir */ if (!GetRegistryValue(regkey, _T("config_dir"), o.global_config_dir, _countof(o.global_config_dir))) { /* use default = openvpnpath\config */ _sntprintf_0(o.global_config_dir, _T("%sconfig"), openvpn_path); } if (!GetRegistryValue(regkey, _T("ovpn_admin_group"), o.ovpn_admin_group, _countof(o.ovpn_admin_group))) { _tcsncpy(o.ovpn_admin_group, OVPN_ADMIN_GROUP, _countof(o.ovpn_admin_group)); } RegCloseKey(regkey); /* config_dir in user's profile by default */ _sntprintf_0(temp_path, _T("%s\\OpenVPN\\config"), profile_dir); if (!GetRegKey(_T("config_dir"), o.config_dir, temp_path, _countof(o.config_dir))) return(false); if (!GetRegKey(_T("config_ext"), o.ext_string, _T("ovpn"), _countof(o.ext_string))) return(false); _sntprintf_0(temp_path, _T("%sbin\\openvpn.exe"), openvpn_path); if (!GetRegKey(_T("exe_path"), o.exe_path, temp_path, _countof(o.exe_path))) return(false); _sntprintf_0(temp_path, _T("%s\\OpenVPN\\log"), profile_dir); if (!GetRegKey(_T("log_dir"), o.log_dir, temp_path, _countof(o.log_dir))) return(false); if (!GetRegKey(_T("log_append"), o.append_string, _T("0"), _countof(o.append_string))) return(false); if (!GetRegKey(_T("priority"), o.priority_string, _T("NORMAL_PRIORITY_CLASS"), _countof(o.priority_string))) return(false); _sntprintf_0(temp_path, _T("%s\\system32\\notepad.exe"), windows_dir); if (!GetRegKey(_T("log_viewer"), o.log_viewer, temp_path, _countof(o.log_viewer))) return(false); _sntprintf_0(temp_path, _T("%s\\system32\\notepad.exe"), windows_dir); if (!GetRegKey(_T("editor"), o.editor, temp_path, _countof(o.editor))) return(false); if (!GetRegKey(_T("allow_edit"), o.allow_edit, _T("1"), _countof(o.allow_edit))) return(false); if (!GetRegKey(_T("allow_service"), o.allow_service, _T("0"), _countof(o.allow_service))) return(false); if (!GetRegKey(_T("allow_password"), o.allow_password, _T("1"), _countof(o.allow_password))) return(false); if (!GetRegKey(_T("allow_proxy"), o.allow_proxy, _T("1"), _countof(o.allow_proxy))) return(false); if (!GetRegKey(_T("service_only"), o.service_only, _T("0"), _countof(o.service_only))) return(false); if (!GetRegKey(_T("show_balloon"), o.show_balloon, _T("1"), _countof(o.show_balloon))) return(false); if (!GetRegKey(_T("silent_connection"), o.silent_connection, _T("0"), _countof(o.silent_connection))) return(false); if (!GetRegKey(_T("show_script_window"), o.show_script_window, _T("1"), _countof(o.show_script_window))) return(false); if (!GetRegKey(_T("disconnect_on_suspend"), o.disconnect_on_suspend, _T("0"), _countof(o.disconnect_on_suspend))) return(false); if (!GetRegKey(_T("passphrase_attempts"), o.psw_attempts_string, _T("3"), _countof(o.psw_attempts_string))) return(false); o.psw_attempts = _ttoi(o.psw_attempts_string); if ((o.psw_attempts < 1) || (o.psw_attempts > 9)) { /* 0 <= passphrase_attempts <= 9 */ ShowLocalizedMsg(IDS_ERR_PASSPHRASE_ATTEMPTS); return(false); } if (!GetRegKey(_T("connectscript_timeout"), o.connectscript_timeout_string, _T("15"), _countof(o.connectscript_timeout_string))) return(false); o.connectscript_timeout = _ttoi(o.connectscript_timeout_string); if ((o.connectscript_timeout < 0) || (o.connectscript_timeout > 99)) { /* 0 <= connectscript_timeout <= 99 */ ShowLocalizedMsg(IDS_ERR_CONN_SCRIPT_TIMEOUT); return(false); } if (!GetRegKey(_T("disconnectscript_timeout"), o.disconnectscript_timeout_string, _T("10"), _countof(o.disconnectscript_timeout_string))) return(false); o.disconnectscript_timeout = _ttoi(o.disconnectscript_timeout_string); if ((o.disconnectscript_timeout <= 0) || (o.disconnectscript_timeout > 99)) { /* 0 < disconnectscript_timeout <= 99 */ ShowLocalizedMsg(IDS_ERR_DISCONN_SCRIPT_TIMEOUT); return(false); } if (!GetRegKey(_T("preconnectscript_timeout"), o.preconnectscript_timeout_string, _T("10"), _countof(o.preconnectscript_timeout_string))) return(false); o.preconnectscript_timeout = _ttoi(o.preconnectscript_timeout_string); if ((o.preconnectscript_timeout <= 0) || (o.preconnectscript_timeout > 99)) { /* 0 < disconnectscript_timeout <= 99 */ ShowLocalizedMsg(IDS_ERR_PRECONN_SCRIPT_TIMEOUT); return(false); } return(true); }