FreeRDP
pf_config.c
1 
23 #include <stdio.h>
24 #include <string.h>
25 #include <winpr/crt.h>
26 #include <winpr/path.h>
27 #include <winpr/collections.h>
28 #include <winpr/cmdline.h>
29 
30 #include "pf_server.h"
31 #include <freerdp/server/proxy/proxy_config.h>
32 
33 #include <freerdp/server/proxy/proxy_log.h>
34 
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>
46 
47 #include "pf_utils.h"
48 
49 #define TAG PROXY_TAG("config")
50 
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)
59 
60 static const char* bool_str_true = "true";
61 static const char* bool_str_false = "false";
62 static const char* boolstr(BOOL rc)
63 {
64  return rc ? bool_str_true : bool_str_false;
65 }
66 
67 static const char* section_server = "Server";
68 static const char* key_host = "Host";
69 static const char* key_port = "Port";
70 
71 static const char* section_target = "Target";
72 static const char* key_target_fixed = "FixedTarget";
73 static const char* key_target_user = "User";
74 static const char* key_target_pwd = "Password";
75 static const char* key_target_domain = "Domain";
76 static const char* key_target_tls_seclevel = "TlsSecLevel";
77 
78 static const char* section_plugins = "Plugins";
79 static const char* key_plugins_modules = "Modules";
80 static const char* key_plugins_required = "Required";
81 
82 static const char* section_channels = "Channels";
83 static const char* key_channels_gfx = "GFX";
84 static const char* key_channels_disp = "DisplayControl";
85 static const char* key_channels_clip = "Clipboard";
86 static const char* key_channels_mic = "AudioInput";
87 static const char* key_channels_sound = "AudioOutput";
88 static const char* key_channels_rdpdr = "DeviceRedirection";
89 static const char* key_channels_video = "VideoRedirection";
90 static const char* key_channels_camera = "CameraRedirection";
91 static const char* key_channels_rails = "RemoteApp";
92 static const char* key_channels_blacklist = "PassthroughIsBlacklist";
93 static const char* key_channels_pass = "Passthrough";
94 static const char* key_channels_intercept = "Intercept";
95 
96 static const char* section_input = "Input";
97 static const char* key_input_kbd = "Keyboard";
98 static const char* key_input_mouse = "Mouse";
99 static const char* key_input_multitouch = "Multitouch";
100 
101 static const char* section_security = "Security";
102 static const char* key_security_server_nla = "ServerNlaSecurity";
103 static const char* key_security_server_tls = "ServerTlsSecurity";
104 static const char* key_security_server_rdp = "ServerRdpSecurity";
105 static const char* key_security_client_nla = "ClientNlaSecurity";
106 static const char* key_security_client_tls = "ClientTlsSecurity";
107 static const char* key_security_client_rdp = "ClientRdpSecurity";
108 static const char* key_security_client_fallback = "ClientAllowFallbackToTls";
109 
110 static const char* section_certificates = "Certificates";
111 static const char* key_private_key_file = "PrivateKeyFile";
112 static const char* key_private_key_content = "PrivateKeyContent";
113 static const char* key_cert_file = "CertificateFile";
114 static const char* key_cert_content = "CertificateContent";
115 
116 WINPR_ATTR_MALLOC(CommandLineParserFree, 1)
117 static char** pf_config_parse_comma_separated_list(const char* list, size_t* count)
118 {
119  if (!list || !count)
120  return NULL;
121 
122  if (strlen(list) == 0)
123  {
124  *count = 0;
125  return NULL;
126  }
127 
128  return CommandLineParseCommaSeparatedValues(list, count);
129 }
130 
131 static BOOL pf_config_get_uint16(wIniFile* ini, const char* section, const char* key,
132  UINT16* result, BOOL required)
133 {
134  int val = 0;
135  const char* strval = NULL;
136 
137  WINPR_ASSERT(result);
138 
139  strval = IniFile_GetKeyValueString(ini, section, key);
140  if (!strval && required)
141  {
142  WLog_ERR(TAG, "key '%s.%s' does not exist.", section, key);
143  return FALSE;
144  }
145  val = IniFile_GetKeyValueInt(ini, section, key);
146  if ((val <= 0) || (val > UINT16_MAX))
147  {
148  WLog_ERR(TAG, "invalid value %d for key '%s.%s'.", val, section, key);
149  return FALSE;
150  }
151 
152  *result = (UINT16)val;
153  return TRUE;
154 }
155 
156 static BOOL pf_config_get_uint32(wIniFile* ini, const char* section, const char* key,
157  UINT32* result, BOOL required)
158 {
159  WINPR_ASSERT(result);
160 
161  const char* strval = IniFile_GetKeyValueString(ini, section, key);
162  if (!strval)
163  {
164  if (required)
165  WLog_ERR(TAG, "key '%s.%s' does not exist.", section, key);
166  return !required;
167  }
168 
169  const int val = IniFile_GetKeyValueInt(ini, section, key);
170  if (val < 0)
171  {
172  WLog_ERR(TAG, "invalid value %d for key '%s.%s'.", val, section, key);
173  return FALSE;
174  }
175 
176  *result = (UINT32)val;
177  return TRUE;
178 }
179 
180 static BOOL pf_config_get_bool(wIniFile* ini, const char* section, const char* key, BOOL fallback)
181 {
182  int num_value = 0;
183  const char* str_value = NULL;
184 
185  str_value = IniFile_GetKeyValueString(ini, section, key);
186  if (!str_value)
187  {
188  WLog_WARN(TAG, "key '%s.%s' not found, value defaults to %s.", section, key,
189  fallback ? bool_str_true : bool_str_false);
190  return fallback;
191  }
192 
193  if (_stricmp(str_value, bool_str_true) == 0)
194  return TRUE;
195  if (_stricmp(str_value, bool_str_false) == 0)
196  return FALSE;
197 
198  num_value = IniFile_GetKeyValueInt(ini, section, key);
199 
200  if (num_value != 0)
201  return TRUE;
202 
203  return FALSE;
204 }
205 
206 static const char* pf_config_get_str(wIniFile* ini, const char* section, const char* key,
207  BOOL required)
208 {
209  const char* value = NULL;
210 
211  value = IniFile_GetKeyValueString(ini, section, key);
212 
213  if (!value)
214  {
215  if (required)
216  WLog_ERR(TAG, "key '%s.%s' not found.", section, key);
217  return NULL;
218  }
219 
220  return value;
221 }
222 
223 static BOOL pf_config_load_server(wIniFile* ini, proxyConfig* config)
224 {
225  const char* host = NULL;
226 
227  WINPR_ASSERT(config);
228  host = pf_config_get_str(ini, section_server, key_host, FALSE);
229 
230  if (!host)
231  return TRUE;
232 
233  config->Host = _strdup(host);
234 
235  if (!config->Host)
236  return FALSE;
237 
238  if (!pf_config_get_uint16(ini, section_server, key_port, &config->Port, TRUE))
239  return FALSE;
240 
241  return TRUE;
242 }
243 
244 static BOOL pf_config_load_target(wIniFile* ini, proxyConfig* config)
245 {
246  const char* target_value = NULL;
247 
248  WINPR_ASSERT(config);
249  config->FixedTarget = pf_config_get_bool(ini, section_target, key_target_fixed, FALSE);
250 
251  if (!pf_config_get_uint16(ini, section_target, key_port, &config->TargetPort,
252  config->FixedTarget))
253  return FALSE;
254 
255  if (!pf_config_get_uint32(ini, section_target, key_target_tls_seclevel,
256  &config->TargetTlsSecLevel, FALSE))
257  return FALSE;
258 
259  if (config->FixedTarget)
260  {
261  target_value = pf_config_get_str(ini, section_target, key_host, TRUE);
262  if (!target_value)
263  return FALSE;
264 
265  config->TargetHost = _strdup(target_value);
266  if (!config->TargetHost)
267  return FALSE;
268  }
269 
270  target_value = pf_config_get_str(ini, section_target, key_target_user, FALSE);
271  if (target_value)
272  {
273  config->TargetUser = _strdup(target_value);
274  if (!config->TargetUser)
275  return FALSE;
276  }
277 
278  target_value = pf_config_get_str(ini, section_target, key_target_pwd, FALSE);
279  if (target_value)
280  {
281  config->TargetPassword = _strdup(target_value);
282  if (!config->TargetPassword)
283  return FALSE;
284  }
285 
286  target_value = pf_config_get_str(ini, section_target, key_target_domain, FALSE);
287  if (target_value)
288  {
289  config->TargetDomain = _strdup(target_value);
290  if (!config->TargetDomain)
291  return FALSE;
292  }
293 
294  return TRUE;
295 }
296 
297 static BOOL pf_config_load_channels(wIniFile* ini, proxyConfig* config)
298 {
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);
318 
319  return TRUE;
320 }
321 
322 static BOOL pf_config_load_input(wIniFile* ini, proxyConfig* config)
323 {
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);
328  return TRUE;
329 }
330 
331 static BOOL pf_config_load_security(wIniFile* ini, proxyConfig* config)
332 {
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);
340 
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);
349  return TRUE;
350 }
351 
352 static BOOL pf_config_load_modules(wIniFile* ini, proxyConfig* config)
353 {
354  const char* modules_to_load = NULL;
355  const char* required_modules = NULL;
356 
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);
359 
360  WINPR_ASSERT(config);
361  config->Modules = pf_config_parse_comma_separated_list(modules_to_load, &config->ModulesCount);
362 
363  config->RequiredPlugins =
364  pf_config_parse_comma_separated_list(required_modules, &config->RequiredPluginsCount);
365  return TRUE;
366 }
367 
368 static char* pf_config_decode_base64(const char* data, const char* name, size_t* pLength)
369 {
370  const char* headers[] = { "-----BEGIN PUBLIC KEY-----", "-----BEGIN RSA PUBLIC KEY-----",
371  "-----BEGIN CERTIFICATE-----", "-----BEGIN PRIVATE KEY-----",
372  "-----BEGIN RSA PRIVATE KEY-----" };
373 
374  size_t decoded_length = 0;
375  char* decoded = NULL;
376  if (!data)
377  {
378  WLog_ERR(TAG, "Invalid base64 data [%p] for %s", data, name);
379  return NULL;
380  }
381 
382  WINPR_ASSERT(name);
383  WINPR_ASSERT(pLength);
384 
385  const size_t length = strlen(data);
386 
387  if (strncmp(data, "-----", 5) == 0)
388  {
389  BOOL expected = FALSE;
390  for (size_t x = 0; x < ARRAYSIZE(headers); x++)
391  {
392  const char* header = headers[x];
393 
394  if (strncmp(data, header, strlen(header)) == 0)
395  expected = TRUE;
396  }
397 
398  if (!expected)
399  {
400  /* Extract header for log message
401  * expected format is '----- SOMETEXT -----'
402  */
403  char hdr[128] = { 0 };
404  const char* end = strchr(&data[5], '-');
405  if (end)
406  {
407  while (*end == '-')
408  end++;
409 
410  const size_t s = MIN(ARRAYSIZE(hdr) - 1ULL, (size_t)(end - data));
411  memcpy(hdr, data, s);
412  }
413 
414  WLog_WARN(TAG, "PEM has unexpected header '%s'. Known supported headers are:", hdr);
415  for (size_t x = 0; x < ARRAYSIZE(headers); x++)
416  {
417  const char* header = headers[x];
418  WLog_WARN(TAG, "%s", header);
419  }
420  }
421 
422  *pLength = length + 1;
423  return _strdup(data);
424  }
425 
426  crypto_base64_decode(data, length, (BYTE**)&decoded, &decoded_length);
427  if (!decoded || decoded_length == 0)
428  {
429  WLog_ERR(TAG, "Failed to decode base64 data of length %" PRIuz " for %s", length, name);
430  free(decoded);
431  return NULL;
432  }
433 
434  *pLength = strnlen(decoded, decoded_length) + 1;
435  return decoded;
436 }
437 
438 static BOOL pf_config_load_certificates(wIniFile* ini, proxyConfig* config)
439 {
440  const char* tmp1 = NULL;
441  const char* tmp2 = NULL;
442 
443  WINPR_ASSERT(ini);
444  WINPR_ASSERT(config);
445 
446  tmp1 = pf_config_get_str(ini, section_certificates, key_cert_file, FALSE);
447  if (tmp1)
448  {
449  if (!winpr_PathFileExists(tmp1))
450  {
451  WLog_ERR(TAG, "%s/%s file %s does not exist", section_certificates, key_cert_file,
452  tmp1);
453  return FALSE;
454  }
455  config->CertificateFile = _strdup(tmp1);
456  config->CertificatePEM =
457  crypto_read_pem(config->CertificateFile, &config->CertificatePEMLength);
458  if (!config->CertificatePEM)
459  return FALSE;
460  config->CertificatePEMLength += 1;
461  }
462  tmp2 = pf_config_get_str(ini, section_certificates, key_cert_content, FALSE);
463  if (tmp2)
464  {
465  if (strlen(tmp2) < 1)
466  {
467  WLog_ERR(TAG, "%s/%s has invalid empty value", section_certificates, key_cert_content);
468  return FALSE;
469  }
470  config->CertificateContent = _strdup(tmp2);
471  config->CertificatePEM = pf_config_decode_base64(
472  config->CertificateContent, "CertificateContent", &config->CertificatePEMLength);
473  if (!config->CertificatePEM)
474  return FALSE;
475  }
476  if (tmp1 && tmp2)
477  {
478  WLog_ERR(TAG,
479  "%s/%s and %s/%s are "
480  "mutually exclusive options",
481  section_certificates, key_cert_file, section_certificates, key_cert_content);
482  return FALSE;
483  }
484  else if (!tmp1 && !tmp2)
485  {
486  WLog_ERR(TAG,
487  "%s/%s or %s/%s are "
488  "required settings",
489  section_certificates, key_cert_file, section_certificates, key_cert_content);
490  return FALSE;
491  }
492 
493  tmp1 = pf_config_get_str(ini, section_certificates, key_private_key_file, FALSE);
494  if (tmp1)
495  {
496  if (!winpr_PathFileExists(tmp1))
497  {
498  WLog_ERR(TAG, "%s/%s file %s does not exist", section_certificates,
499  key_private_key_file, tmp1);
500  return FALSE;
501  }
502  config->PrivateKeyFile = _strdup(tmp1);
503  config->PrivateKeyPEM =
504  crypto_read_pem(config->PrivateKeyFile, &config->PrivateKeyPEMLength);
505  if (!config->PrivateKeyPEM)
506  return FALSE;
507  config->PrivateKeyPEMLength += 1;
508  }
509  tmp2 = pf_config_get_str(ini, section_certificates, key_private_key_content, FALSE);
510  if (tmp2)
511  {
512  if (strlen(tmp2) < 1)
513  {
514  WLog_ERR(TAG, "%s/%s has invalid empty value", section_certificates,
515  key_private_key_content);
516  return FALSE;
517  }
518  config->PrivateKeyContent = _strdup(tmp2);
519  config->PrivateKeyPEM = pf_config_decode_base64(
520  config->PrivateKeyContent, "PrivateKeyContent", &config->PrivateKeyPEMLength);
521  if (!config->PrivateKeyPEM)
522  return FALSE;
523  }
524 
525  if (tmp1 && tmp2)
526  {
527  WLog_ERR(TAG,
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);
532  return FALSE;
533  }
534  else if (!tmp1 && !tmp2)
535  {
536  WLog_ERR(TAG,
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);
541  return FALSE;
542  }
543 
544  return TRUE;
545 }
546 
547 proxyConfig* server_config_load_ini(wIniFile* ini)
548 {
549  proxyConfig* config = NULL;
550 
551  WINPR_ASSERT(ini);
552 
553  config = calloc(1, sizeof(proxyConfig));
554  if (config)
555  {
556  /* Set default values != 0 */
557  config->TargetTlsSecLevel = 1;
558 
559  /* Load from ini */
560  if (!pf_config_load_server(ini, config))
561  goto out;
562 
563  if (!pf_config_load_target(ini, config))
564  goto out;
565 
566  if (!pf_config_load_channels(ini, config))
567  goto out;
568 
569  if (!pf_config_load_input(ini, config))
570  goto out;
571 
572  if (!pf_config_load_security(ini, config))
573  goto out;
574 
575  if (!pf_config_load_modules(ini, config))
576  goto out;
577 
578  if (!pf_config_load_certificates(ini, config))
579  goto out;
580  config->ini = IniFile_Clone(ini);
581  if (!config->ini)
582  goto out;
583  }
584  return config;
585 out:
586  WINPR_PRAGMA_DIAG_PUSH
587  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
588  pf_server_config_free(config);
589  WINPR_PRAGMA_DIAG_POP
590 
591  return NULL;
592 }
593 
594 BOOL pf_server_config_dump(const char* file)
595 {
596  BOOL rc = FALSE;
597  wIniFile* ini = IniFile_New();
598  if (!ini)
599  return FALSE;
600 
601  /* Proxy server configuration */
602  if (IniFile_SetKeyValueString(ini, section_server, key_host, "0.0.0.0") < 0)
603  goto fail;
604  if (IniFile_SetKeyValueInt(ini, section_server, key_port, 3389) < 0)
605  goto fail;
606 
607  /* Target configuration */
608  if (IniFile_SetKeyValueString(ini, section_target, key_host, "somehost.example.com") < 0)
609  goto fail;
610  if (IniFile_SetKeyValueInt(ini, section_target, key_port, 3389) < 0)
611  goto fail;
612  if (IniFile_SetKeyValueString(ini, section_target, key_target_fixed, bool_str_true) < 0)
613  goto fail;
614  if (IniFile_SetKeyValueInt(ini, section_target, key_target_tls_seclevel, 1) < 0)
615  goto fail;
616 
617  /* Channel configuration */
618  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_gfx, bool_str_true) < 0)
619  goto fail;
620  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_disp, bool_str_true) < 0)
621  goto fail;
622  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_clip, bool_str_true) < 0)
623  goto fail;
624  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_mic, bool_str_true) < 0)
625  goto fail;
626  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_sound, bool_str_true) < 0)
627  goto fail;
628  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_rdpdr, bool_str_true) < 0)
629  goto fail;
630  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_video, bool_str_true) < 0)
631  goto fail;
632  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_camera, bool_str_true) < 0)
633  goto fail;
634  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_rails, bool_str_false) < 0)
635  goto fail;
636 
637  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_blacklist, bool_str_true) < 0)
638  goto fail;
639  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_pass, "") < 0)
640  goto fail;
641  if (IniFile_SetKeyValueString(ini, section_channels, key_channels_intercept, "") < 0)
642  goto fail;
643 
644  /* Input configuration */
645  if (IniFile_SetKeyValueString(ini, section_input, key_input_kbd, bool_str_true) < 0)
646  goto fail;
647  if (IniFile_SetKeyValueString(ini, section_input, key_input_mouse, bool_str_true) < 0)
648  goto fail;
649  if (IniFile_SetKeyValueString(ini, section_input, key_input_multitouch, bool_str_true) < 0)
650  goto fail;
651 
652  /* Security settings */
653  if (IniFile_SetKeyValueString(ini, section_security, key_security_server_tls, bool_str_true) <
654  0)
655  goto fail;
656  if (IniFile_SetKeyValueString(ini, section_security, key_security_server_nla, bool_str_false) <
657  0)
658  goto fail;
659  if (IniFile_SetKeyValueString(ini, section_security, key_security_server_rdp, bool_str_true) <
660  0)
661  goto fail;
662 
663  if (IniFile_SetKeyValueString(ini, section_security, key_security_client_tls, bool_str_true) <
664  0)
665  goto fail;
666  if (IniFile_SetKeyValueString(ini, section_security, key_security_client_nla, bool_str_true) <
667  0)
668  goto fail;
669  if (IniFile_SetKeyValueString(ini, section_security, key_security_client_rdp, bool_str_true) <
670  0)
671  goto fail;
672  if (IniFile_SetKeyValueString(ini, section_security, key_security_client_fallback,
673  bool_str_true) < 0)
674  goto fail;
675 
676  /* Module configuration */
677  if (IniFile_SetKeyValueString(ini, section_plugins, key_plugins_modules,
678  "module1,module2,...") < 0)
679  goto fail;
680  if (IniFile_SetKeyValueString(ini, section_plugins, key_plugins_required,
681  "module1,module2,...") < 0)
682  goto fail;
683 
684  /* Certificate configuration */
685  if (IniFile_SetKeyValueString(ini, section_certificates, key_cert_file,
686  "<absolute path to some certificate file> OR") < 0)
687  goto fail;
688  if (IniFile_SetKeyValueString(ini, section_certificates, key_cert_content,
689  "<Contents of some certificate file in PEM format>") < 0)
690  goto fail;
691 
692  if (IniFile_SetKeyValueString(ini, section_certificates, key_private_key_file,
693  "<absolute path to some private key file> OR") < 0)
694  goto fail;
695  if (IniFile_SetKeyValueString(ini, section_certificates, key_private_key_content,
696  "<Contents of some private key file in PEM format>") < 0)
697  goto fail;
698 
699  /* store configuration */
700  if (IniFile_WriteFile(ini, file) < 0)
701  goto fail;
702 
703  rc = TRUE;
704 
705 fail:
706  IniFile_Free(ini);
707  return rc;
708 }
709 
710 proxyConfig* pf_server_config_load_buffer(const char* buffer)
711 {
712  proxyConfig* config = NULL;
713  wIniFile* ini = NULL;
714 
715  ini = IniFile_New();
716 
717  if (!ini)
718  {
719  WLog_ERR(TAG, "IniFile_New() failed!");
720  return NULL;
721  }
722 
723  if (IniFile_ReadBuffer(ini, buffer) < 0)
724  {
725  WLog_ERR(TAG, "failed to parse ini: '%s'", buffer);
726  goto out;
727  }
728 
729  config = server_config_load_ini(ini);
730 out:
731  IniFile_Free(ini);
732  return config;
733 }
734 
735 proxyConfig* pf_server_config_load_file(const char* path)
736 {
737  proxyConfig* config = NULL;
738  wIniFile* ini = IniFile_New();
739 
740  if (!ini)
741  {
742  WLog_ERR(TAG, "IniFile_New() failed!");
743  return NULL;
744  }
745 
746  if (IniFile_ReadFile(ini, path) < 0)
747  {
748  WLog_ERR(TAG, "failed to parse ini file: '%s'", path);
749  goto out;
750  }
751 
752  config = server_config_load_ini(ini);
753 out:
754  IniFile_Free(ini);
755  return config;
756 }
757 
758 static void pf_server_config_print_list(char** list, size_t count)
759 {
760  WINPR_ASSERT(list);
761  for (size_t i = 0; i < count; i++)
762  WLog_INFO(TAG, "\t\t- %s", list[i]);
763 }
764 
765 void pf_server_config_print(const proxyConfig* config)
766 {
767  WINPR_ASSERT(config);
768  WLog_INFO(TAG, "Proxy configuration:");
769 
770  CONFIG_PRINT_SECTION(section_server);
771  CONFIG_PRINT_STR(config, Host);
772  CONFIG_PRINT_UINT16(config, Port);
773 
774  if (config->FixedTarget)
775  {
776  CONFIG_PRINT_SECTION(section_target);
777  CONFIG_PRINT_STR(config, TargetHost);
778  CONFIG_PRINT_UINT16(config, TargetPort);
779  CONFIG_PRINT_UINT32(config, TargetTlsSecLevel);
780 
781  if (config->TargetUser)
782  CONFIG_PRINT_STR(config, TargetUser);
783  if (config->TargetDomain)
784  CONFIG_PRINT_STR(config, TargetDomain);
785  }
786 
787  CONFIG_PRINT_SECTION(section_input);
788  CONFIG_PRINT_BOOL(config, Keyboard);
789  CONFIG_PRINT_BOOL(config, Mouse);
790  CONFIG_PRINT_BOOL(config, Multitouch);
791 
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);
800 
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);
812 
813  if (config->PassthroughCount)
814  {
815  WLog_INFO(TAG, "\tStatic Channels Proxy:");
816  pf_server_config_print_list(config->Passthrough, config->PassthroughCount);
817  }
818 
819  if (config->InterceptCount)
820  {
821  WLog_INFO(TAG, "\tStatic Channels Proxy-Intercept:");
822  pf_server_config_print_list(config->Intercept, config->InterceptCount);
823  }
824 
825  /* modules */
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]);
829 
830  /* Required plugins */
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]);
834 
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);
840 }
841 
842 void pf_server_config_free(proxyConfig* config)
843 {
844  if (config == NULL)
845  return;
846 
847  CommandLineParserFree(config->Passthrough);
848  CommandLineParserFree(config->Intercept);
849  CommandLineParserFree(config->RequiredPlugins);
850  CommandLineParserFree(config->Modules);
851  free(config->TargetHost);
852  free(config->Host);
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);
864  free(config);
865 }
866 
867 size_t pf_config_required_plugins_count(const proxyConfig* config)
868 {
869  WINPR_ASSERT(config);
870  return config->RequiredPluginsCount;
871 }
872 
873 const char* pf_config_required_plugin(const proxyConfig* config, size_t index)
874 {
875  WINPR_ASSERT(config);
876  if (index >= config->RequiredPluginsCount)
877  return NULL;
878 
879  return config->RequiredPlugins[index];
880 }
881 
882 size_t pf_config_modules_count(const proxyConfig* config)
883 {
884  WINPR_ASSERT(config);
885  return config->ModulesCount;
886 }
887 
888 const char** pf_config_modules(const proxyConfig* config)
889 {
890  union
891  {
892  char** ppc;
893  const char** cppc;
894  } cnv;
895 
896  WINPR_ASSERT(config);
897 
898  cnv.ppc = config->Modules;
899  return cnv.cppc;
900 }
901 
902 static BOOL pf_config_copy_string(char** dst, const char* src)
903 {
904  *dst = NULL;
905  if (src)
906  *dst = _strdup(src);
907  return TRUE;
908 }
909 
910 static BOOL pf_config_copy_string_n(char** dst, const char* src, size_t size)
911 {
912  *dst = NULL;
913 
914  if (src && (size > 0))
915  {
916  WINPR_ASSERT(strnlen(src, size) == size - 1);
917  *dst = calloc(size, sizeof(char));
918  if (!*dst)
919  return FALSE;
920  memcpy(*dst, src, size);
921  }
922 
923  return TRUE;
924 }
925 
926 static BOOL pf_config_copy_string_list(char*** dst, size_t* size, char** src, size_t srcSize)
927 {
928  WINPR_ASSERT(dst);
929  WINPR_ASSERT(size);
930  WINPR_ASSERT(src || (srcSize == 0));
931 
932  *dst = NULL;
933  *size = 0;
934  if (srcSize > INT32_MAX)
935  return FALSE;
936 
937  if (srcSize != 0)
938  {
939  char* csv = CommandLineToCommaSeparatedValues((INT32)srcSize, src);
940  *dst = CommandLineParseCommaSeparatedValues(csv, size);
941  free(csv);
942  }
943 
944  return TRUE;
945 }
946 
947 BOOL pf_config_clone(proxyConfig** dst, const proxyConfig* config)
948 {
949  proxyConfig* tmp = calloc(1, sizeof(proxyConfig));
950 
951  WINPR_ASSERT(dst);
952  WINPR_ASSERT(config);
953 
954  if (!tmp)
955  return FALSE;
956 
957  *tmp = *config;
958 
959  if (!pf_config_copy_string(&tmp->Host, config->Host))
960  goto fail;
961  if (!pf_config_copy_string(&tmp->TargetHost, config->TargetHost))
962  goto fail;
963 
964  if (!pf_config_copy_string_list(&tmp->Passthrough, &tmp->PassthroughCount, config->Passthrough,
965  config->PassthroughCount))
966  goto fail;
967  if (!pf_config_copy_string_list(&tmp->Intercept, &tmp->InterceptCount, config->Intercept,
968  config->InterceptCount))
969  goto fail;
970  if (!pf_config_copy_string_list(&tmp->Modules, &tmp->ModulesCount, config->Modules,
971  config->ModulesCount))
972  goto fail;
973  if (!pf_config_copy_string_list(&tmp->RequiredPlugins, &tmp->RequiredPluginsCount,
974  config->RequiredPlugins, config->RequiredPluginsCount))
975  goto fail;
976  if (!pf_config_copy_string(&tmp->CertificateFile, config->CertificateFile))
977  goto fail;
978  if (!pf_config_copy_string(&tmp->CertificateContent, config->CertificateContent))
979  goto fail;
980  if (!pf_config_copy_string_n(&tmp->CertificatePEM, config->CertificatePEM,
981  config->CertificatePEMLength))
982  goto fail;
983  if (!pf_config_copy_string(&tmp->PrivateKeyFile, config->PrivateKeyFile))
984  goto fail;
985  if (!pf_config_copy_string(&tmp->PrivateKeyContent, config->PrivateKeyContent))
986  goto fail;
987  if (!pf_config_copy_string_n(&tmp->PrivateKeyPEM, config->PrivateKeyPEM,
988  config->PrivateKeyPEMLength))
989  goto fail;
990 
991  tmp->ini = IniFile_Clone(config->ini);
992  if (!tmp->ini)
993  goto fail;
994 
995  *dst = tmp;
996  return TRUE;
997 
998 fail:
999  WINPR_PRAGMA_DIAG_PUSH
1000  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
1001  pf_server_config_free(tmp);
1002  WINPR_PRAGMA_DIAG_POP
1003  return FALSE;
1004 }
1005 
1006 struct config_plugin_data
1007 {
1008  proxyPluginsManager* mgr;
1009  const proxyConfig* config;
1010 };
1011 
1012 static const char config_plugin_name[] = "config";
1013 static const char config_plugin_desc[] =
1014  "A plugin filtering according to proxy configuration file rules";
1015 
1016 static BOOL config_plugin_unload(proxyPlugin* plugin)
1017 {
1018  WINPR_ASSERT(plugin);
1019 
1020  /* Here we have to free up our custom data storage. */
1021  if (plugin)
1022  {
1023  free(plugin->custom);
1024  plugin->custom = NULL;
1025  }
1026 
1027  return TRUE;
1028 }
1029 
1030 static BOOL config_plugin_keyboard_event(proxyPlugin* plugin, proxyData* pdata, void* param)
1031 {
1032  BOOL rc = 0;
1033  const struct config_plugin_data* custom = NULL;
1034  const proxyConfig* cfg = NULL;
1035  const proxyKeyboardEventInfo* event_data = (const proxyKeyboardEventInfo*)(param);
1036 
1037  WINPR_ASSERT(plugin);
1038  WINPR_ASSERT(pdata);
1039  WINPR_ASSERT(event_data);
1040 
1041  WINPR_UNUSED(event_data);
1042 
1043  custom = plugin->custom;
1044  WINPR_ASSERT(custom);
1045 
1046  cfg = custom->config;
1047  WINPR_ASSERT(cfg);
1048 
1049  rc = cfg->Keyboard;
1050  WLog_DBG(TAG, "%s", boolstr(rc));
1051  return rc;
1052 }
1053 
1054 static BOOL config_plugin_unicode_event(proxyPlugin* plugin, proxyData* pdata, void* param)
1055 {
1056  BOOL rc = 0;
1057  const struct config_plugin_data* custom = NULL;
1058  const proxyConfig* cfg = NULL;
1059  const proxyUnicodeEventInfo* event_data = (const proxyUnicodeEventInfo*)(param);
1060 
1061  WINPR_ASSERT(plugin);
1062  WINPR_ASSERT(pdata);
1063  WINPR_ASSERT(event_data);
1064 
1065  WINPR_UNUSED(event_data);
1066 
1067  custom = plugin->custom;
1068  WINPR_ASSERT(custom);
1069 
1070  cfg = custom->config;
1071  WINPR_ASSERT(cfg);
1072 
1073  rc = cfg->Keyboard;
1074  WLog_DBG(TAG, "%s", boolstr(rc));
1075  return rc;
1076 }
1077 
1078 static BOOL config_plugin_mouse_event(proxyPlugin* plugin, proxyData* pdata, void* param)
1079 {
1080  BOOL rc = 0;
1081  const struct config_plugin_data* custom = NULL;
1082  const proxyConfig* cfg = NULL;
1083  const proxyMouseEventInfo* event_data = (const proxyMouseEventInfo*)(param);
1084 
1085  WINPR_ASSERT(plugin);
1086  WINPR_ASSERT(pdata);
1087  WINPR_ASSERT(event_data);
1088 
1089  WINPR_UNUSED(event_data);
1090 
1091  custom = plugin->custom;
1092  WINPR_ASSERT(custom);
1093 
1094  cfg = custom->config;
1095  WINPR_ASSERT(cfg);
1096 
1097  rc = cfg->Mouse;
1098  return rc;
1099 }
1100 
1101 static BOOL config_plugin_mouse_ex_event(proxyPlugin* plugin, proxyData* pdata, void* param)
1102 {
1103  BOOL rc = 0;
1104  const struct config_plugin_data* custom = NULL;
1105  const proxyConfig* cfg = NULL;
1106  const proxyMouseExEventInfo* event_data = (const proxyMouseExEventInfo*)(param);
1107 
1108  WINPR_ASSERT(plugin);
1109  WINPR_ASSERT(pdata);
1110  WINPR_ASSERT(event_data);
1111 
1112  WINPR_UNUSED(event_data);
1113 
1114  custom = plugin->custom;
1115  WINPR_ASSERT(custom);
1116 
1117  cfg = custom->config;
1118  WINPR_ASSERT(cfg);
1119 
1120  rc = cfg->Mouse;
1121  return rc;
1122 }
1123 
1124 static BOOL config_plugin_client_channel_data(proxyPlugin* plugin, proxyData* pdata, void* param)
1125 {
1126  const proxyChannelDataEventInfo* channel = (const proxyChannelDataEventInfo*)(param);
1127 
1128  WINPR_ASSERT(plugin);
1129  WINPR_ASSERT(pdata);
1130  WINPR_ASSERT(channel);
1131 
1132  WLog_DBG(TAG, "%s [0x%04" PRIx16 "] got %" PRIuz, channel->channel_name, channel->channel_id,
1133  channel->data_len);
1134  return TRUE;
1135 }
1136 
1137 static BOOL config_plugin_server_channel_data(proxyPlugin* plugin, proxyData* pdata, void* param)
1138 {
1139  const proxyChannelDataEventInfo* channel = (const proxyChannelDataEventInfo*)(param);
1140 
1141  WINPR_ASSERT(plugin);
1142  WINPR_ASSERT(pdata);
1143  WINPR_ASSERT(channel);
1144 
1145  WLog_DBG(TAG, "%s [0x%04" PRIx16 "] got %" PRIuz, channel->channel_name, channel->channel_id,
1146  channel->data_len);
1147  return TRUE;
1148 }
1149 
1150 static BOOL config_plugin_dynamic_channel_create(proxyPlugin* plugin, proxyData* pdata, void* param)
1151 {
1152  BOOL accept = 0;
1153  const proxyChannelDataEventInfo* channel = (const proxyChannelDataEventInfo*)(param);
1154 
1155  WINPR_ASSERT(plugin);
1156  WINPR_ASSERT(pdata);
1157  WINPR_ASSERT(channel);
1158 
1159  const struct config_plugin_data* custom = plugin->custom;
1160  WINPR_ASSERT(custom);
1161 
1162  const proxyConfig* cfg = custom->config;
1163  WINPR_ASSERT(cfg);
1164 
1165  pf_utils_channel_mode rc = pf_utils_get_channel_mode(cfg, channel->channel_name);
1166  switch (rc)
1167  {
1168 
1169  case PF_UTILS_CHANNEL_INTERCEPT:
1170  case PF_UTILS_CHANNEL_PASSTHROUGH:
1171  accept = TRUE;
1172  break;
1173  case PF_UTILS_CHANNEL_BLOCK:
1174  default:
1175  accept = FALSE;
1176  break;
1177  }
1178 
1179  if (accept)
1180  {
1181  if (strncmp(RDPGFX_DVC_CHANNEL_NAME, channel->channel_name,
1182  sizeof(RDPGFX_DVC_CHANNEL_NAME)) == 0)
1183  accept = cfg->GFX;
1184  else if (strncmp(RDPSND_DVC_CHANNEL_NAME, channel->channel_name,
1185  sizeof(RDPSND_DVC_CHANNEL_NAME)) == 0)
1186  accept = cfg->AudioOutput;
1187  else if (strncmp(RDPSND_LOSSY_DVC_CHANNEL_NAME, channel->channel_name,
1188  sizeof(RDPSND_LOSSY_DVC_CHANNEL_NAME)) == 0)
1189  accept = cfg->AudioOutput;
1190  else if (strncmp(AUDIN_DVC_CHANNEL_NAME, channel->channel_name,
1191  sizeof(AUDIN_DVC_CHANNEL_NAME)) == 0)
1192  accept = cfg->AudioInput;
1193  else if (strncmp(RDPEI_DVC_CHANNEL_NAME, channel->channel_name,
1194  sizeof(RDPEI_DVC_CHANNEL_NAME)) == 0)
1195  accept = cfg->Multitouch;
1196  else if (strncmp(TSMF_DVC_CHANNEL_NAME, channel->channel_name,
1197  sizeof(TSMF_DVC_CHANNEL_NAME)) == 0)
1198  accept = cfg->VideoRedirection;
1199  else if (strncmp(VIDEO_CONTROL_DVC_CHANNEL_NAME, channel->channel_name,
1200  sizeof(VIDEO_CONTROL_DVC_CHANNEL_NAME)) == 0)
1201  accept = cfg->VideoRedirection;
1202  else if (strncmp(VIDEO_DATA_DVC_CHANNEL_NAME, channel->channel_name,
1203  sizeof(VIDEO_DATA_DVC_CHANNEL_NAME)) == 0)
1204  accept = cfg->VideoRedirection;
1205  else if (strncmp(RDPECAM_DVC_CHANNEL_NAME, channel->channel_name,
1206  sizeof(RDPECAM_DVC_CHANNEL_NAME)) == 0)
1207  accept = cfg->CameraRedirection;
1208  }
1209 
1210  WLog_DBG(TAG, "%s [0x%04" PRIx16 "]: %s", channel->channel_name, channel->channel_id,
1211  boolstr(accept));
1212  return accept;
1213 }
1214 
1215 static BOOL config_plugin_channel_create(proxyPlugin* plugin, proxyData* pdata, void* param)
1216 {
1217  BOOL accept = 0;
1218  const proxyChannelDataEventInfo* channel = (const proxyChannelDataEventInfo*)(param);
1219 
1220  WINPR_ASSERT(plugin);
1221  WINPR_ASSERT(pdata);
1222  WINPR_ASSERT(channel);
1223 
1224  const struct config_plugin_data* custom = plugin->custom;
1225  WINPR_ASSERT(custom);
1226 
1227  const proxyConfig* cfg = custom->config;
1228  WINPR_ASSERT(cfg);
1229 
1230  pf_utils_channel_mode rc = pf_utils_get_channel_mode(cfg, channel->channel_name);
1231  switch (rc)
1232  {
1233  case PF_UTILS_CHANNEL_INTERCEPT:
1234  case PF_UTILS_CHANNEL_PASSTHROUGH:
1235  accept = TRUE;
1236  break;
1237  case PF_UTILS_CHANNEL_BLOCK:
1238  default:
1239  accept = FALSE;
1240  break;
1241  }
1242  if (accept)
1243  {
1244  if (strncmp(CLIPRDR_SVC_CHANNEL_NAME, channel->channel_name,
1245  sizeof(CLIPRDR_SVC_CHANNEL_NAME)) == 0)
1246  accept = cfg->Clipboard;
1247  else if (strncmp(RDPSND_CHANNEL_NAME, channel->channel_name, sizeof(RDPSND_CHANNEL_NAME)) ==
1248  0)
1249  accept = cfg->AudioOutput;
1250  else if (strncmp(RDPDR_SVC_CHANNEL_NAME, channel->channel_name,
1251  sizeof(RDPDR_SVC_CHANNEL_NAME)) == 0)
1252  accept = cfg->DeviceRedirection;
1253  else if (strncmp(DISP_DVC_CHANNEL_NAME, channel->channel_name,
1254  sizeof(DISP_DVC_CHANNEL_NAME)) == 0)
1255  accept = cfg->DisplayControl;
1256  else if (strncmp(RAIL_SVC_CHANNEL_NAME, channel->channel_name,
1257  sizeof(RAIL_SVC_CHANNEL_NAME)) == 0)
1258  accept = cfg->RemoteApp;
1259  }
1260 
1261  WLog_DBG(TAG, "%s [static]: %s", channel->channel_name, boolstr(accept));
1262  return accept;
1263 }
1264 
1265 BOOL pf_config_plugin(proxyPluginsManager* plugins_manager, void* userdata)
1266 {
1267  struct config_plugin_data* custom = NULL;
1268  proxyPlugin plugin = { 0 };
1269 
1270  plugin.name = config_plugin_name;
1271  plugin.description = config_plugin_desc;
1272  plugin.PluginUnload = config_plugin_unload;
1273 
1274  plugin.KeyboardEvent = config_plugin_keyboard_event;
1275  plugin.UnicodeEvent = config_plugin_unicode_event;
1276  plugin.MouseEvent = config_plugin_mouse_event;
1277  plugin.MouseExEvent = config_plugin_mouse_ex_event;
1278  plugin.ClientChannelData = config_plugin_client_channel_data;
1279  plugin.ServerChannelData = config_plugin_server_channel_data;
1280  plugin.ChannelCreate = config_plugin_channel_create;
1281  plugin.DynamicChannelCreate = config_plugin_dynamic_channel_create;
1282  plugin.userdata = userdata;
1283 
1284  custom = calloc(1, sizeof(struct config_plugin_data));
1285  if (!custom)
1286  return FALSE;
1287 
1288  custom->mgr = plugins_manager;
1289  custom->config = userdata;
1290 
1291  plugin.custom = custom;
1292  plugin.userdata = userdata;
1293 
1294  return plugins_manager->RegisterPlugin(plugins_manager, &plugin);
1295 }
1296 
1297 const char* pf_config_get(const proxyConfig* config, const char* section, const char* key)
1298 {
1299  WINPR_ASSERT(config);
1300  WINPR_ASSERT(config->ini);
1301  WINPR_ASSERT(section);
1302  WINPR_ASSERT(key);
1303 
1304  return IniFile_GetKeyValueString(config->ini, section, key);
1305 }
proxyConfig * server_config_load_ini(wIniFile *ini)
server_config_load_ini Create a proxyConfig from a already loaded INI file.
Definition: pf_config.c:547
void pf_server_config_free(proxyConfig *config)
pf_server_config_free Releases all resources associated with proxyConfig
Definition: pf_config.c:842
void pf_server_config_print(const proxyConfig *config)
pf_server_config_print Print the configuration to stdout
Definition: pf_config.c:765
const char * pf_config_get(const proxyConfig *config, const char *section, const char *key)
pf_config_get get a value for a section/key
Definition: pf_config.c:1297
const char ** pf_config_modules(const proxyConfig *config)
pf_config_modules
Definition: pf_config.c:888
BOOL pf_config_clone(proxyConfig **dst, const proxyConfig *config)
pf_config_clone Create a copy of the configuration
Definition: pf_config.c:947
BOOL pf_server_config_dump(const char *file)
pf_server_config_dump Dumps a default INI configuration file
Definition: pf_config.c:594
size_t pf_config_required_plugins_count(const proxyConfig *config)
pf_config_required_plugins_count
Definition: pf_config.c:867
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
Definition: pf_config.c:710
BOOL pf_config_plugin(proxyPluginsManager *plugins_manager, void *userdata)
pf_config_plugin Register a proxy plugin handling event filtering defined in the configuration.
Definition: pf_config.c:1265
const char * pf_config_required_plugin(const proxyConfig *config, size_t index)
pf_config_required_plugin
Definition: pf_config.c:873
proxyConfig * pf_server_config_load_file(const char *path)
pf_server_config_load_file Create a proxyConfig from a INI file found at path.
Definition: pf_config.c:735
size_t pf_config_modules_count(const proxyConfig *config)
pf_config_modules_count
Definition: pf_config.c:882