Coverage Report

Created: 2026-01-17 07:16

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