FreeRDP
libfreerdp/core/gateway/rpc.c
1 /*
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * RPC over HTTP
4  *
5  * Copyright 2012 Fujitsu Technology Solutions GmbH
6  * Copyright 2012 Dmitrij Jasnov <dmitrij.jasnov@ts.fujitsu.com>
7  * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.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 <winpr/crt.h>
27 #include <winpr/assert.h>
28 #include <winpr/cast.h>
29 #include <winpr/tchar.h>
30 #include <winpr/synch.h>
31 #include <winpr/dsparse.h>
32 #include <winpr/crypto.h>
33 
34 #include <freerdp/log.h>
35 
36 #ifdef FREERDP_HAVE_VALGRIND_MEMCHECK_H
37 #include <valgrind/memcheck.h>
38 #endif
39 
40 #include "../proxy.h"
41 #include "http.h"
42 #include "../credssp_auth.h"
43 #include "ncacn_http.h"
44 #include "rpc_bind.h"
45 #include "rpc_fault.h"
46 #include "rpc_client.h"
47 
48 #include "rpc.h"
49 #include "rts.h"
50 
51 #define TAG FREERDP_TAG("core.gateway.rpc")
52 
53 static const char* PTYPE_STRINGS[] = { "PTYPE_REQUEST", "PTYPE_PING",
54  "PTYPE_RESPONSE", "PTYPE_FAULT",
55  "PTYPE_WORKING", "PTYPE_NOCALL",
56  "PTYPE_REJECT", "PTYPE_ACK",
57  "PTYPE_CL_CANCEL", "PTYPE_FACK",
58  "PTYPE_CANCEL_ACK", "PTYPE_BIND",
59  "PTYPE_BIND_ACK", "PTYPE_BIND_NAK",
60  "PTYPE_ALTER_CONTEXT", "PTYPE_ALTER_CONTEXT_RESP",
61  "PTYPE_RPC_AUTH_3", "PTYPE_SHUTDOWN",
62  "PTYPE_CO_CANCEL", "PTYPE_ORPHANED",
63  "PTYPE_RTS", "" };
64 
65 static const char* client_in_state_str(CLIENT_IN_CHANNEL_STATE state)
66 {
67  // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
68  const char* str = "CLIENT_IN_CHANNEL_STATE_UNKNOWN";
69 
70  switch (state)
71  {
72  case CLIENT_IN_CHANNEL_STATE_INITIAL:
73  str = "CLIENT_IN_CHANNEL_STATE_INITIAL";
74  break;
75 
76  case CLIENT_IN_CHANNEL_STATE_CONNECTED:
77  str = "CLIENT_IN_CHANNEL_STATE_CONNECTED";
78  break;
79 
80  case CLIENT_IN_CHANNEL_STATE_SECURITY:
81  str = "CLIENT_IN_CHANNEL_STATE_SECURITY";
82  break;
83 
84  case CLIENT_IN_CHANNEL_STATE_NEGOTIATED:
85  str = "CLIENT_IN_CHANNEL_STATE_NEGOTIATED";
86  break;
87 
88  case CLIENT_IN_CHANNEL_STATE_OPENED:
89  str = "CLIENT_IN_CHANNEL_STATE_OPENED";
90  break;
91 
92  case CLIENT_IN_CHANNEL_STATE_OPENED_A4W:
93  str = "CLIENT_IN_CHANNEL_STATE_OPENED_A4W";
94  break;
95 
96  case CLIENT_IN_CHANNEL_STATE_FINAL:
97  str = "CLIENT_IN_CHANNEL_STATE_FINAL";
98  break;
99  default:
100  break;
101  }
102  return str;
103 }
104 
105 static const char* client_out_state_str(CLIENT_OUT_CHANNEL_STATE state)
106 {
107  // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
108  const char* str = "CLIENT_OUT_CHANNEL_STATE_UNKNOWN";
109 
110  switch (state)
111  {
112  case CLIENT_OUT_CHANNEL_STATE_INITIAL:
113  str = "CLIENT_OUT_CHANNEL_STATE_INITIAL";
114  break;
115 
116  case CLIENT_OUT_CHANNEL_STATE_CONNECTED:
117  str = "CLIENT_OUT_CHANNEL_STATE_CONNECTED";
118  break;
119 
120  case CLIENT_OUT_CHANNEL_STATE_SECURITY:
121  str = "CLIENT_OUT_CHANNEL_STATE_SECURITY";
122  break;
123 
124  case CLIENT_OUT_CHANNEL_STATE_NEGOTIATED:
125  str = "CLIENT_OUT_CHANNEL_STATE_NEGOTIATED";
126  break;
127 
128  case CLIENT_OUT_CHANNEL_STATE_OPENED:
129  str = "CLIENT_OUT_CHANNEL_STATE_OPENED";
130  break;
131 
132  case CLIENT_OUT_CHANNEL_STATE_OPENED_A6W:
133  str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A6W";
134  break;
135 
136  case CLIENT_OUT_CHANNEL_STATE_OPENED_A10W:
137  str = "CLIENT_OUT_CHANNEL_STATE_OPENED_A10W";
138  break;
139 
140  case CLIENT_OUT_CHANNEL_STATE_OPENED_B3W:
141  str = "CLIENT_OUT_CHANNEL_STATE_OPENED_B3W";
142  break;
143 
144  case CLIENT_OUT_CHANNEL_STATE_RECYCLED:
145  str = "CLIENT_OUT_CHANNEL_STATE_RECYCLED";
146  break;
147 
148  case CLIENT_OUT_CHANNEL_STATE_FINAL:
149  str = "CLIENT_OUT_CHANNEL_STATE_FINAL";
150  break;
151  default:
152  break;
153  }
154  return str;
155 }
156 
157 const char* rpc_vc_state_str(VIRTUAL_CONNECTION_STATE state)
158 {
159  // NOLINTNEXTLINE(clang-analyzer-deadcode.DeadStores)
160  const char* str = "VIRTUAL_CONNECTION_STATE_UNKNOWN";
161 
162  switch (state)
163  {
164  case VIRTUAL_CONNECTION_STATE_INITIAL:
165  str = "VIRTUAL_CONNECTION_STATE_INITIAL";
166  break;
167 
168  case VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT:
169  str = "VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT";
170  break;
171 
172  case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
173  str = "VIRTUAL_CONNECTION_STATE_WAIT_A3W";
174  break;
175 
176  case VIRTUAL_CONNECTION_STATE_WAIT_C2:
177  str = "VIRTUAL_CONNECTION_STATE_WAIT_C2";
178  break;
179 
180  case VIRTUAL_CONNECTION_STATE_OPENED:
181  str = "VIRTUAL_CONNECTION_STATE_OPENED";
182  break;
183 
184  case VIRTUAL_CONNECTION_STATE_FINAL:
185  str = "VIRTUAL_CONNECTION_STATE_FINAL";
186  break;
187  default:
188  break;
189  }
190  return str;
191 }
192 
193 /*
194  * [MS-RPCH]: Remote Procedure Call over HTTP Protocol Specification:
195  * http://msdn.microsoft.com/en-us/library/cc243950/
196  *
197  *
198  *
199  * Connection Establishment
200  *
201  * Client Outbound Proxy Inbound Proxy Server
202  * | | | |
203  * |-----------------IN Channel Request--------------->| |
204  * |---OUT Channel Request-->| |<-Legacy Server Response-|
205  * | |<--------------Legacy Server Response--------------|
206  * | | | |
207  * |---------CONN_A1-------->| | |
208  * |----------------------CONN_B1--------------------->| |
209  * | |----------------------CONN_A2--------------------->|
210  * | | | |
211  * |<--OUT Channel Response--| |---------CONN_B2-------->|
212  * |<--------CONN_A3---------| | |
213  * | |<---------------------CONN_C1----------------------|
214  * | | |<--------CONN_B3---------|
215  * |<--------CONN_C2---------| | |
216  * | | | |
217  *
218  */
219 
220 void rpc_pdu_header_print(wLog* log, const rpcconn_hdr_t* header)
221 {
222  WINPR_ASSERT(header);
223 
224  WLog_Print(log, WLOG_INFO, "rpc_vers: %" PRIu8 "", header->common.rpc_vers);
225  WLog_Print(log, WLOG_INFO, "rpc_vers_minor: %" PRIu8 "", header->common.rpc_vers_minor);
226 
227  if (header->common.ptype > PTYPE_RTS)
228  WLog_Print(log, WLOG_INFO, "ptype: %s (%" PRIu8 ")", "PTYPE_UNKNOWN", header->common.ptype);
229  else
230  WLog_Print(log, WLOG_INFO, "ptype: %s (%" PRIu8 ")", PTYPE_STRINGS[header->common.ptype],
231  header->common.ptype);
232 
233  WLog_Print(log, WLOG_INFO, "pfc_flags (0x%02" PRIX8 ") = {", header->common.pfc_flags);
234 
235  if (header->common.pfc_flags & PFC_FIRST_FRAG)
236  WLog_Print(log, WLOG_INFO, " PFC_FIRST_FRAG");
237 
238  if (header->common.pfc_flags & PFC_LAST_FRAG)
239  WLog_Print(log, WLOG_INFO, " PFC_LAST_FRAG");
240 
241  if (header->common.pfc_flags & PFC_PENDING_CANCEL)
242  WLog_Print(log, WLOG_INFO, " PFC_PENDING_CANCEL");
243 
244  if (header->common.pfc_flags & PFC_RESERVED_1)
245  WLog_Print(log, WLOG_INFO, " PFC_RESERVED_1");
246 
247  if (header->common.pfc_flags & PFC_CONC_MPX)
248  WLog_Print(log, WLOG_INFO, " PFC_CONC_MPX");
249 
250  if (header->common.pfc_flags & PFC_DID_NOT_EXECUTE)
251  WLog_Print(log, WLOG_INFO, " PFC_DID_NOT_EXECUTE");
252 
253  if (header->common.pfc_flags & PFC_OBJECT_UUID)
254  WLog_Print(log, WLOG_INFO, " PFC_OBJECT_UUID");
255 
256  WLog_Print(log, WLOG_INFO, " }");
257  WLog_Print(log, WLOG_INFO,
258  "packed_drep[4]: %02" PRIX8 " %02" PRIX8 " %02" PRIX8 " %02" PRIX8 "",
259  header->common.packed_drep[0], header->common.packed_drep[1],
260  header->common.packed_drep[2], header->common.packed_drep[3]);
261  WLog_Print(log, WLOG_INFO, "frag_length: %" PRIu16 "", header->common.frag_length);
262  WLog_Print(log, WLOG_INFO, "auth_length: %" PRIu16 "", header->common.auth_length);
263  WLog_Print(log, WLOG_INFO, "call_id: %" PRIu32 "", header->common.call_id);
264 
265  if (header->common.ptype == PTYPE_RESPONSE)
266  {
267  WLog_Print(log, WLOG_INFO, "alloc_hint: %" PRIu32 "", header->response.alloc_hint);
268  WLog_Print(log, WLOG_INFO, "p_cont_id: %" PRIu16 "", header->response.p_cont_id);
269  WLog_Print(log, WLOG_INFO, "cancel_count: %" PRIu8 "", header->response.cancel_count);
270  WLog_Print(log, WLOG_INFO, "reserved: %" PRIu8 "", header->response.reserved);
271  }
272 }
273 
274 rpcconn_common_hdr_t rpc_pdu_header_init(const rdpRpc* rpc)
275 {
276  rpcconn_common_hdr_t header = { 0 };
277  WINPR_ASSERT(rpc);
278 
279  header.rpc_vers = rpc->rpc_vers;
280  header.rpc_vers_minor = rpc->rpc_vers_minor;
281  header.packed_drep[0] = rpc->packed_drep[0];
282  header.packed_drep[1] = rpc->packed_drep[1];
283  header.packed_drep[2] = rpc->packed_drep[2];
284  header.packed_drep[3] = rpc->packed_drep[3];
285  return header;
286 }
287 
288 size_t rpc_offset_align(size_t* offset, size_t alignment)
289 {
290  size_t pad = 0;
291  pad = *offset;
292  *offset = (*offset + alignment - 1) & ~(alignment - 1);
293  pad = *offset - pad;
294  return pad;
295 }
296 
297 size_t rpc_offset_pad(size_t* offset, size_t pad)
298 {
299  *offset += pad;
300  return pad;
301 }
302 
303 /*
304  * PDU Segments:
305  * ________________________________
306  * | |
307  * | PDU Header |
308  * |________________________________|
309  * | |
310  * | |
311  * | PDU Body |
312  * | |
313  * |________________________________|
314  * | |
315  * | Security Trailer |
316  * |________________________________|
317  * | |
318  * | Authentication Token |
319  * |________________________________|
320  */
321 
322 /*
323  * PDU Structure with verification trailer
324  *
325  * MUST only appear in a request PDU!
326  * ________________________________
327  * | |
328  * | PDU Header |
329  * |________________________________| _______
330  * | | /|\
331  * | | |
332  * | Stub Data | |
333  * | | |
334  * |________________________________| |
335  * | | PDU Body
336  * | Stub Pad | |
337  * |________________________________| |
338  * | | |
339  * | Verification Trailer | |
340  * |________________________________| |
341  * | | |
342  * | Authentication Pad | |
343  * |________________________________| __\|/__
344  * | |
345  * | Security Trailer |
346  * |________________________________|
347  * | |
348  * | Authentication Token |
349  * |________________________________|
350  *
351  */
352 
353 /*
354  * Security Trailer:
355  *
356  * The sec_trailer structure MUST be placed at the end of the PDU, including past stub data,
357  * when present. The sec_trailer structure MUST be 4-byte aligned with respect to the beginning
358  * of the PDU. Padding octets MUST be used to align the sec_trailer structure if its natural
359  * beginning is not already 4-byte aligned.
360  *
361  * All PDUs that carry sec_trailer information share certain common fields:
362  * frag_length and auth_length. The beginning of the sec_trailer structure for each PDU MUST be
363  * calculated to start from offset (frag_length – auth_length – 8) from the beginning of the PDU.
364  *
365  * Immediately after the sec_trailer structure, there MUST be a BLOB carrying the authentication
366  * information produced by the security provider. This BLOB is called the authentication token and
367  * MUST be of size auth_length. The size MUST also be equal to the length from the first octet
368  * immediately after the sec_trailer structure all the way to the end of the fragment;
369  * the two values MUST be the same.
370  *
371  * A client or a server that (during composing of a PDU) has allocated more space for the
372  * authentication token than the security provider fills in SHOULD fill in the rest of
373  * the allocated space with zero octets. These zero octets are still considered to belong
374  * to the authentication token part of the PDU.
375  *
376  */
377 
378 BOOL rpc_get_stub_data_info(rdpRpc* rpc, const rpcconn_hdr_t* header, size_t* poffset,
379  size_t* length)
380 {
381  size_t used = 0;
382  size_t offset = 0;
383  BOOL rc = FALSE;
384  UINT32 frag_length = 0;
385  UINT32 auth_length = 0;
386  UINT32 auth_pad_length = 0;
387  UINT32 sec_trailer_offset = 0;
388  const rpc_sec_trailer* sec_trailer = NULL;
389 
390  WINPR_ASSERT(rpc);
391  WINPR_ASSERT(header);
392  WINPR_ASSERT(poffset);
393  WINPR_ASSERT(length);
394 
395  offset = RPC_COMMON_FIELDS_LENGTH;
396 
397  switch (header->common.ptype)
398  {
399  case PTYPE_RESPONSE:
400  offset += 8;
401  rpc_offset_align(&offset, 8);
402  sec_trailer = &header->response.auth_verifier;
403  break;
404 
405  case PTYPE_REQUEST:
406  offset += 4;
407  rpc_offset_align(&offset, 8);
408  sec_trailer = &header->request.auth_verifier;
409  break;
410 
411  case PTYPE_RTS:
412  offset += 4;
413  break;
414 
415  default:
416  WLog_Print(rpc->log, WLOG_ERROR, "Unknown PTYPE: 0x%02" PRIX8 "", header->common.ptype);
417  goto fail;
418  }
419 
420  frag_length = header->common.frag_length;
421  auth_length = header->common.auth_length;
422 
423  if (poffset)
424  *poffset = offset;
425 
426  /* The fragment must be larger than the authentication trailer */
427  used = offset + auth_length + 8ull;
428  if (sec_trailer)
429  {
430  auth_pad_length = sec_trailer->auth_pad_length;
431  used += sec_trailer->auth_pad_length;
432  }
433 
434  if (frag_length < used)
435  goto fail;
436 
437  if (!length)
438  return TRUE;
439 
440  sec_trailer_offset = frag_length - auth_length - 8;
441 
442  /*
443  * According to [MS-RPCE], auth_pad_length is the number of padding
444  * octets used to 4-byte align the security trailer, but in practice
445  * we get values up to 15, which indicates 16-byte alignment.
446  */
447 
448  if ((frag_length - (sec_trailer_offset + 8)) != auth_length)
449  {
450  WLog_Print(rpc->log, WLOG_ERROR,
451  "invalid auth_length: actual: %" PRIu32 ", expected: %" PRIu32 "", auth_length,
452  (frag_length - (sec_trailer_offset + 8)));
453  }
454 
455  *length = sec_trailer_offset - auth_pad_length - offset;
456 
457  rc = TRUE;
458 fail:
459  return rc;
460 }
461 
462 SSIZE_T rpc_channel_read(RpcChannel* channel, wStream* s, size_t length)
463 {
464  int status = 0;
465 
466  if (!channel || (length > INT32_MAX))
467  return -1;
468 
469  ERR_clear_error();
470  status = BIO_read(channel->tls->bio, Stream_Pointer(s), (INT32)length);
471 
472  if (status > 0)
473  {
474  Stream_Seek(s, (size_t)status);
475  return status;
476  }
477 
478  if (BIO_should_retry(channel->tls->bio))
479  return 0;
480 
481  WLog_Print(channel->rpc->log, WLOG_ERROR, "rpc_channel_read: Out of retries");
482  return -1;
483 }
484 
485 SSIZE_T rpc_channel_write(RpcChannel* channel, const BYTE* data, size_t length)
486 {
487  if (!channel)
488  return -1;
489 
490  return freerdp_tls_write_all(channel->tls, data, length);
491 }
492 
493 BOOL rpc_in_channel_transition_to_state(RpcInChannel* inChannel, CLIENT_IN_CHANNEL_STATE state)
494 {
495  if (!inChannel)
496  return FALSE;
497 
498  inChannel->State = state;
499  WLog_Print(inChannel->common.rpc->log, WLOG_DEBUG, "%s", client_in_state_str(state));
500  return TRUE;
501 }
502 
503 static int rpc_channel_rpch_init(RpcClient* client, RpcChannel* channel, const char* inout,
504  const GUID* guid)
505 {
506  HttpContext* http = NULL;
507  rdpSettings* settings = NULL;
508  UINT32 timeout = 0;
509 
510  if (!client || !channel || !inout || !client->context || !client->context->settings)
511  return -1;
512 
513  settings = client->context->settings;
514  channel->auth = credssp_auth_new(client->context);
515  rts_generate_cookie((BYTE*)&channel->Cookie);
516  channel->client = client;
517 
518  if (!channel->auth)
519  return -1;
520 
521  channel->http = http_context_new();
522 
523  if (!channel->http)
524  return -1;
525 
526  http = channel->http;
527 
528  {
529  if (!http_context_set_pragma(http, "ResourceTypeUuid=44e265dd-7daf-42cd-8560-3cdb6e7a2729"))
530  return -1;
531 
532  if (guid)
533  {
534  char* strguid = NULL;
535  RPC_STATUS rpcStatus = UuidToStringA(guid, &strguid);
536 
537  if (rpcStatus != RPC_S_OK)
538  return -1;
539 
540  const BOOL rc = http_context_append_pragma(http, "SessionId=%s", strguid);
541  RpcStringFreeA(&strguid);
542  if (!rc)
543  return -1;
544  }
545  if (timeout)
546  {
547  if (!http_context_append_pragma(http, "MinConnTimeout=%" PRIu32, timeout))
548  return -1;
549  }
550 
551  if (!http_context_set_rdg_correlation_id(http, guid) ||
552  !http_context_set_rdg_connection_id(http, guid))
553  return -1;
554  }
555 
556  /* TODO: "/rpcwithcert/rpcproxy.dll". */
557  if (!http_context_set_method(http, inout) ||
558  !http_context_set_uri(http, "/rpc/rpcproxy.dll?localhost:3388") ||
559  !http_context_set_accept(http, "application/rpc") ||
560  !http_context_set_cache_control(http, "no-cache") ||
561  !http_context_set_connection(http, "Keep-Alive") ||
562  !http_context_set_user_agent(http, "MSRPC") ||
563  !http_context_set_host(http, settings->GatewayHostname))
564  return -1;
565 
566  return 1;
567 }
568 
569 static int rpc_in_channel_init(rdpRpc* rpc, RpcInChannel* inChannel, const GUID* guid)
570 {
571  WINPR_ASSERT(rpc);
572  WINPR_ASSERT(inChannel);
573 
574  inChannel->common.rpc = rpc;
575  inChannel->State = CLIENT_IN_CHANNEL_STATE_INITIAL;
576  inChannel->BytesSent = 0;
577  inChannel->SenderAvailableWindow = rpc->ReceiveWindow;
578  inChannel->PingOriginator.ConnectionTimeout = 30;
579  inChannel->PingOriginator.KeepAliveInterval = 0;
580 
581  if (rpc_channel_rpch_init(rpc->client, &inChannel->common, "RPC_IN_DATA", guid) < 0)
582  return -1;
583 
584  return 1;
585 }
586 
587 static RpcInChannel* rpc_in_channel_new(rdpRpc* rpc, const GUID* guid)
588 {
589  RpcInChannel* inChannel = (RpcInChannel*)calloc(1, sizeof(RpcInChannel));
590 
591  if (inChannel)
592  {
593  rpc_in_channel_init(rpc, inChannel, guid);
594  }
595 
596  return inChannel;
597 }
598 
599 void rpc_channel_free(RpcChannel* channel)
600 {
601  if (!channel)
602  return;
603 
604  credssp_auth_free(channel->auth);
605  http_context_free(channel->http);
606  freerdp_tls_free(channel->tls);
607  free(channel);
608 }
609 
610 BOOL rpc_out_channel_transition_to_state(RpcOutChannel* outChannel, CLIENT_OUT_CHANNEL_STATE state)
611 {
612  if (!outChannel)
613  return FALSE;
614 
615  outChannel->State = state;
616  WLog_Print(outChannel->common.rpc->log, WLOG_DEBUG, "%s", client_out_state_str(state));
617  return TRUE;
618 }
619 
620 static int rpc_out_channel_init(rdpRpc* rpc, RpcOutChannel* outChannel, const GUID* guid)
621 {
622  WINPR_ASSERT(rpc);
623  WINPR_ASSERT(outChannel);
624 
625  outChannel->common.rpc = rpc;
626  outChannel->State = CLIENT_OUT_CHANNEL_STATE_INITIAL;
627  outChannel->BytesReceived = 0;
628  outChannel->ReceiverAvailableWindow = rpc->ReceiveWindow;
629  outChannel->ReceiveWindow = rpc->ReceiveWindow;
630  outChannel->ReceiveWindowSize = rpc->ReceiveWindow;
631  outChannel->AvailableWindowAdvertised = rpc->ReceiveWindow;
632 
633  if (rpc_channel_rpch_init(rpc->client, &outChannel->common, "RPC_OUT_DATA", guid) < 0)
634  return -1;
635 
636  return 1;
637 }
638 
639 RpcOutChannel* rpc_out_channel_new(rdpRpc* rpc, const GUID* guid)
640 {
641  RpcOutChannel* outChannel = (RpcOutChannel*)calloc(1, sizeof(RpcOutChannel));
642 
643  if (outChannel)
644  {
645  rpc_out_channel_init(rpc, outChannel, guid);
646  }
647 
648  return outChannel;
649 }
650 
651 BOOL rpc_virtual_connection_transition_to_state(rdpRpc* rpc, RpcVirtualConnection* connection,
652  VIRTUAL_CONNECTION_STATE state)
653 {
654  if (!connection)
655  return FALSE;
656 
657  WINPR_ASSERT(rpc);
658  connection->State = state;
659  WLog_Print(rpc->log, WLOG_DEBUG, "%s", rpc_vc_state_str(state));
660  return TRUE;
661 }
662 
663 static void rpc_virtual_connection_free(RpcVirtualConnection* connection)
664 {
665  if (!connection)
666  return;
667 
668  if (connection->DefaultInChannel)
669  rpc_channel_free(&connection->DefaultInChannel->common);
670  if (connection->NonDefaultInChannel)
671  rpc_channel_free(&connection->NonDefaultInChannel->common);
672  if (connection->DefaultOutChannel)
673  rpc_channel_free(&connection->DefaultOutChannel->common);
674  if (connection->NonDefaultOutChannel)
675  rpc_channel_free(&connection->NonDefaultOutChannel->common);
676  free(connection);
677 }
678 
679 static RpcVirtualConnection* rpc_virtual_connection_new(rdpRpc* rpc)
680 {
681  WINPR_ASSERT(rpc);
682 
683  RpcVirtualConnection* connection =
684  (RpcVirtualConnection*)calloc(1, sizeof(RpcVirtualConnection));
685 
686  if (!connection)
687  return NULL;
688 
689  rts_generate_cookie((BYTE*)&(connection->Cookie));
690  rts_generate_cookie((BYTE*)&(connection->AssociationGroupId));
691  connection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
692 
693  connection->DefaultInChannel = rpc_in_channel_new(rpc, &connection->Cookie);
694 
695  if (!connection->DefaultInChannel)
696  goto fail;
697 
698  connection->DefaultOutChannel = rpc_out_channel_new(rpc, &connection->Cookie);
699 
700  if (!connection->DefaultOutChannel)
701  goto fail;
702 
703  return connection;
704 fail:
705  rpc_virtual_connection_free(connection);
706  return NULL;
707 }
708 
709 static BOOL rpc_channel_tls_connect(RpcChannel* channel, UINT32 timeout)
710 {
711  if (!channel || !channel->client || !channel->client->context ||
712  !channel->client->context->settings)
713  return FALSE;
714 
715  rdpContext* context = channel->client->context;
716  WINPR_ASSERT(context);
717 
718  rdpSettings* settings = context->settings;
719  WINPR_ASSERT(settings);
720 
721  const char* proxyUsername = freerdp_settings_get_string(settings, FreeRDP_ProxyUsername);
722  const char* proxyPassword = freerdp_settings_get_string(settings, FreeRDP_ProxyPassword);
723 
724  rdpTransport* transport = freerdp_get_transport(context);
725  rdpTransportLayer* layer =
726  transport_connect_layer(transport, channel->client->host, channel->client->port, timeout);
727 
728  if (!layer)
729  return FALSE;
730 
731  BIO* layerBio = BIO_new(BIO_s_transport_layer());
732  if (!layerBio)
733  {
734  transport_layer_free(layer);
735  return FALSE;
736  }
737  BIO_set_data(layerBio, layer);
738 
739  BIO* bufferedBio = BIO_new(BIO_s_buffered_socket());
740  if (!bufferedBio)
741  {
742  BIO_free_all(layerBio);
743  return FALSE;
744  }
745 
746  bufferedBio = BIO_push(bufferedBio, layerBio);
747 
748  if (!BIO_set_nonblock(bufferedBio, TRUE))
749  {
750  BIO_free_all(bufferedBio);
751  return FALSE;
752  }
753 
754  if (channel->client->isProxy)
755  {
756  WINPR_ASSERT(settings->GatewayPort <= UINT16_MAX);
757  if (!proxy_connect(context, bufferedBio, proxyUsername, proxyPassword,
758  settings->GatewayHostname, (UINT16)settings->GatewayPort))
759  {
760  BIO_free_all(bufferedBio);
761  return FALSE;
762  }
763  }
764 
765  channel->bio = bufferedBio;
766  rdpTls* tls = channel->tls = freerdp_tls_new(context);
767 
768  if (!tls)
769  return FALSE;
770 
771  tls->hostname = settings->GatewayHostname;
772  tls->port = WINPR_ASSERTING_INT_CAST(int32_t, MIN(UINT16_MAX, settings->GatewayPort));
773  tls->isGatewayTransport = TRUE;
774  int tlsStatus = freerdp_tls_connect(tls, bufferedBio);
775 
776  if (tlsStatus < 1)
777  {
778  if (tlsStatus < 0)
779  {
780  freerdp_set_last_error_if_not(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
781  }
782  else
783  {
784  freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
785  }
786 
787  return FALSE;
788  }
789 
790  return TRUE;
791 }
792 
793 static int rpc_in_channel_connect(RpcInChannel* inChannel, UINT32 timeout)
794 {
795  rdpContext* context = NULL;
796 
797  if (!inChannel || !inChannel->common.client || !inChannel->common.client->context)
798  return -1;
799 
800  context = inChannel->common.client->context;
801 
802  /* Connect IN Channel */
803 
804  if (!rpc_channel_tls_connect(&inChannel->common, timeout))
805  return -1;
806 
807  rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_CONNECTED);
808 
809  if (!rpc_ncacn_http_auth_init(context, &inChannel->common))
810  return -1;
811 
812  /* Send IN Channel Request */
813 
814  if (!rpc_ncacn_http_send_in_channel_request(&inChannel->common))
815  {
816  WLog_Print(inChannel->common.rpc->log, WLOG_ERROR,
817  "rpc_ncacn_http_send_in_channel_request failure");
818  return -1;
819  }
820 
821  if (!rpc_in_channel_transition_to_state(inChannel, CLIENT_IN_CHANNEL_STATE_SECURITY))
822  return -1;
823 
824  return 1;
825 }
826 
827 static int rpc_out_channel_connect(RpcOutChannel* outChannel, UINT32 timeout)
828 {
829  rdpContext* context = NULL;
830 
831  if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
832  return -1;
833 
834  context = outChannel->common.client->context;
835 
836  /* Connect OUT Channel */
837 
838  if (!rpc_channel_tls_connect(&outChannel->common, timeout))
839  return -1;
840 
841  rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
842 
843  if (!rpc_ncacn_http_auth_init(context, &outChannel->common))
844  return FALSE;
845 
846  /* Send OUT Channel Request */
847 
848  if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, FALSE))
849  {
850  WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
851  "rpc_ncacn_http_send_out_channel_request failure");
852  return FALSE;
853  }
854 
855  rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
856  return 1;
857 }
858 
859 int rpc_out_channel_replacement_connect(RpcOutChannel* outChannel, uint32_t timeout)
860 {
861  rdpContext* context = NULL;
862 
863  if (!outChannel || !outChannel->common.client || !outChannel->common.client->context)
864  return -1;
865 
866  context = outChannel->common.client->context;
867 
868  /* Connect OUT Channel */
869 
870  if (!rpc_channel_tls_connect(&outChannel->common, timeout))
871  return -1;
872 
873  rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_CONNECTED);
874 
875  if (!rpc_ncacn_http_auth_init(context, (RpcChannel*)outChannel))
876  return FALSE;
877 
878  /* Send OUT Channel Request */
879 
880  if (!rpc_ncacn_http_send_out_channel_request(&outChannel->common, TRUE))
881  {
882  WLog_Print(outChannel->common.rpc->log, WLOG_ERROR,
883  "rpc_ncacn_http_send_out_channel_request failure");
884  return FALSE;
885  }
886 
887  rpc_out_channel_transition_to_state(outChannel, CLIENT_OUT_CHANNEL_STATE_SECURITY);
888  return 1;
889 }
890 
891 BOOL rpc_connect(rdpRpc* rpc, UINT32 timeout)
892 {
893  RpcInChannel* inChannel = NULL;
894  RpcOutChannel* outChannel = NULL;
895  RpcVirtualConnection* connection = NULL;
896  rpc->VirtualConnection = rpc_virtual_connection_new(rpc);
897 
898  if (!rpc->VirtualConnection)
899  return FALSE;
900 
901  connection = rpc->VirtualConnection;
902  inChannel = connection->DefaultInChannel;
903  outChannel = connection->DefaultOutChannel;
904  rpc_virtual_connection_transition_to_state(rpc, connection, VIRTUAL_CONNECTION_STATE_INITIAL);
905 
906  if (rpc_in_channel_connect(inChannel, timeout) < 0)
907  return FALSE;
908 
909  if (rpc_out_channel_connect(outChannel, timeout) < 0)
910  return FALSE;
911 
912  return TRUE;
913 }
914 
915 rdpRpc* rpc_new(rdpTransport* transport)
916 {
917  rdpContext* context = transport_get_context(transport);
918  rdpRpc* rpc = NULL;
919 
920  WINPR_ASSERT(context);
921 
922  rpc = (rdpRpc*)calloc(1, sizeof(rdpRpc));
923 
924  if (!rpc)
925  return NULL;
926 
927  rpc->log = WLog_Get(TAG);
928  rpc->State = RPC_CLIENT_STATE_INITIAL;
929  rpc->transport = transport;
930  rpc->SendSeqNum = 0;
931  rpc->auth = credssp_auth_new(context);
932 
933  if (!rpc->auth)
934  goto out_free;
935 
936  rpc->PipeCallId = 0;
937  rpc->StubCallId = 0;
938  rpc->StubFragCount = 0;
939  rpc->rpc_vers = 5;
940  rpc->rpc_vers_minor = 0;
941  /* little-endian data representation */
942  rpc->packed_drep[0] = 0x10;
943  rpc->packed_drep[1] = 0x00;
944  rpc->packed_drep[2] = 0x00;
945  rpc->packed_drep[3] = 0x00;
946  rpc->max_xmit_frag = 0x0FF8;
947  rpc->max_recv_frag = 0x0FF8;
948  rpc->ReceiveWindow = 0x00010000;
949  rpc->ChannelLifetime = 0x40000000;
950  rpc->KeepAliveInterval = 300000;
951  rpc->CurrentKeepAliveInterval = rpc->KeepAliveInterval;
952  rpc->CurrentKeepAliveTime = 0;
953  rpc->CallId = 2;
954  rpc->client = rpc_client_new(context, rpc->max_recv_frag);
955 
956  if (!rpc->client)
957  goto out_free;
958 
959  return rpc;
960 out_free:
961  WINPR_PRAGMA_DIAG_PUSH
962  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
963  rpc_free(rpc);
964  WINPR_PRAGMA_DIAG_POP
965  return NULL;
966 }
967 
968 void rpc_free(rdpRpc* rpc)
969 {
970  if (rpc)
971  {
972  rpc_client_free(rpc->client);
973  credssp_auth_free(rpc->auth);
974  rpc_virtual_connection_free(rpc->VirtualConnection);
975  free(rpc);
976  }
977 }
FREERDP_API const char * freerdp_settings_get_string(const rdpSettings *settings, FreeRDP_Settings_Keys_String id)
Returns a immutable string settings value.