Coverage Report

Created: 2026-08-31 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/libfreerdp/core/freerdp.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * FreeRDP Core
4
 *
5
 * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 * Copyright 2015 Thincast Technologies GmbH
7
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8
 *
9
 * Licensed under the Apache License, Version 2.0 (the "License");
10
 * you may not use this file except in compliance with the License.
11
 * You may obtain a copy of the License at
12
 *
13
 *     http://www.apache.org/licenses/LICENSE-2.0
14
 *
15
 * Unless required by applicable law or agreed to in writing, software
16
 * distributed under the License is distributed on an "AS IS" BASIS,
17
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18
 * See the License for the specific language governing permissions and
19
 * limitations under the License.
20
 */
21
22
#include <freerdp/config.h>
23
24
#include "settings.h"
25
26
#include <string.h>
27
#include <stdarg.h>
28
#include <time.h>
29
30
#include "rdp.h"
31
#include "input.h"
32
#include "update.h"
33
#include "surface.h"
34
#include "transport.h"
35
#include "connection.h"
36
#include "message.h"
37
#include <freerdp/buildflags.h>
38
#include "gateway/rpc_fault.h"
39
#include "../cache/cache.h"
40
41
#include <winpr/assert.h>
42
43
#include <winpr/crt.h>
44
#include <winpr/string.h>
45
#include <winpr/stream.h>
46
#include <winpr/wtsapi.h>
47
#include <winpr/ssl.h>
48
#include <winpr/debug.h>
49
50
#include <freerdp/freerdp.h>
51
#include <freerdp/streamdump.h>
52
#include <freerdp/error.h>
53
#include <freerdp/event.h>
54
#include <freerdp/locale/keyboard.h>
55
#include <freerdp/locale/locale.h>
56
#include <freerdp/channels/channels.h>
57
#include <freerdp/version.h>
58
#include <freerdp/log.h>
59
#include <freerdp/utils/signal.h>
60
61
#include "../cache/pointer.h"
62
#include "utils.h"
63
64
9.62k
#define TAG FREERDP_TAG("core")
65
66
static void sig_abort_connect(int signum, const char* signame, void* ctx)
67
0
{
68
0
  rdpContext* context = (rdpContext*)ctx;
69
70
0
  WLog_INFO(TAG, "Signal %s [%d], terminating session %p", signame, signum,
71
0
            WINPR_CXX_COMPAT_CAST(const void*, context));
72
0
  if (context)
73
0
    freerdp_abort_connect_context(context);
74
0
}
75
76
/** Creates a new connection based on the settings found in the "instance" parameter
77
 *  It will use the callbacks registered on the structure to process the pre/post connect operations
78
 *  that the caller requires.
79
 *  @see struct rdp_freerdp in freerdp.h
80
 *
81
 *  @param instance - pointer to a rdp_freerdp structure that contains base information to establish
82
 * the connection. On return, this function will be initialized with the new connection's settings.
83
 *
84
 *  @return TRUE if successful. FALSE otherwise.
85
 *
86
 */
87
static int freerdp_connect_begin(freerdp* instance)
88
0
{
89
0
  BOOL rc = 0;
90
0
  rdpRdp* rdp = nullptr;
91
0
  BOOL status = TRUE;
92
0
  rdpSettings* settings = nullptr;
93
94
0
  if (!instance)
95
0
    return -1;
96
97
0
  WINPR_ASSERT(instance->context);
98
99
  /* We always set the return code to 0 before we start the connect sequence*/
100
0
  instance->ConnectionCallbackState = CLIENT_STATE_INITIAL;
101
0
  freerdp_set_last_error_log(instance->context, FREERDP_ERROR_SUCCESS);
102
0
  clearChannelError(instance->context);
103
0
  if (!utils_reset_abort(instance->context->rdp))
104
0
    return -1;
105
106
0
  rdp = instance->context->rdp;
107
0
  WINPR_ASSERT(rdp);
108
109
0
  settings = instance->context->settings;
110
0
  WINPR_ASSERT(settings);
111
112
0
  freerdp_channels_register_instance(instance->context->channels, instance);
113
114
0
  if (!freerdp_settings_set_default_order_support(settings))
115
0
    return -1;
116
117
0
  if (!freerdp_add_signal_cleanup_handler(instance->context, sig_abort_connect))
118
0
    return -1;
119
120
0
  IFCALLRET(instance->PreConnect, status, instance);
121
0
  instance->ConnectionCallbackState = CLIENT_STATE_PRECONNECT_PASSED;
122
123
0
  freerdp_settings_print_warnings(settings);
124
0
  if (status)
125
0
    status = freerdp_settings_enforce_monitor_exists(settings);
126
127
0
  if (status)
128
0
    status = freerdp_settings_enforce_consistency(settings);
129
130
0
  if (status)
131
0
    status = freerdp_settings_check_client_after_preconnect(settings);
132
133
0
  if (status)
134
0
    status = rdp_set_backup_settings(rdp);
135
0
  if (status)
136
0
    status = utils_reload_channels(instance->context);
137
138
0
  const UINT32 cp = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardCodePage);
139
0
  int64_t KeyboardLayout = freerdp_get_keyboard_default_layout_for_locale(cp);
140
0
  if (KeyboardLayout == 0)
141
0
    KeyboardLayout = freerdp_settings_get_uint32(settings, FreeRDP_KeyboardLayout);
142
143
0
  switch (KeyboardLayout)
144
0
  {
145
0
    case KBD_JAPANESE:
146
0
    case KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002:
147
0
    {
148
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardType,
149
0
                                       WINPR_KBD_TYPE_JAPANESE))
150
0
        return -1;
151
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardSubType, 2))
152
0
        return -1;
153
0
      if (!freerdp_settings_set_uint32(settings, FreeRDP_KeyboardFunctionKey, 12))
154
0
        return -1;
155
0
    }
156
0
    break;
157
0
    default:
158
0
      break;
159
0
  }
160
161
0
  if (!status)
162
0
  {
163
0
    rdpContext* context = instance->context;
164
0
    WINPR_ASSERT(context);
165
0
    freerdp_set_last_error_if_not(context, FREERDP_ERROR_PRE_CONNECT_FAILED);
166
167
0
    WLog_Print(context->log, WLOG_ERROR, "freerdp_pre_connect failed: %s",
168
0
               rdp_client_connection_state_string(instance->ConnectionCallbackState));
169
0
    return 0;
170
0
  }
171
172
0
  rc = rdp_client_connect(rdp);
173
174
  /* --authonly tests the connection without a UI */
175
0
  if (freerdp_settings_get_bool(rdp->settings, FreeRDP_AuthenticationOnly))
176
0
  {
177
0
    rdpContext* context = rdp->context;
178
0
    WINPR_ASSERT(context);
179
0
    WLog_Print(context->log, WLOG_ERROR, "Authentication only, exit status %" PRId32 "", rc);
180
0
    return 0;
181
0
  }
182
183
0
  return rc ? 1 : 0;
184
0
}
185
186
BOOL freerdp_connect(freerdp* instance)
187
0
{
188
0
  BOOL status = FALSE;
189
0
  ConnectionResultEventArgs e = WINPR_C_ARRAY_INIT;
190
0
  const int rc = freerdp_connect_begin(instance);
191
0
  rdpRdp* rdp = nullptr;
192
0
  UINT status2 = ERROR_INTERNAL_ERROR;
193
194
0
  WINPR_ASSERT(instance);
195
0
  WINPR_ASSERT(instance->context);
196
197
0
  rdp = instance->context->rdp;
198
0
  WINPR_ASSERT(rdp);
199
0
  WINPR_ASSERT(rdp->settings);
200
201
0
  if (rc > 0)
202
  /* Pointers might have changed in between */
203
0
  {
204
0
    rdp_update_internal* up = update_cast(rdp->update);
205
206
0
    if (freerdp_settings_get_bool(rdp->settings, FreeRDP_DumpRemoteFx))
207
0
    {
208
0
      up->pcap_rfx = pcap_open(
209
0
          freerdp_settings_get_string(rdp->settings, FreeRDP_DumpRemoteFxFile), TRUE);
210
211
0
      if (up->pcap_rfx)
212
0
        up->dump_rfx = TRUE;
213
0
    }
214
215
0
    pointer_cache_register_callbacks(instance->context->update);
216
0
    status = IFCALLRESULT(TRUE, instance->PostConnect, instance);
217
0
    instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
218
219
0
    if (status)
220
0
      status2 = freerdp_channels_post_connect(instance->context->channels, instance);
221
0
  }
222
0
  else
223
0
  {
224
0
    status2 = CHANNEL_RC_OK;
225
0
    if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_TRANSPORT_FAILED)
226
0
      status = freerdp_reconnect(instance);
227
0
    else
228
0
      goto freerdp_connect_finally;
229
0
  }
