Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/libfreerdp/core/utils.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Terminal Server Gateway (utils)
4
 *
5
 * Copyright 2021 Armin Novak <armin.novak@thincast.com>
6
 * Copyright 2021 Thincast Technologies GmbH
7
 *
8
 * Licensed under the Apache License, Version 2.0 (the "License");
9
 * you may not use this file except in compliance with the License.
10
 * You may obtain a copy of the License at
11
 *
12
 *     http://www.apache.org/licenses/LICENSE-2.0
13
 *
14
 * Unless required by applicable law or agreed to in writing, software
15
 * distributed under the License is distributed on an "AS IS" BASIS,
16
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17
 * See the License for the specific language governing permissions and
18
 * limitations under the License.
19
 */
20
21
#include <freerdp/config.h>
22
23
#include "settings.h"
24
25
#include <winpr/assert.h>
26
27
#include <freerdp/freerdp.h>
28
#include <freerdp/channels/cliprdr.h>
29
#include <freerdp/channels/rdpdr.h>
30
31
#include <freerdp/log.h>
32
#define TAG FREERDP_TAG("core.gateway.utils")
33
34
#include "utils.h"
35
36
#include "../core/rdp.h"
37
38
BOOL utils_str_copy(const char* value, char** dst)
39
0
{
40
0
  WINPR_ASSERT(dst);
41
42
0
  free(*dst);
43
0
  *dst = NULL;
44
0
  if (!value)
45
0
    return TRUE;
46
47
0
  (*dst) = _strdup(value);
48
0
  return (*dst) != NULL;
49
0
}
50
51
static BOOL utils_copy_smartcard_settings(const rdpSettings* settings, rdpSettings* origSettings)
52
0
{
53
  /* update original settings with provided smart card settings */
54
0
  origSettings->SmartcardLogon = settings->SmartcardLogon;
55
0
  origSettings->PasswordIsSmartcardPin = settings->PasswordIsSmartcardPin;
56
0
  if (!utils_str_copy(settings->ReaderName, &origSettings->ReaderName))
57
0
    return FALSE;
58
0
  if (!utils_str_copy(settings->CspName, &origSettings->CspName))
59
0
    return FALSE;
60
0
  if (!utils_str_copy(settings->ContainerName, &origSettings->ContainerName))
61
0
    return FALSE;
62
63
0
  return TRUE;
64
0
}
65
66
auth_status utils_authenticate_gateway(freerdp* instance, rdp_auth_reason reason)
67
0
{
68
0
  rdpSettings* settings = NULL;
69
0
  rdpSettings* origSettings = NULL;
70
0
  BOOL prompt = FALSE;
71
0
  BOOL proceed = 0;
72
73
0
  WINPR_ASSERT(instance);
74
0
  WINPR_ASSERT(instance->context);
75
0
  WINPR_ASSERT(instance->context->settings);
76
0
  WINPR_ASSERT(instance->context->rdp);
77
0
  WINPR_ASSERT(instance->context->rdp->originalSettings);
78
79
0
  settings = instance->context->settings;
80
0
  origSettings = instance->context->rdp->originalSettings;
81
82
0
  if (freerdp_shall_disconnect_context(instance->context))
83
0
    return AUTH_FAILED;
84
85
0
  if (utils_str_is_empty(freerdp_settings_get_string(settings, FreeRDP_GatewayPassword)))
86
0
    prompt = TRUE;
87
0
  if (utils_str_is_empty(freerdp_settings_get_string(settings, FreeRDP_GatewayUsername)))
88
0
    prompt = TRUE;
89
90
0
  if (!prompt)
91
0
    return AUTH_SKIP;
92
93
0
  if (!instance->GatewayAuthenticate && !instance->AuthenticateEx)
94
0
    return AUTH_NO_CREDENTIALS;
95
96
0
  if (!instance->GatewayAuthenticate)
97
0
  {
98
0
    proceed =
99
0
        instance->AuthenticateEx(instance, &settings->GatewayUsername,
100
0
                                 &settings->GatewayPassword, &settings->GatewayDomain, reason);
101
0
    if (!proceed)
102
0
      return AUTH_CANCELLED;
103
0
  }
104
0
  else
105
0
  {
106
0
    proceed =
107
0
        instance->GatewayAuthenticate(instance, &settings->GatewayUsername,
108
0
                                      &settings->GatewayPassword, &settings->GatewayDomain);
109
0
    if (!proceed)
110
0
      return AUTH_CANCELLED;
111
0
  }
112
113
0
  if (utils_str_is_empty(settings->GatewayUsername) ||
114
0
      utils_str_is_empty(settings->GatewayPassword))
115
0
    return AUTH_NO_CREDENTIALS;
116
117
0
  if (!utils_sync_credentials(settings, FALSE))
118
0
    return AUTH_FAILED;
119
120
  /* update original settings with provided user credentials */
121
0
  if (!utils_str_copy(settings->GatewayUsername, &origSettings->GatewayUsername))
122
0
    return AUTH_FAILED;
123
0
  if (!utils_str_copy(settings->GatewayDomain, &origSettings->GatewayDomain))
124
0
    return AUTH_FAILED;
125
0
  if (!utils_str_copy(settings->GatewayPassword, &origSettings->GatewayPassword))
126
0
    return AUTH_FAILED;
127
0
  if (!utils_sync_credentials(origSettings, FALSE))
128
0
    return AUTH_FAILED;
129
130
0
  if (!utils_copy_smartcard_settings(settings, origSettings))
131
0
    return AUTH_FAILED;
132
133
0
  return AUTH_SUCCESS;
134
0
}
135
136
auth_status utils_authenticate(freerdp* instance, rdp_auth_reason reason, BOOL override)
137
0
{
138
0
  rdpSettings* settings = NULL;
139
0
  rdpSettings* origSettings = NULL;
140
0
  BOOL prompt = !override;
141
0
  BOOL proceed = 0;
142
143
0
  WINPR_ASSERT(instance);
144
0
  WINPR_ASSERT(instance->context);
145
0
  WINPR_ASSERT(instance->context->settings);
146
0
  WINPR_ASSERT(instance->context->rdp);
147
0
  WINPR_ASSERT(instance->context->rdp->originalSettings);
148
149
0
  settings = instance->context->settings;
150
0
  origSettings = instance->context->rdp->originalSettings;
151
152
0
  if (freerdp_shall_disconnect_context(instance->context))
153
0
    return AUTH_FAILED;
154
155
0
  if (settings->ConnectChildSession)
156
0
    return AUTH_NO_CREDENTIALS;
157
158
  /* Ask for auth data if no or an empty username was specified or no password was given */
159
0
  if (utils_str_is_empty(freerdp_settings_get_string(settings, FreeRDP_Username)) ||
160
0
      (settings->Password == NULL && settings->RedirectionPassword == NULL))
161
0
    prompt = TRUE;
162
163
0
  if (!prompt)
164
0
    return AUTH_SKIP;
165
166
0
  switch (reason)
167
0
  {
168
0
    case AUTH_RDP:
169
0
    case AUTH_TLS:
170
0
      if (settings->SmartcardLogon)
171
0
      {
172
0
        if (!utils_str_is_empty(settings->Password))
173
0
        {
174
0
          WLog_INFO(TAG, "Authentication via smartcard");
175
0
          return AUTH_SUCCESS;
176
0
        }
177
0
        reason = AUTH_SMARTCARD_PIN;
178
0
      }
179
0
      break;
180
0
    case AUTH_NLA:
181
0
      if (settings->SmartcardLogon)
182
0
        reason = AUTH_SMARTCARD_PIN;
183
0
      break;
184
0
    default:
185
0
      break;
186
0
  }
187
188
  /* If no callback is specified still continue connection */
189
0
  if (!instance->Authenticate && !instance->AuthenticateEx)
190
0
    return AUTH_NO_CREDENTIALS;
191
192
0
  if (!instance->Authenticate)
193
0
  {
194
0
    proceed = instance->AuthenticateEx(instance, &settings->Username, &settings->Password,
195
0
                                       &settings->Domain, reason);
196
0
    if (!proceed)
197
0
      return AUTH_CANCELLED;
198
0
  }
199
0
  else
200
0
  {
201
0
    proceed = instance->Authenticate(instance, &settings->Username, &settings->Password,
202
0
                                     &settings->Domain);
203
0
    if (!proceed)
204
0
      return AUTH_NO_CREDENTIALS;
205
0
  }
206
207
0
  if (utils_str_is_empty(settings->Username) || utils_str_is_empty(settings->Password))
208
0
    return AUTH_NO_CREDENTIALS;
209
210
0
  if (!utils_sync_credentials(settings, TRUE))
211
0
    return AUTH_FAILED;
212
213
  /* update original settings with provided user credentials */
214
0
  if (!utils_str_copy(settings->Username, &origSettings->Username))
215
0
    return AUTH_FAILED;
216
0
  if (!utils_str_copy(settings->Domain, &origSettings->Domain))
217
0
    return AUTH_FAILED;
218
0
  if (!utils_str_copy(settings->Password, &origSettings->Password))
219
0
    return AUTH_FAILED;
220
0
  if (!utils_sync_credentials(origSettings, TRUE))
221
0
    return AUTH_FAILED;
222
223
0
  if (!utils_copy_smartcard_settings(settings, origSettings))
224
0
    return AUTH_FAILED;
225
226
0
  return AUTH_SUCCESS;
227
0
}
228
229
BOOL utils_sync_credentials(rdpSettings* settings, BOOL toGateway)
230
0
{
231
0
  WINPR_ASSERT(settings);
232
0
  if (!settings->GatewayUseSameCredentials)
233
0
    return TRUE;
234
235
0
  if (toGateway)
236
0
  {
237
0
    if (!utils_str_copy(settings->Username, &settings->GatewayUsername))
238
0
      return FALSE;
239
0
    if (!utils_str_copy(settings->Domain, &settings->GatewayDomain))
240
0
      return FALSE;
241
0
    if (!utils_str_copy(settings->Password, &settings->GatewayPassword))
242
0
      return FALSE;
243
0
  }
244
0
  else
245
0
  {
246
0
    if (!utils_str_copy(settings->GatewayUsername, &settings->Username))
247
0
      return FALSE;
248
0
    if (!utils_str_copy(settings->GatewayDomain, &settings->Domain))
249
0
      return FALSE;
250
0
    if (!utils_str_copy(settings->GatewayPassword, &settings->Password))
251
0
      return FALSE;
252
0
  }
253
0
  return TRUE;
254
0
}
255
256
BOOL utils_str_is_empty(const char* str)
257
0
{
258
0
  if (!str)
259
0
    return TRUE;
260
0
  if (strlen(str) == 0)
261
0
    return TRUE;
262
0
  return FALSE;
263
0
}
264
265
BOOL utils_abort_connect(rdpRdp* rdp)
266
1.44k
{
267
1.44k
  if (!rdp)
268
0
    return FALSE;
269
270
1.44k
  return SetEvent(rdp->abortEvent);
271
1.44k
}
272
273
BOOL utils_reset_abort(rdpRdp* rdp)
274
0
{
275
0
  WINPR_ASSERT(rdp);
276
277
0
  return ResetEvent(rdp->abortEvent);
278
0
}
279
280
HANDLE utils_get_abort_event(rdpRdp* rdp)
281
0
{
282
0
  WINPR_ASSERT(rdp);
283
0
  return rdp->abortEvent;
284
0
}
285
286
BOOL utils_abort_event_is_set(rdpRdp* rdp)
287
235
{
288
235
  DWORD status = 0;
289
235
  WINPR_ASSERT(rdp);
290
235
  status = WaitForSingleObject(rdp->abortEvent, 0);
291
235
  return status == WAIT_OBJECT_0;
292
235
}
293
294
const char* utils_is_vsock(const char* hostname)
295
0
{
296
0
  if (!hostname)
297
0
    return NULL;
298
299
0
  const char vsock[8] = "vsock://";
300
0
  if (strncmp(hostname, vsock, sizeof(vsock)) == 0)
301
0
    return &hostname[sizeof(vsock)];
302
0
  return NULL;
303
0
}
304
305
static BOOL remove_rdpdr_type(rdpSettings* settings, UINT32 type)
306
0
{
307
0
  RDPDR_DEVICE* printer = NULL;
308
0
  do
309
0
  {
310
0
    printer = freerdp_device_collection_find_type(settings, type);
311
0
    freerdp_device_collection_del(settings, printer);
312
0
    freerdp_device_free(printer);
313
0
  } while (printer);
314
0
  return TRUE;
315
0
}
316
317
static BOOL disable_clipboard(rdpSettings* settings)
318
0
{
319
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectClipboard, FALSE))
320
0
    return FALSE;
