26#include <winpr/path.h> 
   27#include <winpr/collections.h> 
   28#include <winpr/cmdline.h> 
   31#include <freerdp/server/proxy/proxy_config.h> 
   33#include <freerdp/server/proxy/proxy_log.h> 
   35#include <freerdp/crypto/crypto.h> 
   36#include <freerdp/channels/cliprdr.h> 
   37#include <freerdp/channels/rdpsnd.h> 
   38#include <freerdp/channels/audin.h> 
   39#include <freerdp/channels/rdpdr.h> 
   40#include <freerdp/channels/disp.h> 
   41#include <freerdp/channels/rail.h> 
   42#include <freerdp/channels/rdpei.h> 
   43#include <freerdp/channels/tsmf.h> 
   44#include <freerdp/channels/video.h> 
   45#include <freerdp/channels/rdpecam.h> 
   49#define TAG PROXY_TAG("config") 
   51#define CONFIG_PRINT_SECTION(section) WLog_INFO(TAG, "\t%s:", section) 
   52#define CONFIG_PRINT_SECTION_KEY(section, key) WLog_INFO(TAG, "\t%s/%s:", section, key) 
   53#define CONFIG_PRINT_STR(config, key) WLog_INFO(TAG, "\t\t%s: %s", #key, (config)->key) 
   54#define CONFIG_PRINT_STR_CONTENT(config, key) \ 
   55  WLog_INFO(TAG, "\t\t%s: %s", #key, (config)->key ? "set" : NULL) 
   56#define CONFIG_PRINT_BOOL(config, key) WLog_INFO(TAG, "\t\t%s: %s", #key, boolstr((config)->key)) 
   57#define CONFIG_PRINT_UINT16(config, key) WLog_INFO(TAG, "\t\t%s: %" PRIu16 "", #key, (config)->key) 
   58#define CONFIG_PRINT_UINT32(config, key) WLog_INFO(TAG, "\t\t%s: %" PRIu32 "", #key, (config)->key) 
   60static const char* bool_str_true = 
"true";
 
   61static const char* bool_str_false = 
"false";
 
   62static const char* boolstr(BOOL rc)
 
   64  return rc ? bool_str_true : bool_str_false;
 
   67static const char* section_server = 
"Server";
 
   68static const char* key_host = 
"Host";
 
   69static const char* key_port = 
"Port";
 
   71static const char* section_target = 
"Target";
 
   72static const char* key_target_fixed = 
"FixedTarget";
 
   73static const char* key_target_user = 
"User";
 
   74static const char* key_target_pwd = 
"Password";
 
   75static const char* key_target_domain = 
"Domain";
 
   76static const char* key_target_tls_seclevel = 
"TlsSecLevel";
 
   78static const char* section_plugins = 
"Plugins";
 
   79static const char* key_plugins_modules = 
"Modules";
 
   80static const char* key_plugins_required = 
"Required";
 
   82static const char* section_channels = 
"Channels";
 
   83static const char* key_channels_gfx = 
"GFX";
 
   84static const char* key_channels_disp = 
"DisplayControl";
 
   85static const char* key_channels_clip = 
"Clipboard";
 
   86static const char* key_channels_mic = 
"AudioInput";
 
   87static const char* key_channels_sound = 
"AudioOutput";
 
   88static const char* key_channels_rdpdr = 
"DeviceRedirection";
 
   89static const char* key_channels_video = 
"VideoRedirection";
 
   90static const char* key_channels_camera = 
"CameraRedirection";
 
   91static const char* key_channels_rails = 
"RemoteApp";
 
   92static const char* key_channels_blacklist = 
"PassthroughIsBlacklist";
 
   93static const char* key_channels_pass = 
"Passthrough";
 
   94static const char* key_channels_intercept = 
"Intercept";
 
   96static const char* section_input = 
"Input";
 
   97static const char* key_input_kbd = 
"Keyboard";
 
   98static const char* key_input_mouse = 
"Mouse";
 
   99static const char* key_input_multitouch = 
"Multitouch";
 
  101static const char* section_security = 
"Security";
 
  102static const char* key_security_server_nla = 
"ServerNlaSecurity";
 
  103static const char* key_security_server_tls = 
"ServerTlsSecurity";
 
  104static const char* key_security_server_rdp = 
"ServerRdpSecurity";
 
  105static const char* key_security_client_nla = 
"ClientNlaSecurity";
 
  106static const char* key_security_client_tls = 
"ClientTlsSecurity";
 
  107static const char* key_security_client_rdp = 
"ClientRdpSecurity";
 
  108static const char* key_security_client_fallback = 
"ClientAllowFallbackToTls";
 
  110static const char* section_certificates = 
"Certificates";
 
  111static const char* key_private_key_file = 
"PrivateKeyFile";
 
  112static const char* key_private_key_content = 
"PrivateKeyContent";
 
  113static const char* key_cert_file = 
"CertificateFile";
 
  114static const char* key_cert_content = 
"CertificateContent";
 
  116WINPR_ATTR_MALLOC(CommandLineParserFree, 1)
 
  117static 
char** pf_config_parse_comma_separated_list(const 
char* list, 
size_t* count)
 
  122  if (strlen(list) == 0)
 
  128  return CommandLineParseCommaSeparatedValues(list, count);
 
  131static BOOL pf_config_get_uint16(wIniFile* ini, 
const char* section, 
const char* key,
 
  132                                 UINT16* result, BOOL required)
 
  135  const char* strval = NULL;
 
  137  WINPR_ASSERT(result);
 
  139  strval = IniFile_GetKeyValueString(ini, section, key);
 
  140  if (!strval && required)
 
  142    WLog_ERR(TAG, 
"key '%s.%s' does not exist.", section, key);
 
  145  val = IniFile_GetKeyValueInt(ini, section, key);
 
  146  if ((val <= 0) || (val > UINT16_MAX))
 
  148    WLog_ERR(TAG, 
"invalid value %d for key '%s.%s'.", val, section, key);
 
  152  *result = (UINT16)val;
 
  156static BOOL pf_config_get_uint32(wIniFile* ini, 
const char* section, 
const char* key,
 
  157                                 UINT32* result, BOOL required)
 
  159  WINPR_ASSERT(result);
 
  161  const char* strval = IniFile_GetKeyValueString(ini, section, key);
 
  165      WLog_ERR(TAG, 
"key '%s.%s' does not exist.", section, key);
 
  169  const int val = IniFile_GetKeyValueInt(ini, section, key);
 
  172    WLog_ERR(TAG, 
"invalid value %d for key '%s.%s'.", val, section, key);
 
  176  *result = (UINT32)val;
 
  180static BOOL pf_config_get_bool(wIniFile* ini, 
const char* section, 
const char* key, BOOL fallback)
 
  183  const char* str_value = NULL;
 
  185  str_value = IniFile_GetKeyValueString(ini, section, key);
 
  188    WLog_WARN(TAG, 
"key '%s.%s' not found, value defaults to %s.", section, key,
 
  189              fallback ? bool_str_true : bool_str_false);
 
  193  if (_stricmp(str_value, bool_str_true) == 0)
 
  195  if (_stricmp(str_value, bool_str_false) == 0)
 
  198  num_value = IniFile_GetKeyValueInt(ini, section, key);
 
  206static const char* pf_config_get_str(wIniFile* ini, 
const char* section, 
const char* key,
 
  209  const char* value = NULL;
 
  211  value = IniFile_GetKeyValueString(ini, section, key);
 
  216      WLog_ERR(TAG, 
"key '%s.%s' not found.", section, key);
 
  223static BOOL pf_config_load_server(wIniFile* ini, proxyConfig* config)
 
  225  const char* host = NULL;
 
  227  WINPR_ASSERT(config);
 
  228  host = pf_config_get_str(ini, section_server, key_host, FALSE);
 
  233  config->Host = _strdup(host);
 
  238  if (!pf_config_get_uint16(ini, section_server, key_port, &config->Port, TRUE))
 
  244static BOOL pf_config_load_target(wIniFile* ini, proxyConfig* config)
 
  246  const char* target_value = NULL;
 
  248  WINPR_ASSERT(config);
 
  249  config->FixedTarget = pf_config_get_bool(ini, section_target, key_target_fixed, FALSE);
 
  251  if (!pf_config_get_uint16(ini, section_target, key_port, &config->TargetPort,
 
  252                            config->FixedTarget))
 
  255  if (!pf_config_get_uint32(ini, section_target, key_target_tls_seclevel,
 
  256                            &config->TargetTlsSecLevel, FALSE))
 
  259  if (config->FixedTarget)
 
  261    target_value = pf_config_get_str(ini, section_target, key_host, TRUE);
 
  265    config->TargetHost = _strdup(target_value);
 
  266    if (!config->TargetHost)
 
  270  target_value = pf_config_get_str(ini, section_target, key_target_user, FALSE);
 
  273    config->TargetUser = _strdup(target_value);
 
  274    if (!config->TargetUser)
 
  278  target_value = pf_config_get_str(ini, section_target, key_target_pwd, FALSE);
 
  281    config->TargetPassword = _strdup(target_value);
 
  282    if (!config->TargetPassword)
 
  286  target_value = pf_config_get_str(ini, section_target, key_target_domain, FALSE);
 
  289    config->TargetDomain = _strdup(target_value);
 
  290    if (!config->TargetDomain)
 
  297static BOOL pf_config_load_channels(wIniFile* ini, proxyConfig* config)
 
  299  WINPR_ASSERT(config);
 
  300  config->GFX = pf_config_get_bool(ini, section_channels, key_channels_gfx, TRUE);
 
  301  config->DisplayControl = pf_config_get_bool(ini, section_channels, key_channels_disp, TRUE);
 
  302  config->Clipboard = pf_config_get_bool(ini, section_channels, key_channels_clip, FALSE);
 
  303  config->AudioOutput = pf_config_get_bool(ini, section_channels, key_channels_mic, TRUE);
 
  304  config->AudioInput = pf_config_get_bool(ini, section_channels, key_channels_sound, TRUE);
 
  305  config->DeviceRedirection = pf_config_get_bool(ini, section_channels, key_channels_rdpdr, TRUE);
 
  306  config->VideoRedirection = pf_config_get_bool(ini, section_channels, key_channels_video, TRUE);
 
  307  config->CameraRedirection =
 
  308      pf_config_get_bool(ini, section_channels, key_channels_camera, TRUE);
 
  309  config->RemoteApp = pf_config_get_bool(ini, section_channels, key_channels_rails, FALSE);
 
  310  config->PassthroughIsBlacklist =
 
  311      pf_config_get_bool(ini, section_channels, key_channels_blacklist, FALSE);
 
  312  config->Passthrough = pf_config_parse_comma_separated_list(
 
  313      pf_config_get_str(ini, section_channels, key_channels_pass, FALSE),
 
  314      &config->PassthroughCount);
 
  315  config->Intercept = pf_config_parse_comma_separated_list(
 
  316      pf_config_get_str(ini, section_channels, key_channels_intercept, FALSE),
 
  317      &config->InterceptCount);
 
  322static BOOL pf_config_load_input(wIniFile* ini, proxyConfig* config)
 
  324  WINPR_ASSERT(config);
 
  325  config->Keyboard = pf_config_get_bool(ini, section_input, key_input_kbd, TRUE);
 
  326  config->Mouse = pf_config_get_bool(ini, section_input, key_input_mouse, TRUE);
 
  327  config->Multitouch = pf_config_get_bool(ini, section_input, key_input_multitouch, TRUE);
 
  331static BOOL pf_config_load_security(wIniFile* ini, proxyConfig* config)
 
  333  WINPR_ASSERT(config);
 
  334  config->ServerTlsSecurity =
 
  335      pf_config_get_bool(ini, section_security, key_security_server_tls, TRUE);
 
  336  config->ServerNlaSecurity =
 
  337      pf_config_get_bool(ini, section_security, key_security_server_nla, FALSE);
 
  338  config->ServerRdpSecurity =
 
  339      pf_config_get_bool(ini, section_security, key_security_server_rdp, TRUE);
 
  341  config->ClientTlsSecurity =
 
  342      pf_config_get_bool(ini, section_security, key_security_client_tls, TRUE);
 
  343  config->ClientNlaSecurity =
 
  344      pf_config_get_bool(ini, section_security, key_security_client_nla, TRUE);
 
  345  config->ClientRdpSecurity =
 
  346      pf_config_get_bool(ini, section_security, key_security_client_rdp, TRUE);
 
  347  config->ClientAllowFallbackToTls =
 
  348      pf_config_get_bool(ini, section_security, key_security_client_fallback, TRUE);
 
  352static BOOL pf_config_load_modules(wIniFile* ini, proxyConfig* config)
 
  354  const char* modules_to_load = NULL;
 
  355  const char* required_modules = NULL;
 
  357  modules_to_load = pf_config_get_str(ini, section_plugins, key_plugins_modules, FALSE);
 
  358  required_modules = pf_config_get_str(ini, section_plugins, key_plugins_required, FALSE);
 
  360  WINPR_ASSERT(config);
 
  361  config->Modules = pf_config_parse_comma_separated_list(modules_to_load, &config->ModulesCount);
 
  363  config->RequiredPlugins =
 
  364      pf_config_parse_comma_separated_list(required_modules, &config->RequiredPluginsCount);
 
  368static char* pf_config_decode_base64(
const char* data, 
const char* name, 
size_t* pLength)
 
  370  const char* headers[] = { 
"-----BEGIN PUBLIC KEY-----", 
"-----BEGIN RSA PUBLIC KEY-----",
 
  371                          "-----BEGIN CERTIFICATE-----", 
"-----BEGIN PRIVATE KEY-----",
 
  372                          "-----BEGIN RSA PRIVATE KEY-----" };
 
  374  size_t decoded_length = 0;
 
  375  char* decoded = NULL;
 
  378    WLog_ERR(TAG, 
"Invalid base64 data [%p] for %s", data, name);
 
  383  WINPR_ASSERT(pLength);
 
  385  const size_t length = strlen(data);
 
  387  if (strncmp(data, 
"-----", 5) == 0)
 
  389    BOOL expected = FALSE;
 
  390    for (
size_t x = 0; x < ARRAYSIZE(headers); x++)
 
  392      const char* header = headers[x];
 
  394      if (strncmp(data, header, strlen(header)) == 0)
 
  403      char hdr[128] = { 0 };
 
  404      const char* end = strchr(&data[5], 
'-');
 
  410        const size_t s = MIN(ARRAYSIZE(hdr) - 1ULL, (
size_t)(end - data));
 
  411        memcpy(hdr, data, s);
 
  414      WLog_WARN(TAG, 
"PEM has unexpected header '%s'. Known supported headers are:", hdr);
 
  415      for (
size_t x = 0; x < ARRAYSIZE(headers); x++)
 
  417        const char* header = headers[x];
 
  418        WLog_WARN(TAG, 
"%s", header);
 
  422    *pLength = length + 1;
 
  423    return _strdup(data);
 
  426  crypto_base64_decode(data, length, (BYTE**)&decoded, &decoded_length);
 
  427  if (!decoded || decoded_length == 0)
 
  429    WLog_ERR(TAG, 
"Failed to decode base64 data of length %" PRIuz 
" for %s", length, name);
 
  434  *pLength = strnlen(decoded, decoded_length) + 1;
 
  438static BOOL pf_config_load_certificates(wIniFile* ini, proxyConfig* config)
 
  440  const char* tmp1 = NULL;
 
  441  const char* tmp2 = NULL;
 
  444  WINPR_ASSERT(config);
 
  446  tmp1 = pf_config_get_str(ini, section_certificates, key_cert_file, FALSE);
 
  449    if (!winpr_PathFileExists(tmp1))
 
  451      WLog_ERR(TAG, 
"%s/%s file %s does not exist", section_certificates, key_cert_file,
 
  455    config->CertificateFile = _strdup(tmp1);
 
  456    config->CertificatePEM =
 
  457        crypto_read_pem(config->CertificateFile, &config->CertificatePEMLength);
 
  458    if (!config->CertificatePEM)
 
  460    config->CertificatePEMLength += 1;
 
  462  tmp2 = pf_config_get_str(ini, section_certificates, key_cert_content, FALSE);
 
  465    if (strlen(tmp2) < 1)
 
  467      WLog_ERR(TAG, 
"%s/%s has invalid empty value", section_certificates, key_cert_content);
 
  470    config->CertificateContent = _strdup(tmp2);
 
  471    config->CertificatePEM = pf_config_decode_base64(
 
  472        config->CertificateContent, 
"CertificateContent", &config->CertificatePEMLength);
 
  473    if (!config->CertificatePEM)
 
  479             "%s/%s and %s/%s are " 
  480             "mutually exclusive options",
 
  481             section_certificates, key_cert_file, section_certificates, key_cert_content);
 
  484  else if (!tmp1 && !tmp2)
 
  487             "%s/%s or %s/%s are " 
  489             section_certificates, key_cert_file, section_certificates, key_cert_content);
 
  493  tmp1 = pf_config_get_str(ini, section_certificates, key_private_key_file, FALSE);
 
  496    if (!winpr_PathFileExists(tmp1))
 
  498      WLog_ERR(TAG, 
"%s/%s file %s does not exist", section_certificates,
 
  499               key_private_key_file, tmp1);
 
  502    config->PrivateKeyFile = _strdup(tmp1);
 
  503    config->PrivateKeyPEM =
 
  504        crypto_read_pem(config->PrivateKeyFile, &config->PrivateKeyPEMLength);
 
  505    if (!config->PrivateKeyPEM)
 
  507    config->PrivateKeyPEMLength += 1;
 
  509  tmp2 = pf_config_get_str(ini, section_certificates, key_private_key_content, FALSE);
 
  512    if (strlen(tmp2) < 1)
 
  514      WLog_ERR(TAG, 
"%s/%s has invalid empty value", section_certificates,
 
  515               key_private_key_content);
 
  518    config->PrivateKeyContent = _strdup(tmp2);
 
  519    config->PrivateKeyPEM = pf_config_decode_base64(
 
  520        config->PrivateKeyContent, 
"PrivateKeyContent", &config->PrivateKeyPEMLength);
 
  521    if (!config->PrivateKeyPEM)
 
  528             "%s/%s and %s/%s are " 
  529             "mutually exclusive options",
 
  530             section_certificates, key_private_key_file, section_certificates,
 
  531             key_private_key_content);
 
  534  else if (!tmp1 && !tmp2)
 
  537             "%s/%s or %s/%s are " 
  538             "are required settings",
 
  539             section_certificates, key_private_key_file, section_certificates,
 
  540             key_private_key_content);
 
  549  proxyConfig* config = NULL;
 
  553  config = calloc(1, 
sizeof(proxyConfig));
 
  557    config->TargetTlsSecLevel = 1;
 
  560    if (!pf_config_load_server(ini, config))
 
  563    if (!pf_config_load_target(ini, config))
 
  566    if (!pf_config_load_channels(ini, config))
 
  569    if (!pf_config_load_input(ini, config))
 
  572    if (!pf_config_load_security(ini, config))
 
  575    if (!pf_config_load_modules(ini, config))
 
  578    if (!pf_config_load_certificates(ini, config))
 
  580    config->ini = IniFile_Clone(ini);
 
  586  WINPR_PRAGMA_DIAG_PUSH
 
  587  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
 
  589  WINPR_PRAGMA_DIAG_POP
 
 
  597  wIniFile* ini = IniFile_New();
 
  602  if (IniFile_SetKeyValueString(ini, section_server, key_host, 
"0.0.0.0") < 0)
 
  604  if (IniFile_SetKeyValueInt(ini, section_server, key_port, 3389) < 0)
 
  608  if (IniFile_SetKeyValueString(ini, section_target, key_host, 
"somehost.example.com") < 0)
 
  610  if (IniFile_SetKeyValueInt(ini, section_target, key_port, 3389) < 0)
 
  612  if (IniFile_SetKeyValueString(ini, section_target, key_target_fixed, bool_str_true) < 0)
 
  614  if (IniFile_SetKeyValueInt(ini, section_target, key_target_tls_seclevel, 1) < 0)
 
  618  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_gfx, bool_str_true) < 0)
 
  620  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_disp, bool_str_true) < 0)
 
  622  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_clip, bool_str_true) < 0)
 
  624  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_mic, bool_str_true) < 0)
 
  626  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_sound, bool_str_true) < 0)
 
  628  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_rdpdr, bool_str_true) < 0)
 
  630  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_video, bool_str_true) < 0)
 
  632  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_camera, bool_str_true) < 0)
 
  634  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_rails, bool_str_false) < 0)
 
  637  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_blacklist, bool_str_true) < 0)
 
  639  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_pass, 