230
231
0
  if (!status || (status2 != CHANNEL_RC_OK) || !update_post_connect(instance->context->update))
232
0
  {
233
0
    rdpContext* context = instance->context;
234
0
    WINPR_ASSERT(context);
235
0
    WLog_Print(context->log, WLOG_ERROR, "freerdp_post_connect failed");
236
237
0
    freerdp_set_last_error_if_not(context, FREERDP_ERROR_POST_CONNECT_FAILED);
238
239
0
    status = FALSE;
240
0
    goto freerdp_connect_finally;
241
0
  }
242
243
0
  if (freerdp_settings_get_bool(rdp->settings, FreeRDP_PlayRemoteFx))
244
0
  {
245
0
    wStream* s = nullptr;
246
0
    rdp_update_internal* update = update_cast(instance->context->update);
247
0
    pcap_record record = WINPR_C_ARRAY_INIT;
248
249
0
    WINPR_ASSERT(update);
250
0
    const char* PlayRemoteFxFile =
251
0
        freerdp_settings_get_string(rdp->settings, FreeRDP_PlayRemoteFxFile);
252
0
    update->pcap_rfx = pcap_open(PlayRemoteFxFile, FALSE);
253
0
    status = FALSE;
254
255
0
    if (!update->pcap_rfx)
256
0
      goto freerdp_connect_finally;
257
0
    else
258
0
      update->play_rfx = TRUE;
259
260
0
    status = TRUE;
261
262
0
    while (pcap_has_next_record(update->pcap_rfx) && status)
263
0
    {
264
0
      if (!pcap_get_next_record_header(update->pcap_rfx, &record))
265
0
        break;
266
267
0
      s = transport_take_from_pool(rdp->transport, record.length);
268
0
      if (!s)
269
0
        break;
270
271
0
      record.data = Stream_Buffer(s);
272
0
      if (!pcap_get_next_record_content(update->pcap_rfx, &record))
273
0
        break;
274
0
      if (!Stream_SetLength(s, record.length))
275
0
      {
276
0
        status = FALSE;
277
0
        continue;
278
0
      }
279
0
      Stream_ResetPosition(s);
280
281
0
      if (!update_begin_paint(&update->common))
282
0
        status = FALSE;
283
0
      else
284
0
      {
285
0
        if (!update_recv_surfcmds(&update->common, s))
286
0
          status = FALSE;
287
288
0
        if (!update_end_paint(&update->common))
289
0
          status = FALSE;
290
0
      }
291
292
0
      Stream_Release(s);
293
0
    }
294
295
0
    pcap_close(update->pcap_rfx);
296
0
    update->pcap_rfx = nullptr;
297
0
    goto freerdp_connect_finally;
298
0
  }
299
300
0
  if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
301
0
    freerdp_set_last_error_log(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
302
303
0
  if (status)
304
0
    status = transport_set_connected_event(rdp->transport);
305
306
0
freerdp_connect_finally:
307
0
  EventArgsInit(&e, "freerdp");
308
0
  e.result = status ? 0 : -1;
309
0
  if (PubSub_OnConnectionResult(rdp->pubSub, instance->context, &e) < 0)
310
0
    return FALSE;
311
312
0
  if (!status)
313
0
    freerdp_disconnect(instance);
314
315
0
  return status;
316
0
}
317
318
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
319
BOOL freerdp_abort_connect(freerdp* instance)
320
0
{
321
0
  if (!instance)
322
0
    return FALSE;
323
324
0
  return freerdp_abort_connect_context(instance->context);
325
0
}
326
#endif
327
328
BOOL freerdp_abort_connect_context(rdpContext* context)
329
0
{
330
0
  if (!context)
331
0
    return FALSE;
332
333
0
  freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
334
0
  return utils_abort_connect(context->rdp);
335
0
}
336
337
#if defined(WITH_FREERDP_DEPRECATED)
338
BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, WINPR_ATTR_UNUSED void** wfds,
339
                     WINPR_ATTR_UNUSED int* wcount)