321
0
  freerdp_static_channel_collection_del(settings, CLIPRDR_SVC_CHANNEL_NAME);
322
0
  return TRUE;
323
0
}
324
325
static BOOL disable_drive(rdpSettings* settings)
326
0
{
327
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectDrives, FALSE))
328
0
    return FALSE;
329
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectHomeDrive, FALSE))
330
0
    return FALSE;
331
332
0
  return remove_rdpdr_type(settings, RDPDR_DTYP_FILESYSTEM);
333
0
}
334
335
static BOOL disable_printers(rdpSettings* settings)
336
0
{
337
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectPrinters, FALSE))
338
0
    return FALSE;
339
340
0
  return remove_rdpdr_type(settings, RDPDR_DTYP_PRINT);
341
0
}
342
343
static BOOL disable_port(rdpSettings* settings)
344
0
{
345
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectParallelPorts, FALSE))
346
0
    return FALSE;
347
0
  if (!freerdp_settings_set_bool(settings, FreeRDP_RedirectSerialPorts, FALSE))
348
0
    return FALSE;
349
0
  if (!remove_rdpdr_type(settings, RDPDR_DTYP_SERIAL))
350
0
    return FALSE;
351
0
  return remove_rdpdr_type(settings, RDPDR_DTYP_PARALLEL);
