diff --git a/include/freerdp/server/proxy/proxy_config.h b/include/freerdp/server/proxy/proxy_config.h index 7a5e00b3e..65c995b3b 100644 --- a/include/freerdp/server/proxy/proxy_config.h +++ b/include/freerdp/server/proxy/proxy_config.h @@ -93,6 +93,13 @@ extern "C" { #endif + /** + * @brief pf_server_config_dump Dumps a default INI configuration file + * @param file The file to write to. Existing files are truncated. + * @return TRUE for success, FALSE if the file could not be written. + */ + FREERDP_API BOOL pf_server_config_dump(const char* file); + /** * @brief server_config_load_ini Create a proxyConfig from a already loaded * INI file. diff --git a/server/proxy/cli/freerdp_proxy.c b/server/proxy/cli/freerdp_proxy.c index ebd9d1132..378944112 100644 --- a/server/proxy/cli/freerdp_proxy.c +++ b/server/proxy/cli/freerdp_proxy.c @@ -69,6 +69,16 @@ static void pf_server_register_signal_handlers(void) #endif } +static WINPR_NORETURN(void usage(const char* app)) +{ + printf("Usage:\n"); + printf("%s -h Display this help text.\n", app); + printf("%s --help Display this help text.\n", app); + printf("%s Start the proxy with \n", app); + printf("%s --dump-config Create a template \n", app); + exit(0); +} + int main(int argc, char* argv[]) { proxyConfig* config = NULL; @@ -82,8 +92,27 @@ int main(int argc, char* argv[]) WLog_INFO(TAG, "\tGit commit: %s", FREERDP_GIT_REVISION); WLog_DBG(TAG, "\tBuild config: %s", freerdp_get_build_config()); - if (argc >= 2) + if (argc < 2) + usage(argv[0]); + + { + const char* arg = argv[1]; + + if (_stricmp(arg, "-h") == 0) + usage(argv[0]); + else if (_stricmp(arg, "--help") == 0) + usage(argv[0]); + else if (_stricmp(arg, "--dump-config") == 0) + { + if (argc <= 2) + usage(argv[0]); + pf_server_config_dump(argv[2]); + status = 0; + goto fail; + } + config_path = argv[1]; + } config = pf_server_config_load_file(config_path); if (!config) diff --git a/server/proxy/pf_client.c b/server/proxy/pf_client.c index dcee993cc..c66ca6aac 100644 --- a/server/proxy/pf_client.c +++ b/server/proxy/pf_client.c @@ -681,18 +681,19 @@ out: * Connects RDP, loops while running and handles event and dispatch, cleans up * after the connection ends. */ -static DWORD WINAPI pf_client_thread_proc(LPVOID arg) +static DWORD WINAPI pf_client_thread_proc(pClientContext* pc) { - freerdp* instance = (freerdp*)arg; - pClientContext* pc; + freerdp* instance; proxyData* pdata; DWORD nCount = 0; DWORD status; HANDLE handles[MAXIMUM_WAIT_OBJECTS] = { 0 }; - WINPR_ASSERT(instance); - pc = (pClientContext*)instance->context; WINPR_ASSERT(pc); + + instance = pc->context.instance; + WINPR_ASSERT(instance); + pdata = pc->pdata; WINPR_ASSERT(pdata); /* @@ -904,17 +905,6 @@ static int pf_client_client_stop(rdpContext* context) proxy_data_abort_connect(pdata); freerdp_abort_connect(context->instance); - if (pdata->client_thread) - { - /* - * Wait for client thread to finish. No need to call CloseHandle() here, as - * it is the responsibility of `proxy_data_free`. - */ - PROXY_LOG_DBG(TAG, pc, "waiting for client thread to finish"); - WaitForSingleObject(pdata->client_thread, INFINITE); - PROXY_LOG_DBG(TAG, pc, "thread finished"); - } - return 0; } @@ -938,11 +928,12 @@ int RdpClientEntry(RDP_CLIENT_ENTRY_POINTS* pEntryPoints) */ DWORD WINAPI pf_client_start(LPVOID arg) { - rdpContext* context = (rdpContext*)arg; + DWORD rc = 1; + pClientContext* pc = (pClientContext*)arg; - WINPR_ASSERT(context); - if (freerdp_client_start(context) != 0) - return 1; - - return pf_client_thread_proc(context->instance); + WINPR_ASSERT(pc); + if (freerdp_client_start(&pc->context) == 0) + rc = pf_client_thread_proc(pc); + freerdp_client_stop(&pc->context); + return rc; } diff --git a/server/proxy/pf_config.c b/server/proxy/pf_config.c index 6955a6605..c41eb7cd8 100644 --- a/server/proxy/pf_config.c +++ b/server/proxy/pf_config.c @@ -437,6 +437,116 @@ out: return NULL; } +BOOL pf_server_config_dump(const char* file) +{ + BOOL rc = FALSE; + wIniFile* ini = IniFile_New(); + if (!ini) + return FALSE; + + /* Proxy server configuration */ + if (IniFile_SetKeyValueString(ini, "Server", "Host", "0.0.0.0") < 0) + goto fail; + if (IniFile_SetKeyValueInt(ini, "Server", "Port", 3389) < 0) + goto fail; + + /* Target configuration */ + if (IniFile_SetKeyValueString(ini, "Target", "Host", "somehost.example.com") < 0) + goto fail; + if (IniFile_SetKeyValueInt(ini, "Target", "Port", 3389) < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Target", "FixedTarget", "true") < 0) + goto fail; + + /* Channel configuration */ + if (IniFile_SetKeyValueString(ini, "Channels", "GFX", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Channels", "DisplayControl", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Channels", "Clipboard", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Channels", "AudioOutput", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Channels", "RemoteApp", "false") < 0) + goto fail; + + if (IniFile_SetKeyValueString(ini, "Channels", "PassthroughIsBlacklist", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Channels", "Passthrough", "") < 0) + goto fail; + + /* Input configuration */ + if (IniFile_SetKeyValueString(ini, "Input", "Keyboard", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Input", "Mouse", "true") < 0) + goto fail; + + /* Security settings */ + if (IniFile_SetKeyValueString(ini, "Security", "ServerTlsSecurity", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Security", "ServerNlaSecurity", "false") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Security", "ServerRdpSecurity", "true") < 0) + goto fail; + + if (IniFile_SetKeyValueString(ini, "Security", "ClientTlsSecurity", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Security", "ClientNlaSecurity", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Security", "ClientRdpSecurity", "true") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Security", "ClientAllowFallbackToTls", "true") < 0) + goto fail; + + /* Module configuration */ + if (IniFile_SetKeyValueString(ini, "Plugins", "Modules", "module1,module2,...") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Plugins", "Required", "module1,module2,...") < 0) + goto fail; + + /* Clipboard configuration */ + if (IniFile_SetKeyValueString(ini, "Clipboard", "TextOnly", "false") < 0) + goto fail; + if (IniFile_SetKeyValueInt(ini, "Clipboard", "MaxTextLength", 0) < 0) + goto fail; + + /* GFX configuration */ + if (IniFile_SetKeyValueString(ini, "GFXSettings", "DecodeGFX", "false") < 0) + goto fail; + + /* Certificate configuration */ + if (IniFile_SetKeyValueString(ini, "Certificates", "CertificateFile", + " OR") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Certificates", "CertificateContent", + "") < 0) + goto fail; + + if (IniFile_SetKeyValueString(ini, "Certificates", "PrivateKeyFile", + " OR") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Certificates", "PrivateKeyContent", + "") < 0) + goto fail; + + if (IniFile_SetKeyValueString(ini, "Certificates", "RdpKeyFile", + " OR") < 0) + goto fail; + if (IniFile_SetKeyValueString(ini, "Certificates", "RdpKeyContent", + "") < 0) + goto fail; + + /* store configuration */ + if (IniFile_WriteFile(ini, file) < 0) + goto fail; + + rc = TRUE; + +fail: + IniFile_Free(ini); + return rc; +} + proxyConfig* pf_server_config_load_buffer(const char* buffer) { proxyConfig* config = NULL; diff --git a/server/proxy/pf_context.c b/server/proxy/pf_context.c index a90c0268b..99b9f9620 100644 --- a/server/proxy/pf_context.c +++ b/server/proxy/pf_context.c @@ -259,6 +259,9 @@ void proxy_data_free(proxyData* pdata) if (pdata->modules_info) HashTable_Free(pdata->modules_info); + if (pdata->pc) + freerdp_client_context_free(&pdata->pc->context); + free(pdata); } diff --git a/server/proxy/pf_server.c b/server/proxy/pf_server.c index a9e650260..10ab2d385 100644 --- a/server/proxy/pf_server.c +++ b/server/proxy/pf_server.c @@ -127,10 +127,13 @@ static BOOL pf_server_get_target_info(rdpContext* context, rdpSettings* settings case PROXY_FETCH_TARGET_METHOD_CONFIG: { WINPR_ASSERT(config); - settings->ServerPort = config->TargetPort > 0 ? 3389 : settings->ServerPort; - settings->ServerHostname = _strdup(config->TargetHost); - if (!settings->ServerHostname) + if (config->TargetPort > 0) + freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, config->TargetPort); + else + freerdp_settings_set_uint32(settings, FreeRDP_ServerPort, 3389); + + if (!freerdp_settings_set_string(settings, FreeRDP_ServerHostname, config->TargetHost)) { PROXY_LOG_ERR(TAG, ps, "strdup failed!"); return FALSE; @@ -558,16 +561,26 @@ fail: PROXY_LOG_INFO(TAG, ps, "starting shutdown of connection"); PROXY_LOG_INFO(TAG, ps, "stopping proxy's client"); - pc = (rdpContext*)pdata->pc; - freerdp_client_stop(pc); + if (pdata->client_thread) + { + if (pdata->pc) + freerdp_abort_connect(pdata->pc->context.instance); + /* + * Wait for client thread to finish. No need to call CloseHandle() here, as + * it is the responsibility of `proxy_data_free`. + */ + PROXY_LOG_DBG(TAG, pdata->pc, "waiting for client thread to finish"); + WaitForSingleObject(pdata->client_thread, INFINITE); + PROXY_LOG_DBG(TAG, pdata->pc, "thread finished"); + } pf_modules_run_hook(pdata->module, HOOK_TYPE_SERVER_SESSION_END, pdata, client); + PROXY_LOG_INFO(TAG, ps, "freeing server's channels"); pf_server_channels_free(ps, client); PROXY_LOG_INFO(TAG, ps, "freeing proxy data"); ArrayList_Remove(server->clients, pdata); proxy_data_free(pdata); - freerdp_client_context_free(pc); WINPR_ASSERT(client->Close); client->Close(client);