Coverage Report

Created: 2026-02-26 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/FreeRDP/channels/rdpdr/client/devman.c
Line
Count
Source
1
/**
2
 * FreeRDP: A Remote Desktop Protocol Implementation
3
 * Device Redirection Virtual Channel
4
 *
5
 * Copyright 2010-2011 Vic Lee
6
 * Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
7
 * Copyright 2015 Thincast Technologies GmbH
8
 * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
9
 * Copyright 2016 Armin Novak <armin.novak@gmail.com>
10
 *
11
 * Licensed under the Apache License, Version 2.0 (the "License");
12
 * you may not use this file except in compliance with the License.
13
 * You may obtain a copy of the License at
14
 *
15
 *     http://www.apache.org/licenses/LICENSE-2.0
16
 *
17
 * Unless required by applicable law or agreed to in writing, software
18
 * distributed under the License is distributed on an "AS IS" BASIS,
19
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
 * See the License for the specific language governing permissions and
21
 * limitations under the License.
22
 */
23
24
#include <freerdp/config.h>
25
26
#include <stdio.h>
27
#include <stdlib.h>
28
#include <string.h>
29
30
#include <winpr/crt.h>
31
#include <winpr/stream.h>
32
33
#include <freerdp/types.h>
34
#include <freerdp/addin.h>
35
#include <freerdp/client/channels.h>
36
#include <freerdp/channels/log.h>
37
38
#include "rdpdr_main.h"
39
40
#include "devman.h"
41
42
#define TAG CHANNELS_TAG("rdpdr.client")
43
44
static void devman_device_free(void* obj)
45
0
{
46
0
  DEVICE* device = (DEVICE*)obj;
47
48
0
  if (!device)
49
0
    return;
50
51
0
  if (device->Free)
52
0
    device->Free(device);
53
0
}
54
55
DEVMAN* devman_new(rdpdrPlugin* rdpdr)
56
0
{
57
0
  DEVMAN* devman = NULL;
58
59
0
  if (!rdpdr)
60
0
    return NULL;
61
62
0
  devman = (DEVMAN*)calloc(1, sizeof(DEVMAN));
63
64
0
  if (!devman)
65
0
  {
66
0
    WLog_Print(rdpdr->log, WLOG_INFO, "calloc failed!");
67
0
    return NULL;
68
0
  }
69
70
0
  devman->plugin = (void*)rdpdr;
71
0
  devman->id_sequence = 1;
72
0
  devman->devices = ListDictionary_New(TRUE);
73
74
0
  if (!devman->devices)
75
0
  {
76
0
    WLog_Print(rdpdr->log, WLOG_INFO, "ListDictionary_New failed!");
77
0
    free(devman);
78
0
    return NULL;
79
0
  }
80
81
0
  ListDictionary_ValueObject(devman->devices)->fnObjectFree = devman_device_free;
82
0
  return devman;
83
0
}
84
85
void devman_free(DEVMAN* devman)
86
0
{
87
0
  ListDictionary_Free(devman->devices);
88
0
  free(devman);
89
0
}
90
91
void devman_unregister_device(DEVMAN* devman, void* key)
92
0
{
93
0
  DEVICE* device = NULL;
94
95
0
  if (!devman || !key)
96
0
    return;
97
98
0
  device = (DEVICE*)ListDictionary_Take(devman->devices, key);
99
100
0
  if (device)
101
0
    devman_device_free(device);
102
0
}
103
104
/**
105
 * Function description
106
 *
107
 * @return 0 on success, otherwise a Win32 error code
108
 */