"") < 0)
 
  641  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_intercept, 
"") < 0)
 
  645  if (IniFile_SetKeyValueString(ini, section_input, key_input_kbd, bool_str_true) < 0)
 
  647  if (IniFile_SetKeyValueString(ini, section_input, key_input_mouse, bool_str_true) < 0)
 
  649  if (IniFile_SetKeyValueString(ini, section_input, key_input_multitouch, bool_str_true) < 0)
 
  653  if (IniFile_SetKeyValueString(ini, section_security, key_security_server_tls, bool_str_true) <
 
  656  if (IniFile_SetKeyValueString(ini, section_security, key_security_server_nla, bool_str_false) <
 
  659  if (IniFile_SetKeyValueString(ini, section_security, key_security_server_rdp, bool_str_true) <
 
  663  if (IniFile_SetKeyValueString(ini, section_security, key_security_client_tls, bool_str_true) <
 
  666  if (IniFile_SetKeyValueString(ini, section_security, key_security_client_nla, bool_str_true) <
 
  669  if (IniFile_SetKeyValueString(ini, section_security, key_security_client_rdp, bool_str_true) <
 
  672  if (IniFile_SetKeyValueString(ini, section_security, key_security_client_fallback,
 
  677  if (IniFile_SetKeyValueString(ini, section_plugins, key_plugins_modules,
 
  678                                "module1,module2,...") < 0)
 
  680  if (IniFile_SetKeyValueString(ini, section_plugins, key_plugins_required,
 
  681                                "module1,module2,...") < 0)
 
  685  if (IniFile_SetKeyValueString(ini, section_certificates, key_cert_file,
 
  686                                "<absolute path to some certificate file> OR") < 0)
 
  688  if (IniFile_SetKeyValueString(ini, section_certificates, key_cert_content,
 
  689                                "<Contents of some certificate file in PEM format>") < 0)
 
  692  if (IniFile_SetKeyValueString(ini, section_certificates, key_private_key_file,
 
  693                                "<absolute path to some private key file> OR") < 0)
 
  695  if (IniFile_SetKeyValueString(ini, section_certificates, key_private_key_content,
 
  696                                "<Contents of some private key file in PEM format>") < 0)
 
  700  if (IniFile_WriteFile(ini, file) < 0)
 
 
  712  proxyConfig* config = NULL;
 
  713  wIniFile* ini = NULL;
 
  719    WLog_ERR(TAG, 
"IniFile_New() failed!");
 
  723  if (IniFile_ReadBuffer(ini, buffer) < 0)
 
  725    WLog_ERR(TAG, 
"failed to parse ini: '%s'", buffer);
 
 
  737  proxyConfig* config = NULL;
 
  738  wIniFile* ini = IniFile_New();
 
  742    WLog_ERR(TAG, 
"IniFile_New() failed!");
 
  746  if (IniFile_ReadFile(ini, path) < 0)
 
  748    WLog_ERR(TAG, 
"failed to parse ini file: '%s'", path);
 
 
  758static void pf_server_config_print_list(
char** list, 
size_t count)
 
  761  for (
size_t i = 0; i < count; i++)
 
  762    WLog_INFO(TAG, 
"\t\t- %s", list[i]);
 
  767  WINPR_ASSERT(config);
 
  768  WLog_INFO(TAG, 
"Proxy configuration:");
 
  770  CONFIG_PRINT_SECTION(section_server);
 
  771  CONFIG_PRINT_STR(config, Host);
 
  772  CONFIG_PRINT_UINT16(config, Port);
 
  774  if (config->FixedTarget)
 
  776    CONFIG_PRINT_SECTION(section_target);
 
  777    CONFIG_PRINT_STR(config, TargetHost);
 
  778    CONFIG_PRINT_UINT16(config, TargetPort);
 
  779    CONFIG_PRINT_UINT32(config, TargetTlsSecLevel);
 
  781    if (config->TargetUser)
 
  782      CONFIG_PRINT_STR(config, TargetUser);
 
  783    if (config->TargetDomain)
 
  784      CONFIG_PRINT_STR(config, TargetDomain);
 
  787  CONFIG_PRINT_SECTION(section_input);
 
  788  CONFIG_PRINT_BOOL(config, Keyboard);
 
  789  CONFIG_PRINT_BOOL(config, Mouse);
 
  790  CONFIG_PRINT_BOOL(config, Multitouch);
 
  792  CONFIG_PRINT_SECTION(section_security);
 
  793  CONFIG_PRINT_BOOL(config, ServerNlaSecurity);
 
  794  CONFIG_PRINT_BOOL(config, ServerTlsSecurity);
 
  795  CONFIG_PRINT_BOOL(config, ServerRdpSecurity);
 
  796  CONFIG_PRINT_BOOL(config, ClientNlaSecurity);
 
  797  CONFIG_PRINT_BOOL(config, ClientTlsSecurity);
 
  798  CONFIG_PRINT_BOOL(config, ClientRdpSecurity);
 
  799  CONFIG_PRINT_BOOL(config, ClientAllowFallbackToTls);
 
  801  CONFIG_PRINT_SECTION(section_channels);
 
  802  CONFIG_PRINT_BOOL(config, GFX);
 
  803  CONFIG_PRINT_BOOL(config, DisplayControl);
 
  804  CONFIG_PRINT_BOOL(config, Clipboard);
 
  805  CONFIG_PRINT_BOOL(config, AudioOutput);
 
  806  CONFIG_PRINT_BOOL(config, AudioInput);
 
  807  CONFIG_PRINT_BOOL(config, DeviceRedirection);
 
  808  CONFIG_PRINT_BOOL(config, VideoRedirection);
 
  809  CONFIG_PRINT_BOOL(config, CameraRedirection);
 
  810  CONFIG_PRINT_BOOL(config, RemoteApp);
 
  811  CONFIG_PRINT_BOOL(config, PassthroughIsBlacklist);
 
  813  if (config->PassthroughCount)
 
  815    WLog_INFO(TAG, 
"\tStatic Channels Proxy:");
 
  816    pf_server_config_print_list(config->Passthrough, config->PassthroughCount);
 
  819  if (config->InterceptCount)
 
  821    WLog_INFO(TAG, 
"\tStatic Channels Proxy-Intercept:");
 
  822    pf_server_config_print_list(config->Intercept, config->InterceptCount);
 
  826  CONFIG_PRINT_SECTION_KEY(section_plugins, key_plugins_modules);
 
  827  for (
size_t x = 0; x < config->ModulesCount; x++)
 
  828    CONFIG_PRINT_STR(config, Modules[x]);
 
  831  CONFIG_PRINT_SECTION_KEY(section_plugins, key_plugins_required);
 
  832  for (
size_t x = 0; x < config->RequiredPluginsCount; x++)
 
  833    CONFIG_PRINT_STR(config, RequiredPlugins[x]);
 
  835  CONFIG_PRINT_SECTION(section_certificates);
 
  836  CONFIG_PRINT_STR(config, CertificateFile);
 
  837  CONFIG_PRINT_STR_CONTENT(config, CertificateContent);
 
  838  CONFIG_PRINT_STR(config, PrivateKeyFile);
 
  839  CONFIG_PRINT_STR_CONTENT(config, PrivateKeyContent);
 
 
  847  CommandLineParserFree(config->Passthrough);
 
  848  CommandLineParserFree(config->Intercept);
 
  849  CommandLineParserFree(config->RequiredPlugins);
 
  850  CommandLineParserFree(config->Modules);
 
  851  free(config->TargetHost);
 
  853  free(config->CertificateFile);
 
  854  free(config->CertificateContent);
 
  855  if (config->CertificatePEM)
 
  856    memset(config->CertificatePEM, 0, config->CertificatePEMLength);
 
  857  free(config->CertificatePEM);
 
  858  free(config->PrivateKeyFile);
 
  859  free(config->PrivateKeyContent);
 
  860  if (config->PrivateKeyPEM)
 
  861    memset(config->PrivateKeyPEM, 0, config->PrivateKeyPEMLength);
 
  862  free(config->PrivateKeyPEM);
 
  863  IniFile_Free(config->ini);
 
 
  869  WINPR_ASSERT(config);
 
  870  return config->RequiredPluginsCount;
 
 
  875  WINPR_ASSERT(config);
 
  876  if (index >= config->RequiredPluginsCount)
 
  879  return config->RequiredPlugins[index];
 
 
  884  WINPR_ASSERT(config);
 
  885  return config->ModulesCount;
 
 
  896  WINPR_ASSERT(config);
 
  898  cnv.ppc = config->Modules;
 
 
  902static BOOL pf_config_copy_string(
char** dst, 
const char* src)
 
  910static BOOL pf_config_copy_string_n(
char** dst, 
const char* src, 
size_t size)
 
  914  if (src && (size > 0))
 
  916    WINPR_ASSERT(strnlen(src, size) == size - 1);
 
  917    *dst = calloc(size, 
sizeof(
char));
 
  920    memcpy(*dst, src, size);
 
  926static BOOL pf_config_copy_string_list(
char*** dst, 
size_t* size, 
char** src, 
size_t srcSize)
 
  930  WINPR_ASSERT(src || (srcSize == 0));
 
  934  if (srcSize > INT32_MAX)
 
  939    char* csv = CommandLineToCommaSeparatedValues((INT32)srcSize, src);
 
  940    *dst = CommandLineParseCommaSeparatedValues(csv, size);
 
  949  proxyConfig* tmp = calloc(1, 
sizeof(proxyConfig));
 
  952  WINPR_ASSERT(config);
 
  959  if (!pf_config_copy_string(&tmp->Host, config->Host))
 
  961  if (!pf_config_copy_string(&tmp->TargetHost, config->TargetHost))
 
  964  if (!pf_config_copy_string_list(&tmp->Passthrough, &tmp->PassthroughCount, config->Passthrough,
 
  965                                  config->PassthroughCount))
 
  967  if (!pf_config_copy_string_list(&tmp->Intercept, &tmp->InterceptCount, config->Intercept,
 
  968                                  config->InterceptCount))
 
  970  if (!pf_config_copy_string_list(&tmp->Modules, &tmp->ModulesCount, config->Modules,
 
  971                                  config->ModulesCount))
 
  973  if (!pf_config_copy_string_list(&tmp->RequiredPlugins, &tmp->RequiredPluginsCount,
 
  974                                  config->RequiredPlugins, config->RequiredPluginsCount))
 
  976  if (!pf_config_copy_string(&tmp->CertificateFile, config->CertificateFile))
 
  978  if (!pf_config_copy_string(&tmp->CertificateContent, config->CertificateContent))
 
  980  if (!pf_config_copy_string_n(&tmp->CertificatePEM, config->CertificatePEM,
 
  981                               config->CertificatePEMLength))
 
  983  if (!pf_config_copy_string(&tmp->PrivateKeyFile, config->PrivateKeyFile))
 
  985  if (!pf_config_copy_string(&tmp->PrivateKeyContent, config->PrivateKeyContent))
 
  987  if (!pf_config_copy_string_n(&tmp->PrivateKeyPEM, config->PrivateKeyPEM,
 
  988                               config->PrivateKeyPEMLength))
 
  991  tmp->ini = IniFile_Clone(config->ini);
 
  999  WINPR_PRAGMA_DIAG_PUSH
 
 1000  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
 
 1002  WINPR_PRAGMA_DIAG_POP
 
 
 1006struct config_plugin_data
 
 1008  proxyPluginsManager* mgr;
 
 1009  const proxyConfig* config;
 
 1012static const char config_plugin_name[] = 
"config";
 
 1013static const char config_plugin_desc[] =
 
 1014    "A plugin filtering according to proxy configuration file rules";
 
 1016static BOOL config_plugin_unload(proxyPlugin* plugin)
 
 1018  WINPR_ASSERT(plugin);
 
 1023    free(plugin->custom);
 
 1024    plugin->custom = NULL;
 
 1030static BOOL config_plugin_keyboard_event(proxyPlugin* plugin, WINPR_ATTR_UNUSED proxyData* pdata,
 
 1034  const struct config_plugin_data* custom = NULL;
 
 1035  const proxyConfig* cfg = NULL;
 
 1038  WINPR_ASSERT(plugin);
 
 1039  WINPR_ASSERT(pdata);
 
 1040  WINPR_ASSERT(event_data);
 
 1042  WINPR_UNUSED(event_data);
 
 1044  custom = plugin->custom;
 
 1045  WINPR_ASSERT(custom);
 
 1047  cfg = custom->config;
 
 1051  WLog_DBG(TAG, 
"%s", boolstr(rc));
 
 1055static BOOL config_plugin_unicode_event(proxyPlugin* plugin, WINPR_ATTR_UNUSED proxyData* pdata,
 
 1059  const struct config_plugin_data* custom = NULL;
 
 1060  const proxyConfig* cfg = NULL;
 
 1063  WINPR_ASSERT(plugin);
 
 1064  WINPR_ASSERT(pdata);
 
 1065  WINPR_ASSERT(event_data);
 
 1067  WINPR_UNUSED(event_data);
 
 1069  custom = plugin->custom;
 
 1070  WINPR_ASSERT(custom);
 
 1072  cfg = custom->config;
 
 1076  WLog_DBG(TAG, 
"%s", boolstr(rc));
 
 1080static BOOL config_plugin_mouse_event(proxyPlugin* plugin, WINPR_ATTR_UNUSED proxyData* pdata,
 
 1084  const struct config_plugin_data* custom = NULL;
 
 1085  const proxyConfig* cfg = NULL;
 
 1088  WINPR_ASSERT(plugin);
 
 1089  WINPR_ASSERT(pdata);
 
 1090  WINPR_ASSERT(event_data);
 
 1092  WINPR_UNUSED(event_data);
 
 1094  custom = plugin->custom;
 
 1095  WINPR_ASSERT(custom);
 
 1097  cfg = custom->config;
 
 1104static BOOL config_plugin_mouse_ex_event(proxyPlugin* plugin, WINPR_ATTR_UNUSED proxyData* pdata,
 
 1108  const struct config_plugin_data* custom = NULL;
 
 1109  const proxyConfig* cfg = NULL;
 
 1112  WINPR_ASSERT(plugin);
 
 1113  WINPR_ASSERT(pdata);
 
 1114  WINPR_ASSERT(event_data);
 
 1116  WINPR_UNUSED(event_data);
 
 1118  custom = plugin->custom;
 
 1119  WINPR_ASSERT(custom);
 
 1121  cfg = custom->config;
 
 1128static BOOL config_plugin_client_channel_data(WINPR_ATTR_UNUSED proxyPlugin* plugin,
 
 1129                                              WINPR_ATTR_UNUSED proxyData* pdata, 
void* param)
 
 1133  WINPR_ASSERT(plugin);
 
 1134  WINPR_ASSERT(pdata);
 
 1135  WINPR_ASSERT(channel);
 
 1137  WLog_DBG(TAG, 
"%s [0x%04" PRIx16 
"] got %" PRIuz, channel->channel_name, channel->channel_id,
 
 1142static BOOL config_plugin_server_channel_data(WINPR_ATTR_UNUSED proxyPlugin* plugin,
 
 1143                                              WINPR_ATTR_UNUSED proxyData* pdata, 
void* param)
 
 1147  WINPR_ASSERT(plugin);
 
 1148  WINPR_ASSERT(pdata);
 
 1149  WINPR_ASSERT(channel);
 
 1151  WLog_DBG(TAG, 
"%s [0x%04" PRIx16 
"] got %" PRIuz, channel->channel_name, channel->channel_id,
 
 1156static BOOL config_plugin_dynamic_channel_create(proxyPlugin* plugin,
 
 1157                                                 WINPR_ATTR_UNUSED proxyData* pdata, 
void* param)
 
 1162  WINPR_ASSERT(plugin);
 
 1163  WINPR_ASSERT(pdata);
 
 1164  WINPR_ASSERT(channel);
 
 1166  const struct config_plugin_data* custom = plugin->custom;
 
 1167  WINPR_ASSERT(custom);
 
 1169  const proxyConfig* cfg = custom->config;
 
 1172  pf_utils_channel_mode rc = pf_utils_get_channel_mode(cfg, channel->channel_name);
 
 1176    case PF_UTILS_CHANNEL_INTERCEPT:
 
 1177    case PF_UTILS_CHANNEL_PASSTHROUGH:
 
 1180    case PF_UTILS_CHANNEL_BLOCK:
 
 1188    if (strncmp(RDPGFX_DVC_CHANNEL_NAME, channel->channel_name,
 
 1189                sizeof(RDPGFX_DVC_CHANNEL_NAME)) == 0)
 
 1191    else if (strncmp(RDPSND_DVC_CHANNEL_NAME, channel->channel_name,
 
 1192                     sizeof(RDPSND_DVC_CHANNEL_NAME)) == 0)
 
 1193      accept = cfg->AudioOutput;
 
 1194    else if (strncmp(RDPSND_LOSSY_DVC_CHANNEL_NAME, channel->channel_name,
 
 1195                     sizeof(RDPSND_LOSSY_DVC_CHANNEL_NAME)) == 0)
 
 1196      accept = cfg->AudioOutput;
 
 1197    else if (strncmp(AUDIN_DVC_CHANNEL_NAME, channel->channel_name,
 
 1198                     sizeof(AUDIN_DVC_CHANNEL_NAME)) == 0)
 
 1199      accept = cfg->AudioInput;
 
 1200    else if (strncmp(RDPEI_DVC_CHANNEL_NAME, channel->channel_name,
 
 1201                     sizeof(RDPEI_DVC_CHANNEL_NAME)) == 0)
 
 1202      accept = cfg->Multitouch;
 
 1203    else if (strncmp(TSMF_DVC_CHANNEL_NAME, channel->channel_name,
 
 1204                     sizeof(TSMF_DVC_CHANNEL_NAME)) == 0)
 
 1205      accept = cfg->VideoRedirection;
 
 1206    else if (strncmp(VIDEO_CONTROL_DVC_CHANNEL_NAME, channel->channel_name,
 
 1207                     sizeof(VIDEO_CONTROL_DVC_CHANNEL_NAME)) == 0)
 
 1208      accept = cfg->VideoRedirection;
 
 1209    else if (strncmp(VIDEO_DATA_DVC_CHANNEL_NAME, channel->channel_name,
 
 1210                     sizeof(VIDEO_DATA_DVC_CHANNEL_NAME)) == 0)
 
 1211      accept = cfg->VideoRedirection;
 
 1212    else if (strncmp(RDPECAM_DVC_CHANNEL_NAME, channel->channel_name,
 
 1213                     sizeof(RDPECAM_DVC_CHANNEL_NAME)) == 0)
 
 1214      accept = cfg->CameraRedirection;
 
 1217  WLog_DBG(TAG, 
"%s [0x%04" PRIx16 
"]: %s", channel->channel_name, channel->channel_id,
 
 1222static BOOL config_plugin_channel_create(proxyPlugin* plugin, WINPR_ATTR_UNUSED proxyData* pdata,
 
 1228  WINPR_ASSERT(plugin);
 
 1229  WINPR_ASSERT(pdata);
 
 1230  WINPR_ASSERT(channel);
 
 1232  const struct config_plugin_data* custom = plugin->custom;
 
 1233  WINPR_ASSERT(custom);
 
 1235  const proxyConfig* cfg = custom->config;
 
 1238  pf_utils_channel_mode rc = pf_utils_get_channel_mode(cfg, channel->channel_name);
 
 1241    case PF_UTILS_CHANNEL_INTERCEPT:
 
 1242    case PF_UTILS_CHANNEL_PASSTHROUGH:
 
 1245    case PF_UTILS_CHANNEL_BLOCK:
 
 1252    if (strncmp(CLIPRDR_SVC_CHANNEL_NAME, channel->channel_name,
 
 1253                sizeof(CLIPRDR_SVC_CHANNEL_NAME)) == 0)
 
 1254      accept = cfg->Clipboard;
 
 1255    else if (strncmp(RDPSND_CHANNEL_NAME, channel->channel_name, 
sizeof(RDPSND_CHANNEL_NAME)) ==
 
 1257      accept = cfg->AudioOutput;
 
 1258    else if (strncmp(RDPDR_SVC_CHANNEL_NAME, channel->channel_name,
 
 1259                     sizeof(RDPDR_SVC_CHANNEL_NAME)) == 0)
 
 1260      accept = cfg->DeviceRedirection;
 
 1261    else if (strncmp(DISP_DVC_CHANNEL_NAME, channel->channel_name,
 
 1262                     sizeof(DISP_DVC_CHANNEL_NAME)) == 0)
 
 1263      accept = cfg->DisplayControl;
 
 1264    else if (strncmp(RAIL_SVC_CHANNEL_NAME, channel->channel_name,
 
 1265                     sizeof(RAIL_SVC_CHANNEL_NAME)) == 0)
 
 1266      accept = cfg->RemoteApp;
 
 1269  WLog_DBG(TAG, 
"%s [static]: %s", channel->channel_name, boolstr(accept));
 
 1275  struct config_plugin_data* custom = NULL;
 
 1276  proxyPlugin plugin = { 0 };
 
 1278  plugin.name = config_plugin_name;
 
 1279  plugin.description = config_plugin_desc;
 
 1280  plugin.PluginUnload = config_plugin_unload;
 
 1282  plugin.KeyboardEvent = config_plugin_keyboard_event;
 
 1283  plugin.UnicodeEvent = config_plugin_unicode_event;
 
 1284  plugin.MouseEvent = config_plugin_mouse_event;
 
 1285  plugin.MouseExEvent = config_plugin_mouse_ex_event;
 
 1286  plugin.ClientChannelData = config_plugin_client_channel_data;
 
 1287  plugin.ServerChannelData = config_plugin_server_channel_data;
 
 1288  plugin.ChannelCreate = config_plugin_channel_create;
 
 1289  plugin.DynamicChannelCreate = config_plugin_dynamic_channel_create;
 
 1290  plugin.userdata = userdata;
 
 1292  custom = calloc(1, 
sizeof(
struct config_plugin_data));
 
 1296  custom->mgr = plugins_manager;
 
 1297  custom->config = userdata;
 
 1299  plugin.custom = custom;
 
 1300  plugin.userdata = userdata;
 
 1302  return plugins_manager->RegisterPlugin(plugins_manager, &plugin);
 
 
 1305const char* 
pf_config_get(
const proxyConfig* config, 
const char* section, 
const char* key)
 
 1307  WINPR_ASSERT(config);
 
 1308  WINPR_ASSERT(config->ini);
 
 1309  WINPR_ASSERT(section);
 
 1312  return IniFile_GetKeyValueString(config->ini, section, key);
 
 
proxyConfig * pf_server_config_load_buffer(const char *buffer)
pf_server_config_load_buffer Create a proxyConfig from a memory string buffer in INI file format
 
void pf_server_config_free(proxyConfig *config)
pf_server_config_free Releases all resources associated with proxyConfig
 
void pf_server_config_print(const proxyConfig *config)
pf_server_config_print Print the configuration to stdout
 
BOOL pf_config_clone(proxyConfig **dst, const proxyConfig *config)
pf_config_clone Create a copy of the configuration
 
BOOL pf_server_config_dump(const char *file)
pf_server_config_dump Dumps a default INI configuration file
 
const char * pf_config_get(const proxyConfig *config, const char *section, const char *key)
pf_config_get get a value for a section/key
 
proxyConfig * server_config_load_ini(wIniFile *ini)
server_config_load_ini Create a proxyConfig from a already loaded INI file.
 
size_t pf_config_required_plugins_count(const proxyConfig *config)
pf_config_required_plugins_count
 
proxyConfig * pf_server_config_load_file(const char *path)
pf_server_config_load_file Create a proxyConfig from a INI file found at path.
 
const char ** pf_config_modules(const proxyConfig *config)
pf_config_modules
 
BOOL pf_config_plugin(proxyPluginsManager *plugins_manager, void *userdata)
pf_config_plugin Register a proxy plugin handling event filtering defined in the configuration.
 
const char * pf_config_required_plugin(const proxyConfig *config, size_t index)
pf_config_required_plugin
 
size_t pf_config_modules_count(const proxyConfig *config)
pf_config_modules_count