1 /* libusb-win32, Generic Windows USB Library
2  * Copyright (c) 2002-2005 Stephan Meyer <ste_meyer@web.de>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  */
18 
19 
20 #include "libusb_driver.h"
21 #include "lusb_defdi_guids.h"
22 
23 /* missing in mingw's ddk headers */
24 #ifndef PLUGPLAY_REGKEY_DEVICE
25 #define PLUGPLAY_REGKEY_DEVICE  1
26 #endif
27 
28 #define LIBUSB_REG_SURPRISE_REMOVAL_OK	L"SurpriseRemovalOK"
29 #define LIBUSB_REG_INITIAL_CONFIG_VALUE	L"InitialConfigValue"
30 #define LIBUSB_REG_DEVICE_INTERFACE_GUIDS L"DeviceInterfaceGUIDs"
31 
32 static bool_t reg_get_property(DEVICE_OBJECT *physical_device_object,
33                                int property, char *data, int size);
34 
reg_get_property(DEVICE_OBJECT * physical_device_object,int property,char * data,int size)35 static bool_t reg_get_property(DEVICE_OBJECT *physical_device_object,
36                                int property, char *data, int size)
37 {
38     WCHAR tmp[512];
39     ULONG ret;
40     ULONG i;
41 
42     if (!physical_device_object || !data || !size)
43     {
44         return FALSE;
45     }
46 
47     memset(data, 0, size);
48     memset(tmp, 0, sizeof(tmp));
49 
50     if (NT_SUCCESS(IoGetDeviceProperty(physical_device_object,
51                                        property,
52                                        sizeof(tmp) - 2,
53                                        tmp,
54                                        &ret)) && ret)
55     {
56         /* convert unicode string to normal character string */
57         for (i = 0; (i < ret/2) && (i < ((ULONG)size - 1)); i++)
58         {
59             data[i] = (char)tmp[i];
60         }
61 
62         _strlwr(data);
63 
64         return TRUE;
65     }
66 
67     return FALSE;
68 }
69 
70 
reg_get_properties(libusb_device_t * dev)71 bool_t reg_get_properties(libusb_device_t *dev)
72 {
73     HANDLE key = NULL;
74 	PVOID keyObject = NULL;
75     NTSTATUS status;
76     UNICODE_STRING surprise_removal_ok_name;
77     UNICODE_STRING initial_config_value_name;
78     UNICODE_STRING device_interface_guids;
79     UNICODE_STRING device_interface_guid_value;
80     KEY_VALUE_FULL_INFORMATION *info;
81     ULONG pool_length;
82     ULONG length;
83 	ULONG val;
84 	LPWSTR valW;
85 
86 	if (!dev->physical_device_object)
87     {
88         return FALSE;
89     }
90 
91     /* default settings */
92     dev->surprise_removal_ok = FALSE;
93     dev->is_filter = TRUE;
94 	dev->initial_config_value = SET_CONFIG_ACTIVE_CONFIG;
95 
96     status = IoOpenDeviceRegistryKey(dev->physical_device_object,
97                                      PLUGPLAY_REGKEY_DEVICE,
98                                      STANDARD_RIGHTS_ALL,
99                                      &key);
100     if (NT_SUCCESS(status))
101     {
102         RtlInitUnicodeString(&surprise_removal_ok_name,
103 			LIBUSB_REG_SURPRISE_REMOVAL_OK);
104 
105         RtlInitUnicodeString(&initial_config_value_name,
106 			LIBUSB_REG_INITIAL_CONFIG_VALUE);
107 
108         RtlInitUnicodeString(&device_interface_guids,
109 			LIBUSB_REG_DEVICE_INTERFACE_GUIDS);
110 
111 		pool_length = sizeof(KEY_VALUE_FULL_INFORMATION) + 512;
112 
113         info = ExAllocatePool(NonPagedPool, pool_length);
114 		if (!info)
115 		{
116 			ZwClose(key);
117 			USBERR("ExAllocatePool failed allocating %d bytes\n", pool_length);
118 			return FALSE;
119 		}
120 
121 
122 		// get surprise_removal_ok
123 		// get is_filter
124 		length = pool_length;
125         memset(info, 0, length);
126 
127         status = ZwQueryValueKey(key, &surprise_removal_ok_name,
128 			KeyValueFullInformation, info, length, &length);
129 
130         if (NT_SUCCESS(status) && (info->Type == REG_DWORD))
131         {
132             val = *((ULONG *)(((char *)info) + info->DataOffset));
133 
134             dev->surprise_removal_ok = val ? TRUE : FALSE;
135             dev->is_filter = FALSE;
136         }
137 
138 		if (!dev->is_filter)
139 		{
140 			// get device interface guid
141 			length = pool_length;
142 			memset(info, 0, length);
143 
144 			status = ZwQueryValueKey(key, &device_interface_guids,
145 				KeyValueFullInformation, info, length, &length);
146 
147 			if (NT_SUCCESS(status) && (info->Type == REG_MULTI_SZ))
148 			{
149 				valW = ((LPWSTR)(((char *)info) + info->DataOffset));
150 				RtlInitUnicodeString(&device_interface_guid_value,valW);
151 				status = RtlGUIDFromString(&device_interface_guid_value, &dev->device_interface_guid);
152 				if (NT_SUCCESS(status))
153 				{
154 					if (IsEqualGUID(&dev->device_interface_guid, &LibusbKDeviceGuid))
155 					{
156 						USBWRN0("libusbK default device DeviceInterfaceGUID found. skippng..\n");
157 						RtlInitUnicodeString(&device_interface_guid_value,Libusb0DeviceGuidW);
158 					}
159 					else if (IsEqualGUID(&dev->device_interface_guid, &Libusb0FilterGuid))
160 					{
161 						USBWRN0("libusb0 filter DeviceInterfaceGUID found. skippng..\n");
162 						RtlInitUnicodeString(&device_interface_guid_value,Libusb0DeviceGuidW);
163 					}
164 					else if (IsEqualGUID(&dev->device_interface_guid, &Libusb0DeviceGuid))
165 					{
166 						USBWRN0("libusb0 device DeviceInterfaceGUID found. skippng..\n");
167 						RtlInitUnicodeString(&device_interface_guid_value,Libusb0DeviceGuidW);
168 					}
169 					else
170 					{
171 						USBMSG0("found user specified device interface guid.\n");
172 						dev->device_interface_in_use = TRUE;
173 					}
174 				}
175 				else
176 				{
177 					USBERR0("invalid user specified device interface guid.");
178 				}
179 			}
180 			if (!dev->device_interface_in_use)
181 			{
182 				RtlInitUnicodeString(&device_interface_guid_value,Libusb0DeviceGuidW);
183 			}
184 		}
185 		else
186 		{
187 			RtlInitUnicodeString(&device_interface_guid_value,Libusb0FilterGuidW);
188 		}
189 
190 		if (!dev->device_interface_in_use)
191 		{
192 			status = RtlGUIDFromString(&device_interface_guid_value, &dev->device_interface_guid);
193 			if (NT_SUCCESS(status))
194 			{
195 				USBMSG0("using default device interface guid.\n");
196 				dev->device_interface_in_use = TRUE;
197 			}
198 			else
199 			{
200 				USBERR0("failed using default device interface guid.\n");
201 			}
202 		}
203 
204 		// get initial_config_value
205 		length = pool_length;
206         memset(info, 0, length);
207 
208         status = ZwQueryValueKey(key, &initial_config_value_name,
209 			KeyValueFullInformation, info, length, &length);
210 
211         if (NT_SUCCESS(status) && (info->Type == REG_DWORD))
212         {
213             val = *((ULONG *)(((char *)info) + info->DataOffset));
214             dev->initial_config_value = (int)val;
215         }
216 
217 		status = ObReferenceObjectByHandle(key, KEY_READ, NULL, KernelMode, &keyObject, NULL);
218 		if (NT_SUCCESS(status))
219 		{
220 			length = pool_length;
221 			memset(info, 0, length);
222 			status = ObQueryNameString(keyObject, (POBJECT_NAME_INFORMATION)info, length, &length);
223 			if (NT_SUCCESS(status))
224 			{
225 				PWSTR nameW =((POBJECT_NAME_INFORMATION)info)->Name.Buffer;
226 				PSTR  nameA = dev->objname_plugplay_registry_key;
227 
228 				val=0;
229 				while (nameW[val] && val < (length/2))
230 				{
231 					*nameA=(char)nameW[val];
232 					nameA++;
233 					val++;
234 				}
235 				*nameA='\0';
236 
237 				USBDBG("reg-key-name=%s\n",dev->objname_plugplay_registry_key);
238 			}
239 			else
240 			{
241 				USBERR("ObQueryNameString failed. status=%Xh\n",status);
242 			}
243 
244 			ObDereferenceObject(keyObject);
245 		}
246 		else
247 		{
248 			USBERR("ObReferenceObjectByHandle failed. status=%Xh\n",status);
249 		}
250 
251         ZwClose(key);
252         ExFreePool(info);
253     }
254 
255     return TRUE;
256 }
257 
reg_get_hardware_id(DEVICE_OBJECT * physical_device_object,char * data,int size)258 bool_t reg_get_hardware_id(DEVICE_OBJECT *physical_device_object,
259                            char *data, int size)
260 {
261     if (!physical_device_object || !data || !size)
262     {
263         return FALSE;
264     }
265 
266     return reg_get_property(physical_device_object, DevicePropertyHardwareID,
267                             data, size);
268 }
269 
reg_get_compatible_id(DEVICE_OBJECT * physical_device_object,char * data,int size)270 bool_t reg_get_compatible_id(DEVICE_OBJECT *physical_device_object,
271                            char *data, int size)
272 {
273     if (!physical_device_object || !data || !size)
274     {
275         return FALSE;
276     }
277 
278     return reg_get_property(physical_device_object, DevicePropertyCompatibleIDs,
279                             data, size);
280 }
281 /*
282 Gets a device property for the device_object.
283 
284 Returns: NTSTATUS code from IoGetDeviceProperty
285          STATUS_INVALID_PARAMETER
286 */
reg_get_device_property(PDEVICE_OBJECT device_object,int property,char * data_buffer,int data_length,int * actual_length)287 NTSTATUS reg_get_device_property(PDEVICE_OBJECT device_object,
288 							   int property,
289 							   char* data_buffer,
290 							   int data_length,
291 							   int* actual_length)
292 {
293 	NTSTATUS status = STATUS_INVALID_PARAMETER;
294 
295     if (!device_object || !data_buffer || !data_length || !actual_length)
296 		return status;
297 
298 	// clear data
299     memset(data_buffer, 0, data_length);
300 	*actual_length=0;
301 
302 	// get device property
303     status = IoGetDeviceProperty(
304 		device_object, property, data_length, data_buffer, (PULONG)actual_length);
305 
306     return status;
307 }
308 
309 /*
310 Gets a property from the device registry key of the device_object.
311 
312 Returns: NTSTATUS from ZwQueryValueKey
313          NTSTATUS from IoOpenDeviceRegistryKey if the device registry
314 		          key could not be opened.
315 */
reg_get_custom_property(PDEVICE_OBJECT device_object,char * data_buffer,unsigned int data_length,unsigned int name_offset,int * actual_length)316 NTSTATUS reg_get_custom_property(PDEVICE_OBJECT device_object,
317 								 char *data_buffer,
318 								 unsigned int data_length,
319 								 unsigned int name_offset,
320 								 int* actual_length)
321 {
322     HANDLE key = NULL;
323     NTSTATUS status;
324     UNICODE_STRING name;
325     KEY_VALUE_FULL_INFORMATION *info;
326     ULONG length;
327 
328     status = IoOpenDeviceRegistryKey(device_object, PLUGPLAY_REGKEY_DEVICE, KEY_READ, &key);
329     if (NT_SUCCESS(status))
330     {
331         RtlInitUnicodeString(&name, (WCHAR*)(&data_buffer[name_offset]));
332         length = sizeof(KEY_VALUE_FULL_INFORMATION) + name.MaximumLength + data_length;
333         info = ExAllocatePool(NonPagedPool, length);
334         if (info)
335         {
336             memset(info, 0, length);
337             status = ZwQueryValueKey(key, &name, KeyValueFullInformation, info, length, &length);
338             if (NT_SUCCESS(status))
339             {
340                 data_length = (info->DataLength > data_length) ? data_length : info->DataLength;
341                 memcpy(data_buffer, (((char *)info) + info->DataOffset),data_length);
342                 *actual_length=data_length;
343             }
344             ExFreePool(info);
345         }
346         ZwClose(key);
347     }
348     return status;
349 }
350 
set_filter_interface_key(libusb_device_t * dev,ULONG id)351 VOID set_filter_interface_key(libusb_device_t *dev, ULONG id)
352 {
353 	if (dev->device_interface_in_use)
354 	{
355 		HANDLE hKey=NULL;
356 		if (NT_SUCCESS(IoOpenDeviceInterfaceRegistryKey(&dev->device_interface_name,KEY_ALL_ACCESS,&hKey)))
357 		{
358 			UNICODE_STRING valueName;
359 			RtlInitUnicodeString(&valueName, L"LUsb0");
360 
361 			if (NT_SUCCESS(ZwSetValueKey(hKey,&valueName, 0, REG_DWORD, &id,sizeof(ULONG))))
362 			{
363 				USBMSG("updated interface registry with LUsb0 direct-access symbolic link. id=%d\n",id);
364 			}
365 			else
366 			{
367 				USBERR0("IoOpenDeviceInterfaceRegistryKey:ZwSetValueKey failed\n");
368 			}
369 			ZwClose(hKey);
370 		}
371 		else
372 		{
373 			USBERR0("IoOpenDeviceInterfaceRegistryKey failed\n");
374 		}
375 	}
376 }