352
0
}
353
354
static BOOL disable_pnp(rdpSettings* settings)
355
0
{
356
  // TODO(akallabeth): [MS-RDPEPNP] related stuff is disabled.
357
0
  return TRUE;
358
0
}
359
360
static BOOL apply_gw_policy(rdpContext* context)
361
0
{
362
0
  WINPR_ASSERT(context);
363
0
  return utils_reload_channels(context);
364
0
}
365
366
BOOL utils_apply_gateway_policy(wLog* log, rdpContext* context, UINT32 flags, const char* module)
367
0
{
368
0
  WINPR_ASSERT(log);
369
0
  WINPR_ASSERT(context);
370
371
0
  rdpSettings* settings = context->settings;
372
0
  WINPR_ASSERT(settings);
373
374
0
  if (flags & HTTP_TUNNEL_REDIR_ENABLE_ALL)
375
0
  {
376
0
    WLog_Print(log, WLOG_DEBUG, "[%s] policy allows all redirections", module);
377
0
  }
378
0
  else if (freerdp_settings_get_bool(settings, FreeRDP_GatewayIgnoreRedirectionPolicy))
379
0
  {
380
0
    char buffer[128] = { 0 };
381
0
    WLog_Print(log, WLOG_INFO, "[%s] policy ignored on user request %s", module,
382
0
               utils_redir_flags_to_string(flags, buffer, sizeof(buffer)));
383
0
  }
384
0
  else if (flags & HTTP_TUNNEL_REDIR_DISABLE_ALL)
385
0
  {
386
0
    WLog_Print(log, WLOG_INFO, "[%s] policy denies all redirections", module);
387
0
    if (!disable_drive(settings))
388
0
      return FALSE;
389
0
    if (!disable_printers(settings))
390
0
      return FALSE;
391
0
    if (!disable_clipboard(settings))
392
0
      return FALSE;
393
0
    if (!disable_port(settings))
394
0
      return FALSE;
395
0
    if (!disable_pnp(settings))
396
0
      return FALSE;
397
0
    if (!apply_gw_policy(context))
398
0
      return FALSE;
399
0
  }
400
0
  else
401
0
  {
402
0
    if (flags & HTTP_TUNNEL_REDIR_DISABLE_DRIVE)
403
0
    {
404
0
      WLog_Print(log, WLOG_INFO, "[%s] policy denies drive redirections", module);
405
0
      if (!disable_drive(settings))
406
0
        return FALSE;
407
0
    }
408
0
    if (flags & HTTP_TUNNEL_REDIR_DISABLE_PRINTER)
409
0
    {
410
0
      WLog_Print(log, WLOG_INFO, "[%s] policy denies printer redirections", module);
411
0
      if (!disable_printers(settings))
412
0
        return FALSE;
413
0
    }
414
0
    if (flags & HTTP_TUNNEL_REDIR_DISABLE_PORT)
415
0
    {
416
0
      WLog_Print(log, WLOG_INFO, "[%s] policy denies port redirections", module);
417
0
      if (!disable_port(settings))
418
0
        return FALSE;
419
0
    }
420
0
    if (flags & HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD)
421
0
    {
422
0
      WLog_Print(log, WLOG_INFO, "[%s] policy denies clipboard redirections", module);
423
0
      if (!disable_clipboard(settings))
424
0
        return FALSE;
425
0
    }
426
0
    if (flags & HTTP_TUNNEL_REDIR_DISABLE_PNP)
427
0
    {
428
0
      WLog_Print(log, WLOG_INFO, "[%s] policy denies PNP redirections", module);
429
0
      if (!disable_pnp(settings))
430
0
        return FALSE;
431
0
    }
432
0
    if (flags != 0)
433
0
    {
434
0
      if (!apply_gw_policy(context))
435
0
        return FALSE;
436
0
    }
437
0
  }
438
0
  return TRUE;
439
0
}
440
441
char* utils_redir_flags_to_string(UINT32 flags, char* buffer, size_t size)
442
0
{
443
0
  winpr_str_append("{", buffer, size, "");
444
0
  if (flags & HTTP_TUNNEL_REDIR_ENABLE_ALL)
445
0
    winpr_str_append("ENABLE_ALL", buffer, size, "|");
446
0
  if (flags & HTTP_TUNNEL_REDIR_DISABLE_ALL)
447
0
    winpr_str_append("DISABLE_ALL", buffer, size, "|");
448
0
  if (flags & HTTP_TUNNEL_REDIR_DISABLE_DRIVE)
449
0
    winpr_str_append("DISABLE_DRIVE", buffer, size, "|");
450
0
  if (flags & HTTP_TUNNEL_REDIR_DISABLE_PRINTER)
451
0
    winpr_str_append("DISABLE_PRINTER", buffer, size, "|");
452
0
  if (flags & HTTP_TUNNEL_REDIR_DISABLE_PORT)
453
0
    winpr_str_append("DISABLE_PORT", buffer, size, "|");
454
0
  if (flags & HTTP_TUNNEL_REDIR_DISABLE_CLIPBOARD)
455
0
    winpr_str_append("DISABLE_CLIPBOARD", buffer, size, "|");
456
0
  if (flags & HTTP_TUNNEL_REDIR_DISABLE_PNP)
457
0
    winpr_str_append("DISABLE_PNP", buffer, size, "|");
458
459
0
  char fbuffer[16] = { 0 };
460
0
  _snprintf(fbuffer, sizeof(fbuffer), "[0x%08" PRIx32 "]", flags);
461
462
0
  winpr_str_append(fbuffer, buffer, size, " ");
463
0
  winpr_str_append("{", buffer, size, "}");
464
0
  return buffer;
465
0
}
466
467
BOOL utils_reload_channels(rdpContext* context)
468
0
{
469
0
  WINPR_ASSERT(context);
470
471
0
  freerdp_channels_disconnect(context->channels, context->instance);
472
0
  freerdp_channels_close(context->channels, context->instance);
473
0
  freerdp_channels_free(context->channels);
474
0
  context->channels = freerdp_channels_new(context->instance);
475
0
  WINPR_ASSERT(context->channels);
476
477
0
  BOOL rc = TRUE;
478
0
  IFCALLRET(context->instance->LoadChannels, rc, context->instance);
479
0
  if (rc)
480
0
    return freerdp_channels_pre_connect(context->channels, context->instance) == CHANNEL_RC_OK;
481
0
  return rc;
482
0
}