Coverage Report

Created: 2024-05-20 06:11

/src/FreeRDP/channels/client/generic_dynvc.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Dynamic channel
4
 *
5
 * Copyright 2022 David Fort <contact@hardening-consulting.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <freerdp/config.h>
21
#include <freerdp/log.h>
22
#include <freerdp/client/channels.h>
23
24
#define TAG FREERDP_TAG("genericdynvc")
25
26
static UINT generic_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
27
                                              IWTSVirtualChannel* pChannel, BYTE* Data,
28
                                              BOOL* pbAccept,
29
                                              IWTSVirtualChannelCallback** ppCallback)
30
0
{
31
0
  GENERIC_CHANNEL_CALLBACK* callback = NULL;
32
0
  GENERIC_DYNVC_PLUGIN* plugin = NULL;
33
0
  GENERIC_LISTENER_CALLBACK* listener_callback = (GENERIC_LISTENER_CALLBACK*)pListenerCallback;
34
35
0
  if (!listener_callback || !listener_callback->plugin)
36
0
    return ERROR_INTERNAL_ERROR;
37
38
0
  plugin = (GENERIC_DYNVC_PLUGIN*)listener_callback->plugin;
39
0
  WLog_Print(plugin->log, WLOG_TRACE, "...");
40
41
0
  callback = (GENERIC_CHANNEL_CALLBACK*)calloc(1, plugin->channelCallbackSize);
42
0
  if (!callback)
43
0
  {
44
0
    WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
45
0
    return CHANNEL_RC_NO_MEMORY;
46
0
  }
47
48
  /* implant configured channel callbacks */
49
0
  callback->iface = *plugin->channel_callbacks;
50
51
0
  callback->plugin = listener_callback->plugin;
52
0
  callback->channel_mgr = listener_callback->channel_mgr;
53
0
  callback->channel = pChannel;
54
55
0
  listener_callback->channel_callback = callback;
56
0
  listener_callback->channel = pChannel;
57
58
0
  *ppCallback = (IWTSVirtualChannelCallback*)callback;
59
0
  return CHANNEL_RC_OK;
60
0
}
61
62
static UINT generic_dynvc_plugin_initialize(IWTSPlugin* pPlugin,
63
                                            IWTSVirtualChannelManager* pChannelMgr)
64
0
{
65
0
  UINT rc = 0;
66
0
  GENERIC_LISTENER_CALLBACK* listener_callback = NULL;
67
0
  GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
68
69
0
  if (!plugin)
70
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
71
72
0
  if (!pChannelMgr)
73
0
    return ERROR_INVALID_PARAMETER;
74
75
0
  if (plugin->initialized)
76
0
  {
77
0
    WLog_ERR(TAG, "[%s] channel initialized twice, aborting", plugin->dynvc_name);
78
0
    return ERROR_INVALID_DATA;
79
0
  }
80
81
0
  WLog_Print(plugin->log, WLOG_TRACE, "...");
82
0
  listener_callback = (GENERIC_LISTENER_CALLBACK*)calloc(1, sizeof(GENERIC_LISTENER_CALLBACK));
83
0
  if (!listener_callback)
84
0
  {
85
0
    WLog_Print(plugin->log, WLOG_ERROR, "calloc failed!");
86
0
    return CHANNEL_RC_NO_MEMORY;
87
0
  }
88
89
0
  plugin->listener_callback = listener_callback;
90
0
  listener_callback->iface.OnNewChannelConnection = generic_on_new_channel_connection;
91
0
  listener_callback->plugin = pPlugin;
92
0
  listener_callback->channel_mgr = pChannelMgr;
93
0
  rc = pChannelMgr->CreateListener(pChannelMgr, plugin->dynvc_name, 0, &listener_callback->iface,
94
0
                                   &plugin->listener);
95
96
0
  plugin->listener->pInterface = plugin->iface.pInterface;
97
0
  plugin->initialized = (rc == CHANNEL_RC_OK);
98
0
  return rc;
99
0
}
100
101
static UINT generic_plugin_terminated(IWTSPlugin* pPlugin)
102
0
{
103
0
  GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
104
0
  UINT error = CHANNEL_RC_OK;
105
106
0
  if (!plugin)
107
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
108
109
0
  WLog_Print(plugin->log, WLOG_TRACE, "...");
110
111
  /* some channels (namely rdpei), look at initialized to see if they should continue to run */
112
0
  plugin->initialized = FALSE;
113
114
0
  if (plugin->terminatePluginFn)
115
0
    plugin->terminatePluginFn(plugin);
116
117
0
  if (plugin->listener_callback)
118
0
  {
119
0
    IWTSVirtualChannelManager* mgr = plugin->listener_callback->channel_mgr;
120
0
    if (mgr)
121
0
      IFCALL(mgr->DestroyListener, mgr, plugin->listener);
122
0
  }
123
124
0
  free(plugin->listener_callback);
125
0
  free(plugin->dynvc_name);
126
0
  free(plugin);
127
0
  return error;
128
0
}
129
130
static UINT generic_dynvc_plugin_attached(IWTSPlugin* pPlugin)
131
0
{
132
0
  GENERIC_DYNVC_PLUGIN* pluginn = (GENERIC_DYNVC_PLUGIN*)pPlugin;
133
0
  UINT error = CHANNEL_RC_OK;
134
135
0
  if (!pluginn)
136
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
137
138
0
  pluginn->attached = TRUE;
139
0
  return error;
140
0
}
141
142
static UINT generic_dynvc_plugin_detached(IWTSPlugin* pPlugin)
143
0
{
144
0
  GENERIC_DYNVC_PLUGIN* plugin = (GENERIC_DYNVC_PLUGIN*)pPlugin;
145
0
  UINT error = CHANNEL_RC_OK;
146
147
0
  if (!plugin)
148
0
    return CHANNEL_RC_BAD_CHANNEL_HANDLE;
149
150
0
  plugin->attached = FALSE;
151
0
  return error;
152
0
}
153
154
UINT freerdp_generic_DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints, const char* logTag,
155
                                    const char* name, size_t pluginSize, size_t channelCallbackSize,