109
static UINT devman_register_device(DEVMAN* devman, DEVICE* device)
110
0
{
111
0
  void* key = NULL;
112
113
0
  if (!devman || !device)
114
0
    return ERROR_INVALID_PARAMETER;
115
116
0
  device->id = devman->id_sequence++;
117
0
  key = (void*)(size_t)device->id;
118
119
0
  if (!ListDictionary_Add(devman->devices, key, device))
120
0
  {
121
0
    WLog_INFO(TAG, "ListDictionary_Add failed!");
122
0
    return ERROR_INTERNAL_ERROR;
123
0
  }
124
125
0
  return CHANNEL_RC_OK;
126
0
}
127
128
DEVICE* devman_get_device_by_id(DEVMAN* devman, UINT32 id)
129
0
{
130
0
  DEVICE* device = NULL;
131
0
  void* key = (void*)(size_t)id;
132
133
0
  if (!devman)
134
0
  {
135
0
    WLog_ERR(TAG, "device manager=NULL");
136
0
    return NULL;
137
0
  }
138
139
0
  device = (DEVICE*)ListDictionary_GetItemValue(devman->devices, key);
140
0
  if (!device)
141
0
    WLog_WARN(TAG, "could not find device ID 0x%08" PRIx32, id);
142
0
  return device;
143
0
}
144
145
DEVICE* devman_get_device_by_type(DEVMAN* devman, UINT32 type)
146
0
{
147
0
  DEVICE* device = NULL;
148
0
  ULONG_PTR* keys = NULL;
149
150
0
  if (!devman)
151
0
    return NULL;
152
153
0
  ListDictionary_Lock(devman->devices);
154
0
  const size_t count = ListDictionary_GetKeys(devman->devices, &keys);
155
156
0
  for (size_t x = 0; x < count; x++)
157
0
  {
158
0
    DEVICE* cur = (DEVICE*)ListDictionary_GetItemValue(devman->devices, (void*)keys[x]);
159
160
0
    if (!cur)
161
0
      continue;
162
163
0
    if (cur->type != type)
164
0
      continue;
165
166
0
    device = cur;
167
0
    break;
168
0
  }
169
170
0
  free(keys);
171
0
  ListDictionary_Unlock(devman->devices);
172
0
  return device;
173
0
}
174
175
static const char DRIVE_SERVICE_NAME[] = "drive";
176
static const char PRINTER_SERVICE_NAME[] = "printer";
177
static const char SMARTCARD_SERVICE_NAME[] = "smartcard";
178
static const char SERIAL_SERVICE_NAME[] = "serial";
179
static const char PARALLEL_SERVICE_NAME[] = "parallel";
180
181
/**
182
 * Function description
183
 *
184
 * @return 0 on success, otherwise a Win32 error code
185
 */
186
UINT devman_load_device_service(DEVMAN* devman, RDPDR_DEVICE* device, rdpContext* rdpcontext)
187
0
{
188
0
  const char* ServiceName = NULL;
189
0
  DEVICE_SERVICE_ENTRY_POINTS ep = WINPR_C_ARRAY_INIT;
190
0
  union
191
0
  {
192
0
    const RDPDR_DEVICE* cdp;
193
0
    RDPDR_DEVICE* dp;
194
0
  } devconv;
195
196
0
  devconv.cdp = device;
197
0
  if (!devman || !device || !rdpcontext)
198
0
    return ERROR_INVALID_PARAMETER;
199
200
0
  if (device->Type == RDPDR_DTYP_FILESYSTEM)
201
0
    ServiceName = DRIVE_SERVICE_NAME;
202
0
  else if (device->Type == RDPDR_DTYP_PRINT)
203
0
    ServiceName = PRINTER_SERVICE_NAME;
204
0
  else if (device->Type == RDPDR_DTYP_SMARTCARD)
205
0
    ServiceName = SMARTCARD_SERVICE_NAME;
206
0
  else if (device->Type == RDPDR_DTYP_SERIAL)
207
0
    ServiceName = SERIAL_SERVICE_NAME;
208
0
  else if (device->Type == RDPDR_DTYP_PARALLEL)
209
0
    ServiceName = PARALLEL_SERVICE_NAME;
210
211
0
  if (!ServiceName)
212
0
  {
213
0
    WLog_INFO(TAG, "ServiceName %s did not match!", ServiceName);
214
0
    return ERROR_INVALID_NAME;
215
0
  }
216
217
0
  if (device->Name)
218
0
    WLog_INFO(TAG, "Loading device service %s [%s] (static)", ServiceName, device->Name);
219
0
  else
220
0
    WLog_INFO(TAG, "Loading device service %s (static)", ServiceName);
221
222
0
  PVIRTUALCHANNELENTRY pvce =
223
0
      freerdp_load_channel_addin_entry(ServiceName, NULL, "DeviceServiceEntry", 0);
224
0
  PDEVICE_SERVICE_ENTRY entry = WINPR_FUNC_PTR_CAST(pvce, PDEVICE_SERVICE_ENTRY);
225
226
0
  if (!entry)
227
0
  {
228
0
    WLog_INFO(TAG, "freerdp_load_channel_addin_entry failed!");
229
0
    return ERROR_INTERNAL_ERROR;
230
0
  }
231
232
0
  ep.devman = devman;
233
0
  ep.RegisterDevice = devman_register_device;
234
0
  ep.device = devconv.dp;
235
0
  ep.rdpcontext = rdpcontext;
236
0
  return entry(&ep);
237
0
}