1 /* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3    Copyright (C) 2014-2015 Red Hat, Inc.
4 
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with this library; if not, see <http://www.gnu.org/licenses/>.
17 
18   Authors:
19     Dmitry Fleytman <dmitry@daynix.com>
20     Kirill Moizik <kirill@daynix.com>
21 */
22 #include <config.h>
23 
24 #include <windows.h>
25 #include <glib-object.h>
26 #include "usbdk_api.h"
27 #include "channel-usbredir-priv.h"
28 
29 #define USB_DK_HIDE_RULE_MATCH_ALL ((ULONG64)(-1))
30 typedef struct tag_USB_DK_HIDE_RULE
31 {
32     ULONG64 Hide;
33     ULONG64 Class;
34     ULONG64 VID;
35     ULONG64 PID;
36     ULONG64 BCD;
37 } USB_DK_HIDE_RULE, *PUSB_DK_HIDE_RULE;
38 
39 typedef HANDLE(__cdecl *USBDK_CREATEHIDERHANDLE)(void);
40 typedef BOOL(__cdecl * USBDK_ADDHIDERULE)(HANDLE hider_handle, PUSB_DK_HIDE_RULE rule);
41 typedef BOOL(__cdecl *USBDK_CLEARHIDERULES)(HANDLE hider_handle);
42 typedef void(__cdecl *USBDK_CLOSEHIDERHANDLE)(HANDLE hider_handle);
43 
44 struct tag_usbdk_api_wrapper
45 {
46     HMODULE                                 module;
47     USBDK_CREATEHIDERHANDLE                 CreateHiderHandle;
48     USBDK_ADDHIDERULE                       AddRule;
49     USBDK_CLEARHIDERULES                    ClearRules;
50     USBDK_CLOSEHIDERHANDLE                  CloseHiderHandle;
51 };
52 
usbdk_is_driver_installed(void)53 BOOL usbdk_is_driver_installed(void)
54 {
55     gboolean usbdk_installed = FALSE;
56     SC_HANDLE managerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
57 
58     if (managerHandle) {
59         SC_HANDLE serviceHandle = OpenService(managerHandle, TEXT("UsbDk"), GENERIC_READ);
60 
61         if (serviceHandle) {
62             SPICE_DEBUG("UsbDk driver is installed.");
63             usbdk_installed = TRUE;
64             CloseServiceHandle(serviceHandle);
65         }
66         CloseServiceHandle(managerHandle);
67     }
68     return usbdk_installed;
69 }
70 
usbdk_api_unload(usbdk_api_wrapper * usbdk_api)71 void usbdk_api_unload(usbdk_api_wrapper *usbdk_api)
72 {
73     if (usbdk_api != NULL) {
74         if (usbdk_api->module != NULL) {
75             SPICE_DEBUG("Unloading UsbDk API DLL");
76             FreeLibrary(usbdk_api->module);
77         }
78         g_free(usbdk_api);
79     }
80 }
81 
usbdk_api_load(void)82 usbdk_api_wrapper *usbdk_api_load(void)
83 {
84     usbdk_api_wrapper *usbdk_api = g_new0(usbdk_api_wrapper, 1);
85 
86     SPICE_DEBUG("Loading UsbDk API DLL");
87     usbdk_api->module = LoadLibraryA("UsbDkHelper");
88     if (usbdk_api->module == NULL) {
89         g_warning("Failed to load UsbDkHelper.dll, error %lu", GetLastError());
90         goto error_unload;
91     }
92 
93     usbdk_api->CreateHiderHandle = (USBDK_CREATEHIDERHANDLE)
94         GetProcAddress(usbdk_api->module, "UsbDk_CreateHiderHandle");
95     if (usbdk_api->CreateHiderHandle == NULL) {
96         g_warning("Failed to find CreateHandle entry point");
97         goto error_unload;
98     }
99 
100     usbdk_api->AddRule = (USBDK_ADDHIDERULE)
101         GetProcAddress(usbdk_api->module, "UsbDk_AddHideRule");
102     if (usbdk_api->AddRule == NULL) {
103         g_warning("Failed to find AddRule entry point");
104         goto error_unload;
105     }
106 
107     usbdk_api->ClearRules = (USBDK_CLEARHIDERULES)
108         GetProcAddress(usbdk_api->module, "UsbDk_ClearHideRules");
109     if (usbdk_api->ClearRules == NULL) {
110         g_warning("Failed to find ClearRules entry point");
111         goto error_unload;
112     }
113 
114     usbdk_api->CloseHiderHandle = (USBDK_CLOSEHIDERHANDLE)
115         GetProcAddress(usbdk_api->module, "UsbDk_CloseHiderHandle");
116     if (usbdk_api->CloseHiderHandle == NULL) {
117         g_warning("Failed to find CloseHiderHandle  entry point");
118         goto error_unload;
119     }
120     return usbdk_api;
121 
122 error_unload:
123     usbdk_api_unload(usbdk_api);
124     return NULL;
125 }
126 
usbdk_usbredir_field_to_usbdk(int value)127 static uint64_t usbdk_usbredir_field_to_usbdk(int value)
128 {
129     if (value >= 0) {
130         return value;
131     }
132 
133     g_warn_if_fail(value == -1);
134 
135     return USB_DK_HIDE_RULE_MATCH_ALL;
136 }
137 
usbdk_add_hide_rule(usbdk_api_wrapper * usbdk_api,HANDLE hider_handle,PUSB_DK_HIDE_RULE rule)138 static BOOL usbdk_add_hide_rule(usbdk_api_wrapper *usbdk_api,
139                                 HANDLE hider_handle,
140                                 PUSB_DK_HIDE_RULE rule)
141 {
142     return usbdk_api->AddRule(hider_handle, rule);
143 }
144 
usbdk_api_set_hide_rules(usbdk_api_wrapper * usbdk_api,HANDLE hider_handle,gchar * redirect_on_connect)145 void usbdk_api_set_hide_rules(usbdk_api_wrapper *usbdk_api, HANDLE hider_handle,
146                               gchar *redirect_on_connect)
147 {
148     struct usbredirfilter_rule *rules;
149     int r, count;
150 
151     r = usbredirfilter_string_to_rules(redirect_on_connect, ",", "|",
152                                        &rules, &count);
153     if (r) {
154         g_warning("auto-connect rules parsing failed with error %d", r);
155         return;
156     }
157 
158     for (int i = 0; i < count; i++) {
159         USB_DK_HIDE_RULE rule;
160         rule.Hide  = usbdk_usbredir_field_to_usbdk(rules[i].allow);
161         rule.Class = usbdk_usbredir_field_to_usbdk(rules[i].device_class);
162         rule.VID   = usbdk_usbredir_field_to_usbdk(rules[i].vendor_id);
163         rule.PID   = usbdk_usbredir_field_to_usbdk(rules[i].product_id);
164         rule.BCD   = usbdk_usbredir_field_to_usbdk(rules[i].device_version_bcd);
165         if (!usbdk_add_hide_rule(usbdk_api, hider_handle, &rule)) {
166             SPICE_DEBUG("UsbDk add hide rule API failed");
167         }
168     }
169 
170     free(rules);
171 }
172 
usbdk_create_hider_handle(usbdk_api_wrapper * usbdk_api)173 HANDLE usbdk_create_hider_handle(usbdk_api_wrapper *usbdk_api)
174 {
175     HANDLE handle = usbdk_api->CreateHiderHandle();
176     return (handle == INVALID_HANDLE_VALUE) ? NULL : handle;
177 }
178 
usbdk_clear_hide_rules(usbdk_api_wrapper * usbdk_api,HANDLE hider_handle)179 BOOL usbdk_clear_hide_rules(usbdk_api_wrapper *usbdk_api, HANDLE hider_handle)
180 {
181     return usbdk_api->ClearRules(hider_handle);
182 }
183 
usbdk_close_hider_handle(usbdk_api_wrapper * usbdk_api,HANDLE hider_handle)184 void usbdk_close_hider_handle(usbdk_api_wrapper *usbdk_api, HANDLE hider_handle)
185 {
186     return usbdk_api->CloseHiderHandle(hider_handle);
187 }
188