340
{
341
  rdpRdp* rdp = nullptr;
342
343
  WINPR_ASSERT(instance);
344
  WINPR_ASSERT(instance->context);
345
346
  rdp = instance->context->rdp;
347
  WINPR_ASSERT(rdp);
348
349
  transport_get_fds(rdp->transport, rfds, rcount);
350
  return TRUE;
351
}
352
#endif
353
354
BOOL freerdp_check_fds(freerdp* instance)
355
0
{
356
0
  int status = 0;
357
0
  rdpRdp* rdp = nullptr;
358
359
0
  if (!instance)
360
0
    return FALSE;
361
362
0
  if (!instance->context)
363
0
    return FALSE;
364
365
0
  if (!instance->context->rdp)
366
0
    return FALSE;
367
368
0
  rdp = instance->context->rdp;
369
0
  status = rdp_check_fds(rdp);
370
371
0
  if (status < 0)
372
0
  {
373
0
    TerminateEventArgs e;
374
0
    rdpContext* context = instance->context;
375
0
    WINPR_ASSERT(context);
376
377
0
    WLog_Print(context->log, WLOG_DEBUG, "rdp_check_fds() - %i", status);
378
0
    EventArgsInit(&e, "freerdp");
379
0
    e.code = 0;
380
0
    if (PubSub_OnTerminate(rdp->pubSub, context, &e) < 0)
381
0
      return FALSE;
382
0
    return FALSE;
383
0
  }
384
385
0
  return TRUE;
386
0
}
387
388
DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events, DWORD count)
389
0
{
390
0
  DWORD nCount = 0;
391
392
0
  WINPR_ASSERT(context);
393
0
  WINPR_ASSERT(context->rdp);
394
0
  WINPR_ASSERT(events || (count == 0));
395
396
0
  const size_t rrc = rdp_get_event_handles(context->rdp, &events[nCount], count - nCount);
397
0
  if (rrc == 0)
398
0
    return 0;
399
400
0
  nCount += WINPR_ASSERTING_INT_CAST(uint32_t, rrc);
401
402
0
  if (events && (nCount < count + 2))
403
0
  {
404
0
    events[nCount++] = freerdp_channels_get_event_handle(context->instance);
405
0
    events[nCount++] = getChannelErrorEventHandle(context);
406
0
  }
407
0
  else
408
0
    return 0;
409
410
0
  const SSIZE_T rc = freerdp_client_channel_get_registered_event_handles(
411
0
      context->channels, &events[nCount], count - nCount);
412
0
  if (rc < 0)
413
0
    return 0;
414
0
  return nCount + (DWORD)rc;
415
0
}
416
417
/* Resend mouse cursor position to prevent session lock in prevent-session-lock mode */
418
static BOOL freerdp_prevent_session_lock(rdpContext* context)
419
0
{
420
0
  WINPR_ASSERT(context);
421
0
  WINPR_ASSERT(context->input);
422
423
0
  rdp_input_internal* in = input_cast(context->input);
424
425
0
  UINT32 FakeMouseMotionInterval =
426
0
      freerdp_settings_get_uint32(context->settings, FreeRDP_FakeMouseMotionInterval);
427
0
  if (FakeMouseMotionInterval && in->lastInputTimestamp)
428
0
  {
429
0
    const time_t now = time(nullptr);
430
0
    if (WINPR_ASSERTING_INT_CAST(size_t, now) - in->lastInputTimestamp >
431
0
        FakeMouseMotionInterval)
432
0
    {
433
0
      WLog_Print(context->log, WLOG_DEBUG,
434
0
                 "fake mouse move: x=%d y=%d lastInputTimestamp=%" PRIu64 " "
435
0
                 "FakeMouseMotionInterval=%" PRIu32,
436
0
                 in->lastX, in->lastY, in->lastInputTimestamp, FakeMouseMotionInterval);
437
438
0
      BOOL status = freerdp_input_send_mouse_event(context->input, PTR_FLAGS_MOVE, in->lastX,
439
0
                                                   in->lastY);
440
0
      if (!status)
441
0
      {
442
0
        if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
443
0
          WLog_Print(context->log, WLOG_ERROR,
444
0
                     "freerdp_prevent_session_lock() failed - %" PRIi32 "", status);
445
446
0
        return FALSE;
447
0
      }
448
449
0
      return status;
450
0
    }
451
0
  }
452
453
0
  return TRUE;
454
0
}
455
456
BOOL freerdp_check_event_handles(rdpContext* context)
457
0
{
458
0
  WINPR_ASSERT(context);
459
460
0
  BOOL status = freerdp_check_fds(context->instance);
461
462
0
  if (!status)
463
0
  {
464
0
    if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
465
0
      WLog_Print(context->log, WLOG_ERROR, "freerdp_check_fds() failed - %" PRIi32 "",
466
0
                 status);
467
468
0
    return FALSE;
469
0
  }
470
471
0
  status = freerdp_channels_check_fds(context->channels, context->instance);
472
473
0
  if (!status)
474
0
  {
475
0
    if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
476
0
      WLog_Print(context->log, WLOG_ERROR,
477
0
                 "freerdp_channels_check_fds() failed - %" PRIi32 "", status);
478
479
0
    return FALSE;
480
0
  }
481
482
0
  status = checkChannelErrorEvent(context);
483
484
0
  if (!status)
485
0
  {
486
0
    if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
487
0
      WLog_Print(context->log, WLOG_ERROR, "checkChannelErrorEvent() failed - %" PRIi32 "",
488
0
                 status);
489
490
0
    return FALSE;
491
0
  }
492
493
0
  status = freerdp_prevent_session_lock(context);
494
495
0
  return status;
496
0
}
497
498
wMessageQueue* freerdp_get_message_queue(freerdp* instance, DWORD id)
499
0
{
500
0
  wMessageQueue* queue = nullptr;
501
502
0
  WINPR_ASSERT(instance);
503
504
0
  rdpContext* context = instance->context;
505
0
  WINPR_ASSERT(context);
506
507
0
  switch (id)
508
0
  {
509
0
    case FREERDP_UPDATE_MESSAGE_QUEUE:
510
0
    {
511
0
      rdp_update_internal* update = update_cast(context->update);
512
0
      queue = update->queue;
513
0
    }
514
0
    break;
515
516
0
    case FREERDP_INPUT_MESSAGE_QUEUE:
517
0
    {
518
0
      rdp_input_internal* input = input_cast(context->input);
519
0
      queue = input->queue;
520
0
    }
521
0
    break;
522
0
    default:
523
0
      break;
524
0
  }
525
526
0
  return queue;
527
0
}
528
529
HANDLE freerdp_get_message_queue_event_handle(freerdp* instance, DWORD id)
530
0
{
531
0
  HANDLE event = nullptr;
532
0
  wMessageQueue* queue = freerdp_get_message_queue(instance, id);
533
534
0
  if (queue)
535
0
    event = MessageQueue_Event(queue);
536
537
0
  return event;
538
0
}
539
540
int freerdp_message_queue_process_message(freerdp* instance, DWORD id, wMessage* message)
541
0
{
542
0
  int status = -1;
543
0
  rdpContext* context = nullptr;
544
545
0
  WINPR_ASSERT(instance);
546
547
0
  context = instance->context;
548
0
  WINPR_ASSERT(context);
549
550
0
  switch (id)
551
0
  {
552
0
    case FREERDP_UPDATE_MESSAGE_QUEUE:
553
0
      status = update_message_queue_process_message(context->update, message);
554
0
      break;
555
556
0
    case FREERDP_INPUT_MESSAGE_QUEUE:
557
0
      status = input_message_queue_process_message(context->input, message);
558
0
      break;
559
0
    default:
560
0
      break;
561
0
  }
562
563
0
  return status;
564
0
}
565
566
int freerdp_message_queue_process_pending_messages(freerdp* instance, DWORD id)
567
0
{
568
0
  int status = -1;
569
0
  rdpContext* context = nullptr;
570
571
0
  WINPR_ASSERT(instance);
572
573
0
  context = instance->context;
574
0
  WINPR_ASSERT(context);
575
576
0
  switch (id)
577
0
  {
578
0
    case FREERDP_UPDATE_MESSAGE_QUEUE:
579
0
      status = update_message_queue_process_pending_messages(context->update);
580
0
      break;
581
582
0
    case FREERDP_INPUT_MESSAGE_QUEUE:
583
0
      status = input_message_queue_process_pending_messages(context->input);
584
0
      break;
585
0
    default:
586
0
      break;
587
0
  }
588
589
0
  return status;
590
0
}
591
592
static BOOL freerdp_send_channel_data(freerdp* instance, UINT16 channelId, const BYTE* data,
593
                                      size_t size)
594
0
{
595
0
  WINPR_ASSERT(instance);
596
0
  WINPR_ASSERT(instance->context);
597
0
  WINPR_ASSERT(instance->context->rdp);
598
0
  return rdp_send_channel_data(instance->context->rdp, channelId, data, size);
599
0
}
600
601
static BOOL freerdp_send_channel_packet(freerdp* instance, UINT16 channelId, size_t totalSize,
602
                                        UINT32 flags, const BYTE* data, size_t chunkSize)
603
0
{
604
0
  WINPR_ASSERT(instance);
605
0
  WINPR_ASSERT(instance->context);
606
0
  WINPR_ASSERT(instance->context->rdp);
607
0
  return rdp_channel_send_packet(instance->context->rdp, channelId, totalSize, flags, data,
608
0
                                 chunkSize);
609
0
}
610
611
BOOL freerdp_disconnect(freerdp* instance)
612
0
{
613
0
  BOOL rc = TRUE;
614
615
0
  if (!instance || !instance->context)
616
0
    return FALSE;
617
618
0
  rdpRdp* rdp = instance->context->rdp;
619
0
  if (rdp)
620
0
  {
621
    /* Try to send a [MS-RDPBCGR] 1.3.1.4.1 User-Initiated on Client PDU, we don't care about
622
     * success */
623
0
    if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_CANCELLED)
624
0
    {
625
0
      (void)mcs_send_disconnect_provider_ultimatum(rdp->mcs,
626
0
                                                   Disconnect_Ultimatum_user_requested);
627
0
    }
628
0
  }
629
630
0
  utils_abort_connect(rdp);
631
632
0
  if (!rdp_client_disconnect(rdp))
633
0
    rc = FALSE;
634
635
0
  rdp_update_internal* up = nullptr;
636
0
  if (rdp && rdp->update)
637
0
  {
638
0
    up = update_cast(rdp->update);
639
640
0
    update_post_disconnect(rdp->update);
641
0
  }
642
643
0
  IFCALL(instance->PostDisconnect, instance);
644
0
  cache_free(instance->context->cache);
645
0
  instance->context->cache = nullptr;
646
647
0
  if (up)