156
                                    const IWTSVirtualChannelCallback* channel_callbacks,
157
                                    DYNVC_PLUGIN_INIT_FN initPluginFn,
158
                                    DYNVC_PLUGIN_TERMINATE_FN terminatePluginFn)
159
0
{
160
0
  GENERIC_DYNVC_PLUGIN* plugin = NULL;
161
0
  UINT error = CHANNEL_RC_INITIALIZATION_ERROR;
162
163
0
  WINPR_ASSERT(pEntryPoints);
164
0
  WINPR_ASSERT(pEntryPoints->GetPlugin);
165
0
  WINPR_ASSERT(logTag);
166
0
  WINPR_ASSERT(name);
167
0
  WINPR_ASSERT(pluginSize >= sizeof(*plugin));
168
0
  WINPR_ASSERT(channelCallbackSize >= sizeof(GENERIC_CHANNEL_CALLBACK));
169
170
0
  plugin = (GENERIC_DYNVC_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, name);
171
0
  if (plugin != NULL)
172
0
    return CHANNEL_RC_ALREADY_INITIALIZED;
173
174
0
  plugin = (GENERIC_DYNVC_PLUGIN*)calloc(1, pluginSize);
175
0
  if (!plugin)
176
0
  {
177
0
    WLog_ERR(TAG, "calloc failed!");
178
0
    return CHANNEL_RC_NO_MEMORY;
179
0
  }
180
181
0
  plugin->log = WLog_Get(logTag);
182
0
  plugin->attached = TRUE;
183
0
  plugin->channel_callbacks = channel_callbacks;
184
0
  plugin->channelCallbackSize = channelCallbackSize;
185
0
  plugin->iface.Initialize = generic_dynvc_plugin_initialize;
186
0
  plugin->iface.Connected = NULL;
187
0
  plugin->iface.Disconnected = NULL;
188
0
  plugin->iface.Terminated = generic_plugin_terminated;
189
0
  plugin->iface.Attached = generic_dynvc_plugin_attached;
190
0
  plugin->iface.Detached = generic_dynvc_plugin_detached;
191
0
  plugin->terminatePluginFn = terminatePluginFn;
192
193
0
  if (initPluginFn)
194
0
  {
195
0
    rdpSettings* settings = pEntryPoints->GetRdpSettings(pEntryPoints);
196
0
    rdpContext* context = pEntryPoints->GetRdpContext(pEntryPoints);
197
198
0
    error = initPluginFn(plugin, context, settings);
199
0
    if (error != CHANNEL_RC_OK)
200
0
      goto error;
201
0
  }
202
203
0
  plugin->dynvc_name = _strdup(name);
204
0
  if (!plugin->dynvc_name)
205
0
    goto error;
206
207
0
  error = pEntryPoints->RegisterPlugin(pEntryPoints, name, &plugin->iface);
208
0
  if (error == CHANNEL_RC_OK)
209
0
    return error;
210
211
0
error:
212
0
  generic_plugin_terminated(&plugin->iface);
213
0
  return error;
214
0
}