648
0
  {
649
0
    update_dump_stats(rdp->update);
650
0
    if (up->pcap_rfx)
651
0
    {
652
0
      up->dump_rfx = FALSE;
653
0
      pcap_close(up->pcap_rfx);
654
0
      up->pcap_rfx = nullptr;
655
0
    }
656
0
  }
657
658
0
  if (instance->context->channels)
659
0
    freerdp_channels_close(instance->context->channels, instance);
660
661
0
  IFCALL(instance->PostFinalDisconnect, instance);
662
663
0
  freerdp_del_signal_cleanup_handler(instance->context, sig_abort_connect);
664
0
  return rc;
665
0
}
666
667
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
668
BOOL freerdp_disconnect_before_reconnect(freerdp* instance)
669
0
{
670
0
  WINPR_ASSERT(instance);
671
0
  return freerdp_disconnect_before_reconnect_context(instance->context);
672
0
}
673
#endif
674
675
BOOL freerdp_disconnect_before_reconnect_context(rdpContext* context)
676
0
{
677
0
  rdpRdp* rdp = nullptr;
678
679
0
  WINPR_ASSERT(context);
680
681
0
  rdp = context->rdp;
682
0
  return rdp_client_disconnect_and_clear(rdp);
683
0
}
684
685
BOOL freerdp_reconnect(freerdp* instance)
686
0
{
687
0
  rdpRdp* rdp = nullptr;
688
689
0
  WINPR_ASSERT(instance);
690
0
  WINPR_ASSERT(instance->context);
691
692
0
  if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_CANCELLED)
693
0
    return FALSE;
694
695
0
  rdp = instance->context->rdp;
696
697
0
  if (!utils_reset_abort(instance->context->rdp))
698
0
    return FALSE;
699
0
  return rdp_client_reconnect(rdp);
700
0
}
701
702
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
703
BOOL freerdp_shall_disconnect(const freerdp* instance)
704
0
{
705
0
  if (!instance)
706
0
    return FALSE;
707
708
0
  return freerdp_shall_disconnect_context(instance->context);
709
0
}
710
#endif
711
712
BOOL freerdp_shall_disconnect_context(const rdpContext* context)
713
76
{
714
76
  if (!context)
715
0
    return FALSE;
716
717
76
  return utils_abort_event_is_set(context->rdp);
718
76
}
719
720
BOOL freerdp_focus_required(freerdp* instance)
721
0
{
722
0
  rdpRdp* rdp = nullptr;
723
0
  BOOL bRetCode = FALSE;
724
725
0
  WINPR_ASSERT(instance);
726
0
  WINPR_ASSERT(instance->context);
727
728
0
  rdp = instance->context->rdp;
729
0
  WINPR_ASSERT(rdp);
730
731
0
  if (rdp->resendFocus)
732
0
  {
733
0
    bRetCode = TRUE;
734
0
    rdp->resendFocus = FALSE;
735
0
  }
736
737
0
  return bRetCode;
738
0
}
739
740
void freerdp_set_focus(freerdp* instance)
741
0
{
742
0
  rdpRdp* rdp = nullptr;
743
744
0
  WINPR_ASSERT(instance);
745
0
  WINPR_ASSERT(instance->context);
746
747
0
  rdp = instance->context->rdp;
748
0
  WINPR_ASSERT(rdp);
749
750
0
  rdp->resendFocus = TRUE;
751
0
}
752
753
void freerdp_get_version(int* major, int* minor, int* revision)
754
0
{
755
0
  if (major != nullptr)
756
0
    *major = FREERDP_VERSION_MAJOR;
757
758
0
  if (minor != nullptr)
759
0
    *minor = FREERDP_VERSION_MINOR;
760
761
0
  if (revision != nullptr)
762
0
    *revision = FREERDP_VERSION_REVISION;
763
0
}
764
765
const char* freerdp_get_version_string(void)
766
0
{
767
0
  return FREERDP_VERSION_FULL;
768
0
}
769
770
const char* freerdp_get_build_config(void)
771
0
{
772
0
  WINPR_PRAGMA_DIAG_PUSH
773
0
  WINPR_PRAGMA_DIAG_IGNORED_OVERLENGTH_STRINGS
774
0
  static const char build_config[] =
775
0
      "Build configuration: " FREERDP_BUILD_CONFIG "\n"
776
0
      "Build type:          " FREERDP_BUILD_TYPE "\n"
777
0
      "CFLAGS:              " FREERDP_CFLAGS "\n"
778
0
      "Compiler:            " FREERDP_COMPILER_ID ", " FREERDP_COMPILER_VERSION "\n"
779
0
      "Target architecture: " FREERDP_TARGET_ARCH "\n";
780
0
  WINPR_PRAGMA_DIAG_POP
781
0
  return build_config;
782
0
}
783
784
const char* freerdp_get_build_revision(void)
785
0
{
786
0
  return FREERDP_GIT_REVISION;
787
0
}
788
789
static wEventType FreeRDP_Events[] = {
790
  DEFINE_EVENT_ENTRY(WindowStateChange),   DEFINE_EVENT_ENTRY(ResizeWindow),
791
  DEFINE_EVENT_ENTRY(LocalResizeWindow),   DEFINE_EVENT_ENTRY(EmbedWindow),
792
  DEFINE_EVENT_ENTRY(PanningChange),       DEFINE_EVENT_ENTRY(ZoomingChange),
793
  DEFINE_EVENT_ENTRY(ErrorInfo),           DEFINE_EVENT_ENTRY(Terminate),
794
  DEFINE_EVENT_ENTRY(ConnectionResult),    DEFINE_EVENT_ENTRY(ChannelConnected),
795
  DEFINE_EVENT_ENTRY(ChannelDisconnected), DEFINE_EVENT_ENTRY(MouseEvent),
796
  DEFINE_EVENT_ENTRY(Activated),           DEFINE_EVENT_ENTRY(Timer),
797
  DEFINE_EVENT_ENTRY(GraphicsReset),       DEFINE_EVENT_ENTRY(UserNotification),
798
  DEFINE_EVENT_ENTRY(ChannelInitialized),  DEFINE_EVENT_ENTRY(ChannelTerminated),
799
  DEFINE_EVENT_ENTRY(StateChanged)
800
};
801
802
/** Allocator function for a rdp context.
803
 *  The function will allocate a rdpRdp structure using rdp_new(), then copy
804
 *  its contents to the appropriate fields in the rdp_freerdp structure given in parameters.
805
 *  It will also initialize the 'context' field in the rdp_freerdp structure as needed.
806
 *  If the caller has set the ContextNew callback in the 'instance' parameter, it will be called at
807
 * the end of the function.
808
 *
809
 *  @param instance - Pointer to the rdp_freerdp structure that will be initialized with the new
810
 * context.
811
 */
812
BOOL freerdp_context_new(freerdp* instance)
813
0
{
814
0
  return freerdp_context_new_ex(instance, nullptr);
815
0
}
816
817
static BOOL freerdp_common_context(rdpContext* context, AccessTokenType tokenType, char** token,
818
                                   size_t count, ...)
819
0
{
820
0
  BOOL rc = FALSE;
821
822
0
  WINPR_ASSERT(context);
823
0
  if (!context->instance || !context->instance->GetAccessToken)
824
0
    return TRUE;
825
826
0
  va_list ap = WINPR_C_ARRAY_INIT;
827
0
  va_start(ap, count);
828
0
  switch (tokenType)
829
0
  {
830
0
    case ACCESS_TOKEN_TYPE_AAD:
831
0
      if (count != 2)
832
0
      {
833
0
        WLog_ERR(TAG,
834
0
                 "ACCESS_TOKEN_TYPE_AAD expected 2 additional arguments, but got %" PRIuz
835
0
                 ", aborting",
836
0
                 count);
837
0
      }
838
0
      else
839
0
      {
840
0
        const char* scope = va_arg(ap, const char*);
841
0
        const char* req_cnf = va_arg(ap, const char*);
842
0
        rc = context->instance->GetAccessToken(context->instance, tokenType, token, count,
843
0
                                               scope, req_cnf);
844
0
      }
845
0
      break;
846
0
    case ACCESS_TOKEN_TYPE_AVD:
847
0
      if (count != 0)
848
0
      {
849
0
        WLog_WARN(TAG,
850
0
                  "ACCESS_TOKEN_TYPE_AVD expected 0 additional arguments, but got %" PRIuz
851
0
                  ", ignoring",
852
0
                  count);
853
0
      }
854
0
      else
855
0
      {
856
0
        rc = context->instance->GetAccessToken(context->instance, tokenType, token, count);
857
0
      }
858
0
      break;
859
0
    default:
860
0
      break;
861
0
  }
862
0
  va_end(ap);
863
864
0
  if (!rc)
865
0
    freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
866
867
0
  return rc;
868
0
}
869
870
BOOL freerdp_context_new_ex(freerdp* instance, rdpSettings* settings)
871
9.62k
{
872
9.62k
  rdpRdp* rdp = nullptr;
873
9.62k
  rdpContext* context = nullptr;
874
9.62k
  BOOL ret = TRUE;
875
876
9.62k
  WINPR_ASSERT(instance);
877
878
9.62k
  instance->context = context = (rdpContext*)calloc(1, instance->ContextSize);
879
880
9.62k
  if (!context)
881
0
    return FALSE;
882
883
9.62k
  context->log = WLog_Get(TAG);
884
9.62k
  if (!context->log)
885
0
    goto fail;
886
887
  /* Set to external settings, prevents rdp_new from creating its own instance */
888
9.62k
  context->settings = settings;
889
9.62k
  context->instance = instance;
890
9.62k
  context->ServerMode = FALSE;
891
9.62k
  context->disconnectUltimatum = 0;
892
893
9.62k
  context->metrics = metrics_new(context);
894
895
9.62k
  if (!context->metrics)
896
0
    goto fail;
897
898
9.62k
  rdp = rdp_new(context);
899
900
9.62k
  if (!rdp)
901
0
    goto fail;
902
903
9.62k
  context->rdp = rdp;
904
9.62k
  context->pubSub = rdp->pubSub;
905
906
9.62k
  if (!context->pubSub)
907
0
    goto fail;
908
909
9.62k
  PubSub_AddEventTypes(rdp->pubSub, FreeRDP_Events, ARRAYSIZE(FreeRDP_Events));
910
911
#if defined(WITH_FREERDP_DEPRECATED)
912
  instance->input = rdp->input;
913
  instance->update = rdp->update;
914
  instance->settings = rdp->settings;
915
  instance->autodetect = rdp->autodetect;
916
#endif
917
918
9.62k
  instance->heartbeat = rdp->heartbeat;
919
9.62k
  context->graphics = graphics_new(context);
920
921
9.62k
  if (!context->graphics)
922
0
    goto fail;
923
924
9.62k
  context->input = rdp->input;
925
9.62k
  context->update = rdp->update;
926
9.62k
  context->settings = rdp->settings;
927
9.62k
  context->autodetect = rdp->autodetect;
928
929
9.62k
  if (!(context->errorDescription = calloc(1, 500)))
930
0
  {
931
0
    WLog_Print(context->log, WLOG_ERROR, "calloc failed!");
932
0
    goto fail;
933
0
  }
934
935
9.62k
  if (!(context->channelErrorEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
936
0
  {
937
0
    WLog_Print(context->log, WLOG_ERROR, "CreateEvent failed!");
938
0
    goto fail;
939
0
  }
940
941
9.62k
  update_register_client_callbacks(rdp->update);
942
943
9.62k
  if (!(context->channels = freerdp_channels_new(instance)))
944
0
    goto fail;
945
946
9.62k
  context->dump = stream_dump_new();
947
9.62k
  if (!context->dump)
948
0
    goto fail;
949
950
  /* Fallback:
951
   * Client common library might set a function pointer to handle this, but here we provide a
952
   * default implementation that simply calls instance->GetAccessToken.
953
   */
954
9.62k
  if (!freerdp_set_common_access_token(context, freerdp_common_context))
955
0
    goto fail;
956
957
9.62k
  IFCALLRET(instance->ContextNew, ret, instance, context);
958
959
9.62k
  if (!ret)
960
0
    goto fail;
961
962
9.62k
  return TRUE;
963
964
0
fail:
965
0
  freerdp_context_free(instance);
966
0
  return FALSE;
967
9.62k
}
968
969
BOOL freerdp_context_reset(freerdp* instance)
970
0
{
971
0
  if (!instance)
972
0
    return FALSE;
973
974
0
  WINPR_ASSERT(instance->context);
975
0
  rdpRdp* rdp = instance->context->rdp;
976
977
0
  return rdp_reset_runtime_settings(rdp);
978
0
}
979
980
/** Deallocator function for a rdp context.
981
 *  The function will deallocate the resources from the 'instance' parameter that were allocated
982
 * from a call to freerdp_context_new(). If the ContextFree callback is set in the 'instance'
983
 * parameter, it will be called before deallocation occurs.
984
 *
985
 *  @param instance - Pointer to the rdp_freerdp structure that was initialized by a call to
986
 * freerdp_context_new(). On return, the fields associated to the context are invalid.
987
 */
988
void freerdp_context_free(freerdp* instance)
989
9.62k
{
990
9.62k
  rdpContext* ctx = nullptr;
991
992
9.62k
  if (!instance)
993
0
    return;
994
995
9.62k
  if (!instance->context)
996
0
    return;
997
998
9.62k
  ctx = instance->context;
999
1000
9.62k
  IFCALL(instance->ContextFree, instance, ctx);
1001
9.62k
  rdp_free(ctx->rdp);
1002
9.62k
  ctx->rdp = nullptr;
1003
9.62k
  ctx->settings = nullptr; /* owned by rdpRdp */
1004
1005
9.62k
  graphics_free(ctx->graphics);
1006
9.62k
  ctx->graphics = nullptr;
1007
1008
9.62k
  metrics_free(ctx->metrics);
1009
9.62k
  ctx->metrics = nullptr;
1010
1011
9.62k
  if (ctx->channelErrorEvent)
1012
9.62k
    (void)CloseHandle(ctx->channelErrorEvent);
1013
9.62k
  ctx->channelErrorEvent = nullptr;
1014
1015
9.62k
  free(ctx->errorDescription);
1016
9.62k
  ctx->errorDescription = nullptr;
1017
1018
9.62k
  freerdp_channels_free(ctx->channels);
1019
9.62k
  ctx->channels = nullptr;
1020
1021
9.62k
  freerdp_client_codecs_free(ctx->codecs);
1022
9.62k
  ctx->codecs = nullptr;
1023
1024
9.62k
  stream_dump_free(ctx->dump);
1025
9.62k
  ctx->dump = nullptr;
1026
1027
9.62k
  ctx->input = nullptr;      /* owned by rdpRdp */
1028
9.62k
  ctx->update = nullptr;     /* owned by rdpRdp */
1029
9.62k
  ctx->settings = nullptr;   /* owned by rdpRdp */
1030
9.62k
  ctx->autodetect = nullptr; /* owned by rdpRdp */
1031
1032
9.62k
  free(ctx);
1033
9.62k
  instance->context = nullptr;
1034
#if defined(WITH_FREERDP_DEPRECATED)
1035
  instance->input = nullptr;      /* owned by rdpRdp */
1036
  instance->update = nullptr;     /* owned by rdpRdp */
1037
  instance->settings = nullptr;   /* owned by rdpRdp */
1038
  instance->autodetect = nullptr; /* owned by rdpRdp */
1039
#endif
1040
9.62k
  instance->heartbeat = nullptr; /* owned by rdpRdp */
1041
9.62k
}
1042
1043
int freerdp_get_disconnect_ultimatum(const rdpContext* context)
1044
0
{
1045
0
  WINPR_ASSERT(context);
1046
0
  return context->disconnectUltimatum;
1047
0
}
1048
1049
UINT32 freerdp_error_info(const freerdp* instance)
1050
0
{
1051
0
  WINPR_ASSERT(instance);
1052
0
  WINPR_ASSERT(instance->context);
1053
0
  WINPR_ASSERT(instance->context->rdp);
1054
0
  return instance->context->rdp->errorInfo;
1055
0
}
1056
1057
void freerdp_set_error_info(rdpRdp* rdp, UINT32 error)
1058
0
{
1059
0
  if (!rdp)
1060
0
    return;
1061
1062
0
  rdp_set_error_info(rdp, error);
1063
0
}
1064
1065
BOOL freerdp_send_error_info(rdpRdp* rdp)
1066
0
{
1067
0
  if (!rdp)
1068
0
    return FALSE;
1069
1070
0
  return rdp_send_error_info(rdp);
1071
0
}
1072
1073
UINT32 freerdp_get_last_error(const rdpContext* context)
1074
109
{
1075
109
  WINPR_ASSERT(context);
1076
109
  return context->LastError;
1077
109
}
1078
1079
const char* freerdp_get_last_error_name(UINT32 code)
1080
1.53k
{
1081
1.53k
  const char* name = nullptr;
1082
1.53k
  const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1083
1.53k
  const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1084
1085
1.53k
  switch (cls)
1086
1.53k
  {
1087
0
    case FREERDP_ERROR_ERRBASE_CLASS:
1088
0
      name = freerdp_get_error_base_name(type);
1089
0
      break;
1090
1091
969
    case FREERDP_ERROR_ERRINFO_CLASS:
1092
969
      name = freerdp_get_error_info_name(type);
1093
969
      break;
1094
1095
326
    case FREERDP_ERROR_CONNECT_CLASS:
1096
326
      name = freerdp_get_error_connect_name(type);
1097
326
      break;
1098
1099
238
    default:
1100
238
      name = rpc_error_to_string(code);
1101
238
      break;
1102
1.53k
  }
1103
1104
1.53k
  return name;
1105
1.53k
}
1106
1107
const char* freerdp_get_last_error_string(UINT32 code)
1108
0
{
1109
0
  const char* string = nullptr;
1110
0
  const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1111
0
  const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1112
1113
0
  switch (cls)
1114
0
  {
1115
0
    case FREERDP_ERROR_ERRBASE_CLASS:
1116
0
      string = freerdp_get_error_base_string(type);
1117
0
      break;
1118
1119
0
    case FREERDP_ERROR_ERRINFO_CLASS:
1120
0
      string = freerdp_get_error_info_string(type);
1121
0
      break;
1122
1123
0
    case FREERDP_ERROR_CONNECT_CLASS:
1124
0
      string = freerdp_get_error_connect_string(type);
1125
0
      break;
1126
1127
0
    default:
1128
0
      string = rpc_error_to_string(code);
1129
0
      break;
1130
0
  }
1131
1132
0
  return string;
1133
0
}
1134
1135
const char* freerdp_get_last_error_category(UINT32 code)
1136
0
{
1137
0
  const char* string = nullptr;
1138
0
  const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
1139
0
  const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
1140
1141
0
  switch (cls)
1142
0
  {
1143
0
    case FREERDP_ERROR_ERRBASE_CLASS:
1144
0
      string = freerdp_get_error_base_category(type);
1145
0
      break;
1146
1147
0
    case FREERDP_ERROR_ERRINFO_CLASS:
1148
0
      string = freerdp_get_error_info_category(type);
1149
0
      break;
1150
1151
0
    case FREERDP_ERROR_CONNECT_CLASS:
1152
0
      string = freerdp_get_error_connect_category(type);
1153
0
      break;
1154
1155
0
    default:
1156
0
      string = rpc_error_to_category(code);
1157
0
      break;
1158
0
  }
1159
1160
0
  return string;
1161
0
}
1162
1163
void freerdp_set_last_error_ex(rdpContext* context, UINT32 lastError, const char* fkt,
1164
                               const char* file, int line)
1165
1.40k
{
1166
1.40k
  WINPR_ASSERT(context);
1167
1.40k
  WINPR_ASSERT(line >= 0);
1168
1169
1.40k
  if (lastError)
1170
1.39k
  {
1171
1.39k
    if (WLog_IsLevelActive(context->log, WLOG_ERROR))
1172
1.39k
    {
1173
1.39k
      WLog_PrintTextMessage(context->log, WLOG_ERROR, (size_t)line, file, fkt,
1174
1.39k
                            "%s [0x%08" PRIX32 "]", freerdp_get_last_error_name(lastError),
1175
1.39k
                            lastError);
1176
1.39k
    }
1177
1.39k
  }
1178
1179
1.40k
  if (lastError == FREERDP_ERROR_SUCCESS)
1180
6
  {
1181
6
    if (WLog_IsLevelActive(context->log, WLOG_DEBUG))
1182
0
      WLog_PrintTextMessage(context->log, WLOG_DEBUG, (size_t)line, file, fkt,
1183
0
                            "resetting error state");
1184
6
  }
1185
1.39k
  else if (context->LastError != FREERDP_ERROR_SUCCESS)
1186
68
  {
1187
68
    if (WLog_IsLevelActive(context->log, WLOG_ERROR))
1188
68
    {
1189
68
      WLog_PrintTextMessage(context->log, WLOG_ERROR, (size_t)line, file, fkt,
1190
68
                            "TODO: Trying to set error code %s, but %s already set!",
1191
68
                            freerdp_get_last_error_name(lastError),
1192
68
                            freerdp_get_last_error_name(context->LastError));
1193
68
    }
1194
68
  }
1195
1.40k
  context->LastError = lastError;
1196
1.40k
}
1197
1198
const char* freerdp_get_logon_error_info_type_ex(UINT32 type, char* buffer, size_t size)
1199
0
{
1200
0
  const char* str = freerdp_get_logon_error_info_type(type);
1201
0
  (void)_snprintf(buffer, size, "%s(0x%04" PRIx32 ")", str, type);
1202
0
  return buffer;
1203
0
}
1204
1205
const char* freerdp_get_logon_error_info_type(UINT32 type)
1206
109
{
1207
109
#define CASE_ENTRY(x) \
1208
109
  case x:           \
1209
1
    return #x
1210
109
  switch (type)
1211
109
  {
1212
0
    CASE_ENTRY(LOGON_MSG_SESSION_BUSY_OPTIONS);
1213
0
    CASE_ENTRY(LOGON_MSG_DISCONNECT_REFUSED);
1214
0
    CASE_ENTRY(LOGON_MSG_NO_PERMISSION);
1215
0
    CASE_ENTRY(LOGON_MSG_BUMP_OPTIONS);
1216
0
    CASE_ENTRY(LOGON_MSG_RECONNECT_OPTIONS);
1217
0
    CASE_ENTRY(LOGON_MSG_SESSION_TERMINATE);
1218
0
    CASE_ENTRY(LOGON_MSG_SESSION_CONTINUE);
1219
1
    CASE_ENTRY(ERROR_CODE_ACCESS_DENIED);
1220
1221
108
    default:
1222
108
      return "UNKNOWN";
1223
109
  }
1224
109
#undef CASE_ENTRY
1225
109
}
1226
1227
const char* freerdp_get_logon_error_info_data(UINT32 data)
1228
109
{
1229
109
  switch (data)
1230
109
  {
1231
10
    case LOGON_FAILED_BAD_PASSWORD:
1232
10
      return "LOGON_FAILED_BAD_PASSWORD";
1233
1234
1
    case LOGON_FAILED_UPDATE_PASSWORD:
1235
1
      return "LOGON_FAILED_UPDATE_PASSWORD";
1236
1237
6
    case LOGON_FAILED_OTHER:
1238
6
      return "LOGON_FAILED_OTHER";
1239
1240
1
    case LOGON_WARNING:
1241
1
      return "LOGON_WARNING";
1242
1243
91
    default:
1244
91
      return "SESSION_ID";
1245
109
  }
1246
109
}
1247
1248
const char* freerdp_get_logon_error_info_data_ex(UINT32 data, char* buffer, size_t size)
1249
0
{
1250
0
  const char* str = freerdp_get_logon_error_info_data(data);
1251
0
  (void)_snprintf(buffer, size, "%s(0x%04" PRIx32 ")", str, data);
1252
0
  return buffer;
1253
0
}
1254
1255
/** Allocator function for the rdp_freerdp structure.
1256
 *  @return an allocated structure filled with 0s. Need to be deallocated using freerdp_free()
1257
 */
1258
freerdp* freerdp_new(void)
1259
9.62k
{
1260
9.62k
  freerdp* instance = nullptr;
1261
9.62k
  instance = (freerdp*)calloc(1, sizeof(freerdp));
1262
1263
9.62k
  if (!instance)
1264
0
    return nullptr;
1265
1266
9.62k
  instance->ContextSize = sizeof(rdpContext);
1267
9.62k
  instance->SendChannelData = freerdp_send_channel_data;
1268
9.62k
  instance->SendChannelPacket = freerdp_send_channel_packet;
1269
9.62k
  instance->ReceiveChannelData = freerdp_channels_data;
1270
9.62k
  return instance;
1271
9.62k
}
1272
1273
/** Deallocator function for the rdp_freerdp structure.
1274
 *  @param instance - pointer to the rdp_freerdp structure to deallocate.
1275
 *                    On return, this pointer is not valid anymore.
1276
 */
1277
void freerdp_free(freerdp* instance)
1278
9.62k
{
1279
9.62k
  free(instance);
1280
9.62k
}
1281
1282
ULONG freerdp_get_transport_sent(const rdpContext* context, BOOL resetCount)
1283
0
{
1284
0
  WINPR_ASSERT(context);
1285
0
  WINPR_ASSERT(context->rdp);
1286
0
  UINT64 rc = transport_get_bytes_sent(context->rdp->transport, resetCount);
1287
0
  return WINPR_CXX_COMPAT_CAST(ULONG, MIN(rc, UINT32_MAX));
1288
0
}
1289
1290
BOOL freerdp_nla_impersonate(rdpContext* context)
1291
0
{
1292
0
  rdpNla* nla = nullptr;
1293
1294
0
  if (!context)
1295
0
    return FALSE;
1296
1297
0
  if (!context->rdp)
1298
0
    return FALSE;
1299
1300
0
  if (!context->rdp->transport)
1301
0
    return FALSE;
1302
1303
0
  nla = transport_get_nla(context->rdp->transport);
1304
0
  return nla_impersonate(nla);
1305
0
}
1306
1307
BOOL freerdp_nla_revert_to_self(rdpContext* context)
1308
0
{
1309
0
  rdpNla* nla = nullptr;
1310
1311
0
  if (!context)
1312
0
    return FALSE;
1313
1314
0
  if (!context->rdp)
1315
0
    return FALSE;
1316
1317
0
  if (!context->rdp->transport)
1318
0
    return FALSE;
1319
1320
0
  nla = transport_get_nla(context->rdp->transport);
1321
0
  return nla_revert_to_self(nla);
1322
0
}
1323
1324
UINT32 freerdp_get_nla_sspi_error(const rdpContext* context)
1325
0
{
1326
0
  WINPR_ASSERT(context);
1327
0
  WINPR_ASSERT(context->rdp);
1328
0
  WINPR_ASSERT(context->rdp->transport);
1329
1330
0
  rdpNla* nla = context->rdp->nla;
1331
0
  if (!nla)
1332
0
    nla = transport_get_nla(context->rdp->transport);
1333
0
  return (UINT32)nla_get_sspi_error(nla);
1334
0
}
1335
1336
BOOL freerdp_nla_encrypt(rdpContext* context, const SecBuffer* inBuffer, SecBuffer* outBuffer)
1337
0
{
1338
0
  WINPR_ASSERT(context);
1339
0
  WINPR_ASSERT(context->rdp);
1340
1341
0
  rdpNla* nla = context->rdp->nla;
1342
0
  return nla_encrypt(nla, inBuffer, outBuffer);
1343
0
}
1344
1345
BOOL freerdp_nla_decrypt(rdpContext* context, const SecBuffer* inBuffer, SecBuffer* outBuffer)
1346
0
{
1347
0
  WINPR_ASSERT(context);
1348
0
  WINPR_ASSERT(context->rdp);
1349
1350
0
  rdpNla* nla = context->rdp->nla;
1351
0
  return nla_decrypt(nla, inBuffer, outBuffer);
1352
0
}
1353
1354
SECURITY_STATUS freerdp_nla_QueryContextAttributes(rdpContext* context, DWORD ulAttr, PVOID pBuffer)
1355
0
{
1356
0
  WINPR_ASSERT(context);
1357
0
  WINPR_ASSERT(context->rdp);
1358
1359
0
  rdpNla* nla = context->rdp->nla;
1360
0
  if (!nla)
1361
0
    nla = transport_get_nla(context->rdp->transport);
1362
1363
0
  WINPR_ASSERT(nla);
1364
1365
0
  return nla_QueryContextAttributes(nla, ulAttr, pBuffer);
1366
0
}
1367
1368
SECURITY_STATUS freerdp_nla_FreeContextBuffer(rdpContext* context, PVOID pBuffer)
1369
0
{
1370
0
  WINPR_ASSERT(context);
1371
0
  WINPR_ASSERT(context->rdp);
1372
1373
0
  rdpNla* nla = context->rdp->nla;
1374
0
  if (!nla)
1375
0
    nla = transport_get_nla(context->rdp->transport);
1376
1377
0
  WINPR_ASSERT(nla);
1378
1379
0
  return nla_FreeContextBuffer(nla, pBuffer);
1380
0
}
1381
1382
HANDLE getChannelErrorEventHandle(rdpContext* context)
1383
0
{
1384
0
  WINPR_ASSERT(context);
1385
0
  return context->channelErrorEvent;
1386
0
}
1387
1388
BOOL checkChannelErrorEvent(rdpContext* context)
1389
0
{
1390
0
  WINPR_ASSERT(context);
1391
1392
0
  if (WaitForSingleObject(context->channelErrorEvent, 0) == WAIT_OBJECT_0)
1393
0
  {
1394
0
    WLog_Print(context->log, WLOG_ERROR, "%s. Error was %" PRIu32 "", context->errorDescription,
1395
0
               context->channelErrorNum);
1396
0
    return FALSE;
1397
0
  }
1398
1399
0
  return TRUE;
1400
0
}
1401
1402
/**
1403
 * Function description
1404
 *
1405
 * @return 0 on success, otherwise a Win32 error code
1406
 */
1407
UINT getChannelError(const rdpContext* context)
1408
0
{
1409
0
  WINPR_ASSERT(context);
1410
0
  return context->channelErrorNum;
1411
0
}
1412
1413
const char* getChannelErrorDescription(const rdpContext* context)
1414
0
{
1415
0
  WINPR_ASSERT(context);
1416
0
  return context->errorDescription;
1417
0
}
1418
1419
void clearChannelError(rdpContext* context)
1420
0
{
1421
0
  WINPR_ASSERT(context);
1422
0
  context->channelErrorNum = 0;
1423
0
  memset(context->errorDescription, 0, 500);
1424
0
  (void)ResetEvent(context->channelErrorEvent);
1425
0
}
1426
1427
WINPR_ATTR_FORMAT_ARG(3, 4)
1428
void setChannelError(rdpContext* context, UINT errorNum, WINPR_FORMAT_ARG const char* format, ...)
1429
0
{
1430
0
  va_list ap = WINPR_C_ARRAY_INIT;
1431
0
  va_start(ap, format);
1432
1433
0
  WINPR_ASSERT(context);
1434
1435
0
  context->channelErrorNum = errorNum;
1436
0
  (void)vsnprintf(context->errorDescription, 499, format, ap);
1437
0
  va_end(ap);
1438
0
  (void)SetEvent(context->channelErrorEvent);
1439
0
}
1440
1441
const char* freerdp_nego_get_routing_token(const rdpContext* context, DWORD* length)
1442
0
{
1443
0
  if (!context || !context->rdp)
1444
0
    return nullptr;
1445
1446
0
  return (const char*)nego_get_routing_token(context->rdp->nego, length);
1447
0
}
1448
1449
BOOL freerdp_io_callback_set_event(rdpContext* context, BOOL set)
1450
0
{
1451
0
  WINPR_ASSERT(context);
1452
0
  return rdp_io_callback_set_event(context->rdp, set);
1453
0
}
1454
1455
const rdpTransportIo* freerdp_get_io_callbacks(rdpContext* context)
1456
0
{
1457
0
  WINPR_ASSERT(context);
1458
0
  return rdp_get_io_callbacks(context->rdp);
1459
0
}
1460
1461
BOOL freerdp_set_io_callbacks(rdpContext* context, const rdpTransportIo* io_callbacks)
1462
0
{
1463
0
  WINPR_ASSERT(context);
1464
0
  return rdp_set_io_callbacks(context->rdp, io_callbacks);
1465
0
}
1466
1467
BOOL freerdp_set_io_callback_context(rdpContext* context, void* usercontext)
1468
0
{
1469
0
  WINPR_ASSERT(context);
1470
0
  return rdp_set_io_callback_context(context->rdp, usercontext);
1471
0
}
1472
1473
void* freerdp_get_io_callback_context(rdpContext* context)
1474
0
{
1475
0
  WINPR_ASSERT(context);
1476
0
  return rdp_get_io_callback_context(context->rdp);
1477
0
}
1478
1479
CONNECTION_STATE freerdp_get_state(const rdpContext* context)
1480
0
{
1481
0
  WINPR_ASSERT(context);
1482
0
  return rdp_get_state(context->rdp);
1483
0
}
1484
1485
const char* freerdp_state_string(CONNECTION_STATE state)
1486
0
{
1487
0
  return rdp_state_string(state);
1488
0
}
1489
1490
BOOL freerdp_is_active_state(const rdpContext* context)
1491
0
{
1492
0
  WINPR_ASSERT(context);
1493
0
  return rdp_is_active_state(context->rdp);
1494
0
}
1495
1496
BOOL freerdp_channels_from_mcs(rdpSettings* settings, const rdpContext* context)
1497
0
{
1498
0
  WINPR_ASSERT(context);
1499
0
  return rdp_channels_from_mcs(settings, context->rdp);
1500
0
}
1501
1502
HANDLE freerdp_abort_event(rdpContext* context)
1503
0
{
1504
0
  WINPR_ASSERT(context);
1505
0
  return utils_get_abort_event(context->rdp);
1506
0
}
1507
1508
static void test_mcs_free(rdpMcs* mcs)
1509
35.7k
{
1510
35.7k
  if (!mcs)
1511
0
    return;
1512
1513
35.7k
  if (mcs->context)
1514
35.7k
  {
1515
35.7k
    rdpSettings* settings = mcs->context->settings;
1516
35.7k
    freerdp_settings_free(settings);
1517
35.7k
  }
1518
35.7k
  free(mcs->context);
1519
1520
35.7k
  mcs_free(mcs);
1521
35.7k
}
1522
1523
static rdpMcs* test_mcs_new(void)
1524
35.7k
{
1525
35.7k
  rdpSettings* settings = freerdp_settings_new(0);
1526
35.7k
  rdpContext* context = calloc(1, sizeof(rdpContext));
1527
1528
35.7k
  if (!settings)
1529
0
    goto fail;
1530
35.7k
  if (!freerdp_settings_set_bool(settings, FreeRDP_TransportDumpReplay, TRUE))
1531
0
    goto fail;
1532
1533
35.7k
  if (!context)
1534
0
    goto fail;
1535
35.7k
  context->settings = settings;
1536
35.7k
  return mcs_new(context);
1537
1538
0
fail:
1539
0
  free(context);
1540
0
  freerdp_settings_free(settings);
1541
1542
0
  return nullptr;
1543
35.7k
}
1544
1545
BOOL freerdp_is_valid_mcs_create_request(const BYTE* data, size_t size)
1546
17.8k
{
1547
1548
17.8k
  wStream sbuffer = WINPR_C_ARRAY_INIT;
1549
17.8k
  wStream* s = Stream_StaticConstInit(&sbuffer, data, size);
1550
1551
17.8k
  WINPR_ASSERT(data || (size == 0));
1552
17.8k
  WINPR_ASSERT(s);
1553
1554
17.8k
  rdpMcs* mcs = test_mcs_new();
1555
17.8k
  WINPR_ASSERT(mcs);
1556
1557
17.8k
  BOOL result = mcs_recv_connect_initial(mcs, s);
1558
17.8k
  test_mcs_free(mcs);
1559
17.8k
  return result;
1560
17.8k
}
1561
1562
BOOL freerdp_is_valid_mcs_create_response(const BYTE* data, size_t size)
1563
17.8k
{
1564
1565
17.8k
  wStream sbuffer = WINPR_C_ARRAY_INIT;
1566
17.8k
  wStream* s = Stream_StaticConstInit(&sbuffer, data, size);
1567
1568
17.8k
  WINPR_ASSERT(data || (size == 0));
1569
17.8k
  WINPR_ASSERT(s);
1570
1571
17.8k
  rdpMcs* mcs = test_mcs_new();
1572
17.8k
  WINPR_ASSERT(mcs);
1573
1574
17.8k
  BOOL result = mcs_recv_connect_response(mcs, s);
1575
17.8k
  test_mcs_free(mcs);
1576
17.8k
  return result;
1577
17.8k
}
1578
1579
BOOL freerdp_persist_credentials(rdpContext* context)
1580
0
{
1581
0
  if (!context)
1582
0
    return FALSE;
1583
0
  WINPR_ASSERT(context->rdp);
1584
0
  return utils_persist_credentials(context->rdp->originalSettings, context->rdp->settings);
1585
0
}
1586
1587
const char* freerdp_disconnect_reason_string(int reason)
1588
0
{
1589
0
  switch (reason)
1590
0
  {
1591
0
    case Disconnect_Ultimatum_domain_disconnected:
1592
0
      return "rn-domain-disconnected";
1593
0
    case Disconnect_Ultimatum_provider_initiated:
1594
0
      return "rn-provider-initiated";
1595
0
    case Disconnect_Ultimatum_token_purged:
1596
0
      return "rn-token-purged";
1597
0
    case Disconnect_Ultimatum_user_requested:
1598
0
      return "rn-user-requested";
1599
0
    case Disconnect_Ultimatum_channel_purged:
1600
0
      return "rn-channel-purged";
1601
0
    default:
1602
0
      return "rn-unknown";
1603
0
  }
1604
0
}
1605
1606
BOOL freerdp_set_common_access_token(rdpContext* context,
1607
                                     pGetCommonAccessToken GetCommonAccessToken)
1608
9.62k
{
1609
9.62k
  WINPR_ASSERT(context);
1610
9.62k
  WINPR_ASSERT(context->rdp);
1611
9.62k
  context->rdp->GetCommonAccessToken = GetCommonAccessToken;
1612
9.62k
  return TRUE;
1613
9.62k
}
1614
1615
pGetCommonAccessToken freerdp_get_common_access_token(const rdpContext* context)
1616
0
{
1617
0
  WINPR_ASSERT(context);
1618
0
  WINPR_ASSERT(context->rdp);
1619
0
  return context->rdp->GetCommonAccessToken;
1620
0
}